summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitattributes5
-rw-r--r--.github/workflows/ci-deb.yml230
-rw-r--r--.github/workflows/ci-rpm.yml332
-rw-r--r--.github/workflows/ci.yml483
-rw-r--r--.gitignore74
-rw-r--r--.travis.yml95
-rw-r--r--.vscode/c_cpp_properties.json28
-rw-r--r--.vscode/launch.json52
-rw-r--r--CONTRIBUTING109
-rw-r--r--COPYRIGHT95
-rw-r--r--CREDITS2
-rw-r--r--INSTALL.rst169
-rw-r--r--LICENSE340
-rw-r--r--Make.inc.in186
-rw-r--r--Makefile401
-rw-r--r--README.rst179
-rw-r--r--VERSION1
-rw-r--r--config.guess1701
-rw-r--r--config.sub1855
-rwxr-xr-xconfigure16139
-rw-r--r--configure.ac2645
-rw-r--r--doc/.gitignore1
-rw-r--r--doc/ChangeLog189
-rw-r--r--doc/Makefile.sphinx95
-rw-r--r--doc/README181
-rw-r--r--doc/all.mk55
-rw-r--r--doc/antora/antora.yml18
-rw-r--r--doc/antora/modules/ROOT/assets/images/favicon.pngbin0 -> 4105 bytes
-rw-r--r--doc/antora/modules/ROOT/assets/images/favicon.svg104
-rw-r--r--doc/antora/modules/ROOT/assets/images/networkradius.pngbin0 -> 7126 bytes
-rw-r--r--doc/antora/modules/ROOT/nav.adoc1
-rw-r--r--doc/antora/modules/ROOT/pages/directories.adoc69
-rw-r--r--doc/antora/modules/ROOT/pages/index.adoc137
-rw-r--r--doc/antora/modules/howto/nav.adoc19
-rw-r--r--doc/antora/modules/howto/pages/index.adoc17
-rw-r--r--doc/antora/modules/howto/pages/protocols/dhcp/enable.adoc213
-rw-r--r--doc/antora/modules/howto/pages/protocols/dhcp/index.adoc35
-rw-r--r--doc/antora/modules/howto/pages/protocols/dhcp/policy.adoc14
-rw-r--r--doc/antora/modules/howto/pages/protocols/dhcp/policy_common_options.adoc80
-rw-r--r--doc/antora/modules/howto/pages/protocols/dhcp/policy_device_options.adoc310
-rw-r--r--doc/antora/modules/howto/pages/protocols/dhcp/policy_ippool_access.adoc54
-rw-r--r--doc/antora/modules/howto/pages/protocols/dhcp/policy_ippool_creation.adoc112
-rw-r--r--doc/antora/modules/howto/pages/protocols/dhcp/policy_network_options.adoc237
-rw-r--r--doc/antora/modules/howto/pages/protocols/dhcp/policy_subnet_options.adoc184
-rw-r--r--doc/antora/modules/howto/pages/protocols/dhcp/prepare.adoc59
-rw-r--r--doc/antora/modules/howto/pages/protocols/dhcp/test.adoc143
-rw-r--r--doc/antora/modules/howto/pages/protocols/proxy/enable_proxy_protocol.adoc114
-rw-r--r--doc/antora/modules/howto/pages/protocols/proxy/enable_radsec.adoc188
-rw-r--r--doc/antora/modules/howto/pages/protocols/proxy/index.adoc126
-rw-r--r--doc/antora/modules/howto/pages/protocols/proxy/radsec_client.adoc181
-rw-r--r--doc/antora/modules/howto/pages/protocols/proxy/radsec_with_haproxy.adoc134
-rw-r--r--doc/antora/modules/howto/pages/protocols/proxy/radsec_with_traefik.adoc128
-rw-r--r--doc/antora/modules/installation/nav.adoc5
-rw-r--r--doc/antora/modules/installation/pages/dependencies.adoc58
-rw-r--r--doc/antora/modules/installation/pages/index.adoc15
-rw-r--r--doc/antora/modules/installation/pages/packages.adoc22
-rw-r--r--doc/antora/modules/installation/pages/source.adoc199
-rw-r--r--doc/antora/modules/installation/pages/upgrade.adoc737
-rw-r--r--doc/antora/modules/unlang/.gitignore1
-rw-r--r--doc/antora/modules/unlang/nav.adoc51
-rw-r--r--doc/antora/modules/unlang/pages/attr.adoc77
-rw-r--r--doc/antora/modules/unlang/pages/break.adoc28
-rw-r--r--doc/antora/modules/unlang/pages/case.adoc44
-rw-r--r--doc/antora/modules/unlang/pages/condition/and.adoc21
-rw-r--r--doc/antora/modules/unlang/pages/condition/cmp.adoc104
-rw-r--r--doc/antora/modules/unlang/pages/condition/eq.adoc30
-rw-r--r--doc/antora/modules/unlang/pages/condition/index.adoc85
-rw-r--r--doc/antora/modules/unlang/pages/condition/not.adoc19
-rw-r--r--doc/antora/modules/unlang/pages/condition/operands.adoc37
-rw-r--r--doc/antora/modules/unlang/pages/condition/or.adoc21
-rw-r--r--doc/antora/modules/unlang/pages/condition/para.adoc19
-rw-r--r--doc/antora/modules/unlang/pages/condition/regex.adoc180
-rw-r--r--doc/antora/modules/unlang/pages/condition/return_codes.adoc35
-rw-r--r--doc/antora/modules/unlang/pages/default.adoc47
-rw-r--r--doc/antora/modules/unlang/pages/else.adoc30
-rw-r--r--doc/antora/modules/unlang/pages/elsif.adoc43
-rw-r--r--doc/antora/modules/unlang/pages/foreach.adoc40
-rw-r--r--doc/antora/modules/unlang/pages/group.adoc39
-rw-r--r--doc/antora/modules/unlang/pages/if.adoc29
-rw-r--r--doc/antora/modules/unlang/pages/index.adoc162
-rw-r--r--doc/antora/modules/unlang/pages/keywords.adoc78
-rw-r--r--doc/antora/modules/unlang/pages/list.adoc72
-rw-r--r--doc/antora/modules/unlang/pages/load-balance.adoc32
-rw-r--r--doc/antora/modules/unlang/pages/module.adoc86
-rw-r--r--doc/antora/modules/unlang/pages/module_builtin.adoc42
-rw-r--r--doc/antora/modules/unlang/pages/module_method.adoc27
-rw-r--r--doc/antora/modules/unlang/pages/redundant-load-balance.adoc39
-rw-r--r--doc/antora/modules/unlang/pages/redundant.adoc42
-rw-r--r--doc/antora/modules/unlang/pages/return.adoc36
-rw-r--r--doc/antora/modules/unlang/pages/return_codes.adoc17
-rw-r--r--doc/antora/modules/unlang/pages/switch.adoc83
-rw-r--r--doc/antora/modules/unlang/pages/type/all_types.adoc80
-rw-r--r--doc/antora/modules/unlang/pages/type/double.adoc39
-rw-r--r--doc/antora/modules/unlang/pages/type/index.adoc117
-rw-r--r--doc/antora/modules/unlang/pages/type/ip.adoc15
-rw-r--r--doc/antora/modules/unlang/pages/type/numb.adoc11
-rw-r--r--doc/antora/modules/unlang/pages/type/string/backticks.adoc38
-rw-r--r--doc/antora/modules/unlang/pages/type/string/double.adoc68
-rw-r--r--doc/antora/modules/unlang/pages/type/string/escaping.adoc14
-rw-r--r--doc/antora/modules/unlang/pages/type/string/single.adoc19
-rw-r--r--doc/antora/modules/unlang/pages/type/string/unquoted.adoc21
-rw-r--r--doc/antora/modules/unlang/pages/update.adoc160
-rw-r--r--doc/antora/modules/unlang/pages/xlat/alternation.adoc24
-rw-r--r--doc/antora/modules/unlang/pages/xlat/attribute.adoc54
-rw-r--r--doc/antora/modules/unlang/pages/xlat/builtin.adoc891
-rw-r--r--doc/antora/modules/unlang/pages/xlat/character.adoc80
-rw-r--r--doc/antora/modules/unlang/pages/xlat/index.adoc56
-rw-r--r--doc/antora/modules/unlang/pages/xlat/module.adoc18
-rw-r--r--doc/antora/modules/unlang/partials/rcode_table.adoc39
-rw-r--r--doc/bugs175
-rw-r--r--doc/concepts/aaa.rst99
-rw-r--r--doc/concepts/proxy.rst118
-rw-r--r--doc/configuration/acct_type.rst71
-rw-r--r--doc/configuration/autz_type.rst88
-rw-r--r--doc/configuration/configurable_failover.rst476
-rw-r--r--doc/configuration/dynamic_home_servers.md238
-rw-r--r--doc/configuration/load_balance.rst172
-rw-r--r--doc/configuration/post_auth_type44
-rw-r--r--doc/configuration/session_type10
-rw-r--r--doc/configuration/simultaneous_use173
-rw-r--r--doc/configuration/snmp58
-rw-r--r--doc/configuration/variables.rst151
-rw-r--r--doc/deployment/CYGWIN.rst283
-rw-r--r--doc/deployment/MACOSX12
-rw-r--r--doc/deployment/OS222
-rw-r--r--doc/deployment/performance-testing168
-rw-r--r--doc/deployment/supervise-radiusd.rst163
-rw-r--r--doc/deployment/tuning_guide58
-rw-r--r--doc/developer/autotools.md179
-rw-r--r--doc/developer/coding-methods.rst242
-rw-r--r--doc/developer/contributing.rst127
-rw-r--r--doc/developer/module_interface.rst186
-rw-r--r--doc/developer/release-method.rst42
-rw-r--r--doc/index.rst29
-rw-r--r--doc/modules/RADIUS-LDAP-eDirectory18
-rw-r--r--doc/modules/ldap_howto.rst1648
-rw-r--r--doc/modules/mschap.rst196
-rw-r--r--doc/modules/rlm_dbm195
-rw-r--r--doc/modules/rlm_eap395
-rw-r--r--doc/modules/rlm_expiration23
-rw-r--r--doc/modules/rlm_krb547
-rw-r--r--doc/modules/rlm_pam108
-rw-r--r--doc/modules/rlm_passwd50
-rw-r--r--doc/modules/rlm_python76
-rw-r--r--doc/modules/rlm_soh183
-rw-r--r--doc/modules/rlm_sql283
-rw-r--r--doc/modules/rlm_sqlcounter182
-rw-r--r--doc/modules/rlm_sqlippool40
-rw-r--r--doc/schemas/ldap/edir/freeradius-clients.ldif69
-rw-r--r--doc/schemas/ldap/iplanet/freeradius.ldif73
-rw-r--r--doc/schemas/ldap/iplanet/freeradius.schema78
-rw-r--r--doc/schemas/ldap/openldap/freeradius-clients.ldif17
-rw-r--r--doc/schemas/ldap/openldap/freeradius-clients.schema70
-rw-r--r--doc/schemas/ldap/openldap/freeradius.ldif76
-rw-r--r--doc/schemas/ldap/openldap/freeradius.schema477
-rw-r--r--doc/schemas/ldap/samba/README.txt11
-rw-r--r--doc/schemas/ldap/samba/freeradius-attrs.ldif806
-rw-r--r--doc/schemas/ldap/samba/freeradius-classes.ldif91
-rw-r--r--doc/schemas/ldap/samba/freeradius-clients-attrs.ldif91
-rw-r--r--doc/schemas/ldap/samba/freeradius-clients-classes.ldif19
-rw-r--r--doc/schemas/ldap/samba/freeradius-user.ldif10
-rw-r--r--doc/schemas/logstash/README95
-rw-r--r--doc/schemas/logstash/kibana4-dashboard.json123
-rw-r--r--doc/schemas/logstash/log-courier.conf56
-rw-r--r--doc/schemas/logstash/logstash-radius.conf256
-rwxr-xr-xdoc/schemas/logstash/radius-mapping.sh100
-rw-r--r--doc/schemas/sql8
-rw-r--r--doc/source/.gitignore4
-rw-r--r--doc/source/Doxyfile2313
-rw-r--r--doc/source/extra/client.c12
-rw-r--r--doc/source/extra/core.c31
-rw-r--r--doc/source/extra/freeradius.pngbin0 -> 14616 bytes
-rw-r--r--doc/source/extra/module.c17
-rw-r--r--doc/source/extra/toc.c102
-rw-r--r--doc/vendor/ascend57
-rw-r--r--doc/vendor/bay11
-rw-r--r--doc/vendor/cisco.rst168
-rw-r--r--doc/vendor/proxim12
-rwxr-xr-xinstall-sh251
-rw-r--r--m4/ac_prog_cc_sunpro.m417
-rw-r--r--m4/ax_cc.m4493
-rw-r--r--m4/ax_compare_version.m4177
-rw-r--r--m4/ax_prog_perl_modules.m477
-rw-r--r--m4/ax_prog_ruby_version.m466
-rw-r--r--m4/ax_ruby_devel.m4214
-rw-r--r--m4/ax_with_prog.m470
-rw-r--r--m4/fr_check_struct_has_member.m436
-rw-r--r--m4/fr_check_type_include.m421
-rw-r--r--m4/fr_have_bounded_attribute.m426
-rw-r--r--m4/fr_have_builtin_bswap64.m423
-rw-r--r--m4/fr_have_builtin_choose_expr.m424
-rw-r--r--m4/fr_have_builtin_types_compatible_p.m424
-rw-r--r--m4/fr_init_module.m416
-rw-r--r--m4/fr_module_start_tests.m4250
-rw-r--r--m4/fr_smart_check_include.m4133
-rw-r--r--m4/fr_smart_check_lib.m497
-rw-r--r--m4/fr_tls.m467
-rw-r--r--m4/libcurl_check_config.m4251
-rw-r--r--m4/python.m4363
-rw-r--r--m4/vl_lib_readline.m445
-rw-r--r--main.mk1
-rw-r--r--man/man1/dhcpclient.171
-rw-r--r--man/man1/rad_counter.142
-rw-r--r--man/man1/radclient.1195
-rw-r--r--man/man1/radeapclient.1100
-rw-r--r--man/man1/radlast.121
-rw-r--r--man/man1/radtest.181
-rw-r--r--man/man1/radwho.199
-rw-r--r--man/man1/radzap.168
-rw-r--r--man/man1/smbencrypt.122
-rw-r--r--man/man5/checkrad.595
-rw-r--r--man/man5/clients.conf.546
-rw-r--r--man/man5/dictionary.5185
-rw-r--r--man/man5/radiusd.conf.5202
-rw-r--r--man/man5/radrelay.conf.5146
-rw-r--r--man/man5/rlm_always.5119
-rw-r--r--man/man5/rlm_attr_filter.5145
-rw-r--r--man/man5/rlm_chap.530
-rw-r--r--man/man5/rlm_counter.589
-rw-r--r--man/man5/rlm_detail.589
-rw-r--r--man/man5/rlm_digest.579
-rw-r--r--man/man5/rlm_expr.5113
-rw-r--r--man/man5/rlm_files.595
-rw-r--r--man/man5/rlm_idn.545
-rw-r--r--man/man5/rlm_mschap.5110
-rw-r--r--man/man5/rlm_pap.5137
-rw-r--r--man/man5/rlm_passwd.5136
-rw-r--r--man/man5/rlm_realm.594
-rw-r--r--man/man5/rlm_sql.5152
-rw-r--r--man/man5/rlm_unbound.582
-rw-r--r--man/man5/rlm_unix.566
-rw-r--r--man/man5/unlang.5900
-rw-r--r--man/man5/users.5228
-rw-r--r--man/man8/radcrypt.845
-rw-r--r--man/man8/raddebug.8104
-rw-r--r--man/man8/radiusd.8235
-rw-r--r--man/man8/radmin.8188
-rw-r--r--man/man8/radrelay.849
-rw-r--r--man/man8/radsniff.875
-rw-r--r--man/man8/radsqlrelay.890
-rw-r--r--man/man8/rlm_sqlippool_tool.8157
-rw-r--r--mibs/FREERADIUS-MGMT-MIB.mib38
-rw-r--r--mibs/FREERADIUS-NOTIFICATION-MIB.mib180
-rw-r--r--mibs/FREERADIUS-PRODUCT-RADIUSD-MIB.mib75
-rw-r--r--mibs/FREERADIUS-SMI.mib52
-rw-r--r--mibs/RADIUS-ACC-CLIENT-MIB.mib647
-rw-r--r--mibs/RADIUS-ACC-SERVER-MIB.mib732
-rw-r--r--mibs/RADIUS-AUTH-CLIENT-MIB.mib708
-rw-r--r--mibs/RADIUS-AUTH-SERVER-MIB.mib775
-rw-r--r--mibs/RADIUS-STAT-MIB.mib349
-rw-r--r--mibs/README7
-rwxr-xr-xmissing215
-rw-r--r--raddb/.gitignore6
-rw-r--r--raddb/README.rst665
-rw-r--r--raddb/all.mk152
-rw-r--r--raddb/certs/.gitignore13
-rw-r--r--raddb/certs/Makefile186
-rw-r--r--raddb/certs/README.md248
-rwxr-xr-xraddb/certs/bootstrap86
-rw-r--r--raddb/certs/ca.cnf62
-rw-r--r--raddb/certs/client.cnf53
-rw-r--r--raddb/certs/demoCA/cacert.pem22
-rw-r--r--raddb/certs/inner-server.cnf55
-rw-r--r--raddb/certs/ocsp.cnf61
-rw-r--r--raddb/certs/realms/README.md235
-rw-r--r--raddb/certs/server.cnf72
-rw-r--r--raddb/certs/xpextensions75
-rw-r--r--raddb/clients.conf288
-rw-r--r--raddb/debug.conf9
-rw-r--r--raddb/dictionary49
-rw-r--r--raddb/experimental.conf116
-rw-r--r--raddb/home_servers/README.md21
-rw-r--r--raddb/home_servers/tls.conf58
-rw-r--r--raddb/mods-available/README.rst116
-rw-r--r--raddb/mods-available/abfab_psk_sql15
-rw-r--r--raddb/mods-available/always81
-rw-r--r--raddb/mods-available/attr_filter61
-rw-r--r--raddb/mods-available/cache150
-rw-r--r--raddb/mods-available/cache_auth116
-rw-r--r--raddb/mods-available/chap11
-rw-r--r--raddb/mods-available/couchbase204
-rw-r--r--raddb/mods-available/counter82
-rw-r--r--raddb/mods-available/cui53
-rw-r--r--raddb/mods-available/date35
-rw-r--r--raddb/mods-available/detail109
-rw-r--r--raddb/mods-available/detail.example.com27
-rw-r--r--raddb/mods-available/detail.log75
-rw-r--r--raddb/mods-available/dhcp19
-rw-r--r--raddb/mods-available/dhcp_files56
-rw-r--r--raddb/mods-available/dhcp_passwd20
-rw-r--r--raddb/mods-available/dhcp_sql92
-rw-r--r--raddb/mods-available/dhcp_sqlippool101
-rw-r--r--raddb/mods-available/digest13
-rw-r--r--raddb/mods-available/dynamic_clients32
-rw-r--r--raddb/mods-available/eap1115
-rw-r--r--raddb/mods-available/echo123
-rw-r--r--raddb/mods-available/etc_group32
-rw-r--r--raddb/mods-available/exec29
-rw-r--r--raddb/mods-available/expiration13
-rw-r--r--raddb/mods-available/expr148
-rw-r--r--raddb/mods-available/files30
-rw-r--r--raddb/mods-available/idn28
-rw-r--r--raddb/mods-available/inner-eap107
-rw-r--r--raddb/mods-available/ippool66
-rw-r--r--raddb/mods-available/json271
-rw-r--r--raddb/mods-available/krb582
-rw-r--r--raddb/mods-available/ldap712
-rw-r--r--raddb/mods-available/ldap_google262
-rw-r--r--raddb/mods-available/linelog170
-rw-r--r--raddb/mods-available/logintime23
-rw-r--r--raddb/mods-available/mac2ip25
-rw-r--r--raddb/mods-available/mac2vlan18
-rw-r--r--raddb/mods-available/moonshot-targeted-ids57
-rw-r--r--raddb/mods-available/mschap253
-rw-r--r--raddb/mods-available/ntlm_auth18
-rw-r--r--raddb/mods-available/opendirectory26
-rw-r--r--raddb/mods-available/pam26
-rw-r--r--raddb/mods-available/pap18
-rw-r--r--raddb/mods-available/passwd55
-rw-r--r--raddb/mods-available/perl94
-rw-r--r--raddb/mods-available/preprocess62
-rw-r--r--raddb/mods-available/python65
-rw-r--r--raddb/mods-available/python365
-rw-r--r--raddb/mods-available/radutmp53
-rw-r--r--raddb/mods-available/realm80
-rw-r--r--raddb/mods-available/redis99
-rw-r--r--raddb/mods-available/rediswho52
-rw-r--r--raddb/mods-available/replicate42
-rw-r--r--raddb/mods-available/rest301
-rw-r--r--raddb/mods-available/smbpasswd16
-rw-r--r--raddb/mods-available/smsotp94
-rw-r--r--raddb/mods-available/soh4
-rw-r--r--raddb/mods-available/sometimes12
-rw-r--r--raddb/mods-available/sql376
-rw-r--r--raddb/mods-available/sql_map49
-rw-r--r--raddb/mods-available/sqlcounter122
-rw-r--r--raddb/mods-available/sqlippool109
-rw-r--r--raddb/mods-available/sradutmp16
-rw-r--r--raddb/mods-available/totp40
-rw-r--r--raddb/mods-available/unbound13
-rw-r--r--raddb/mods-available/unix25
-rw-r--r--raddb/mods-available/unpack105
-rw-r--r--raddb/mods-available/utf814
-rw-r--r--raddb/mods-available/wimax165
-rw-r--r--raddb/mods-available/yubikey158
-rw-r--r--raddb/mods-config/README.rst22
-rw-r--r--raddb/mods-config/attr_filter/access_challenge19
-rw-r--r--raddb/mods-config/attr_filter/access_reject18
-rw-r--r--raddb/mods-config/attr_filter/accounting_response16
-rw-r--r--raddb/mods-config/attr_filter/coa22
-rw-r--r--raddb/mods-config/attr_filter/post-proxy121
-rw-r--r--raddb/mods-config/attr_filter/pre-proxy67
-rw-r--r--raddb/mods-config/files/accounting27
-rw-r--r--raddb/mods-config/files/authorize206
-rw-r--r--raddb/mods-config/files/dhcp153
-rw-r--r--raddb/mods-config/files/pre-proxy31
-rw-r--r--raddb/mods-config/perl/example.pl230
-rw-r--r--raddb/mods-config/preprocess/hints86
-rw-r--r--raddb/mods-config/preprocess/huntgroups43
-rwxr-xr-xraddb/mods-config/realm/freeradius-naptr-to-home-server.sh161
-rw-r--r--raddb/mods-config/sql/counter/mysql/dailycounter.conf46
-rw-r--r--raddb/mods-config/sql/counter/mysql/expire_on_login.conf6
-rw-r--r--raddb/mods-config/sql/counter/mysql/monthlycounter.conf34
-rw-r--r--raddb/mods-config/sql/counter/mysql/noresetcounter.conf4
-rw-r--r--raddb/mods-config/sql/counter/mysql/weeklycounter.conf11
-rw-r--r--raddb/mods-config/sql/counter/postgresql/dailycounter.conf34
-rw-r--r--raddb/mods-config/sql/counter/postgresql/expire_on_login.conf6
-rw-r--r--raddb/mods-config/sql/counter/postgresql/monthlycounter.conf31
-rw-r--r--raddb/mods-config/sql/counter/postgresql/noresetcounter.conf4
-rw-r--r--raddb/mods-config/sql/counter/postgresql/weeklycounter.conf12
-rw-r--r--raddb/mods-config/sql/counter/sqlite/dailycounter.conf33
-rw-r--r--raddb/mods-config/sql/counter/sqlite/expire_on_login.conf6
-rw-r--r--raddb/mods-config/sql/counter/sqlite/monthlycounter.conf34
-rw-r--r--raddb/mods-config/sql/counter/sqlite/noresetcounter.conf4
-rw-r--r--raddb/mods-config/sql/counter/sqlite/weeklycounter.conf12
-rw-r--r--raddb/mods-config/sql/cui/mysql/queries.conf50
-rw-r--r--raddb/mods-config/sql/cui/mysql/schema.sql9
-rw-r--r--raddb/mods-config/sql/cui/postgresql/queries.conf47
-rw-r--r--raddb/mods-config/sql/cui/postgresql/schema.sql14
-rw-r--r--raddb/mods-config/sql/cui/sqlite/queries.conf47
-rw-r--r--raddb/mods-config/sql/cui/sqlite/schema.sql9
-rw-r--r--raddb/mods-config/sql/dhcp/mssql/queries.conf52
-rw-r--r--raddb/mods-config/sql/dhcp/mssql/schema.sql91
-rw-r--r--raddb/mods-config/sql/dhcp/mysql/queries.conf75
-rw-r--r--raddb/mods-config/sql/dhcp/mysql/schema.sql47
-rw-r--r--raddb/mods-config/sql/dhcp/mysql/setup.sql21
-rw-r--r--raddb/mods-config/sql/dhcp/oracle/queries.conf47
-rw-r--r--raddb/mods-config/sql/dhcp/oracle/schema.sql81
-rw-r--r--raddb/mods-config/sql/dhcp/postgresql/queries.conf76
-rw-r--r--raddb/mods-config/sql/dhcp/postgresql/schema.sql44
-rw-r--r--raddb/mods-config/sql/dhcp/postgresql/setup.sql28
-rw-r--r--raddb/mods-config/sql/dhcp/sqlite/queries.conf52
-rw-r--r--raddb/mods-config/sql/dhcp/sqlite/schema.sql46
-rw-r--r--raddb/mods-config/sql/ippool-dhcp/mssql/procedure.sql159
-rw-r--r--raddb/mods-config/sql/ippool-dhcp/mssql/queries.conf257
-rw-r--r--raddb/mods-config/sql/ippool-dhcp/mssql/schema.sql40
-rw-r--r--raddb/mods-config/sql/ippool-dhcp/mysql/procedure-no-skip-locked.sql160
-rw-r--r--raddb/mods-config/sql/ippool-dhcp/mysql/procedure.sql144
-rw-r--r--raddb/mods-config/sql/ippool-dhcp/mysql/queries.conf221
-rw-r--r--raddb/mods-config/sql/ippool-dhcp/mysql/schema.sql21
-rw-r--r--raddb/mods-config/sql/ippool-dhcp/oracle/procedure.sql217
-rw-r--r--raddb/mods-config/sql/ippool-dhcp/oracle/queries.conf200
-rw-r--r--raddb/mods-config/sql/ippool-dhcp/oracle/schema.sql28
-rw-r--r--raddb/mods-config/sql/ippool-dhcp/postgresql/procedure.sql119
-rw-r--r--raddb/mods-config/sql/ippool-dhcp/postgresql/queries.conf291
-rw-r--r--raddb/mods-config/sql/ippool-dhcp/postgresql/schema.sql23
-rw-r--r--raddb/mods-config/sql/ippool-dhcp/sqlite/queries.conf236
-rw-r--r--raddb/mods-config/sql/ippool-dhcp/sqlite/schema.sql25
-rw-r--r--raddb/mods-config/sql/ippool/mongo/queries.conf109
-rw-r--r--raddb/mods-config/sql/ippool/mssql/procedure.sql137
-rw-r--r--raddb/mods-config/sql/ippool/mssql/queries.conf175
-rw-r--r--raddb/mods-config/sql/ippool/mssql/schema.sql25
-rw-r--r--raddb/mods-config/sql/ippool/mysql/procedure-no-skip-locked.sql149
-rw-r--r--raddb/mods-config/sql/ippool/mysql/procedure.sql139
-rw-r--r--raddb/mods-config/sql/ippool/mysql/queries.conf156
-rw-r--r--raddb/mods-config/sql/ippool/mysql/schema.sql18
-rw-r--r--raddb/mods-config/sql/ippool/oracle/procedure.sql129
-rw-r--r--raddb/mods-config/sql/ippool/oracle/queries.conf172
-rw-r--r--raddb/mods-config/sql/ippool/oracle/schema.sql27
-rw-r--r--raddb/mods-config/sql/ippool/postgresql/procedure.sql111
-rw-r--r--raddb/mods-config/sql/ippool/postgresql/queries.conf207
-rw-r--r--raddb/mods-config/sql/ippool/postgresql/schema.sql22
-rw-r--r--raddb/mods-config/sql/ippool/sqlite/queries.conf148
-rw-r--r--raddb/mods-config/sql/ippool/sqlite/schema.sql18
-rw-r--r--raddb/mods-config/sql/main/mongo/queries.conf289
-rw-r--r--raddb/mods-config/sql/main/mssql/process-radacct.sql161
-rw-r--r--raddb/mods-config/sql/main/mssql/queries.conf617
-rw-r--r--raddb/mods-config/sql/main/mssql/schema.sql302
-rw-r--r--raddb/mods-config/sql/main/mysql/extras/wimax/queries.conf40
-rw-r--r--raddb/mods-config/sql/main/mysql/extras/wimax/schema.sql16
-rw-r--r--raddb/mods-config/sql/main/mysql/process-radacct.sql289
-rw-r--r--raddb/mods-config/sql/main/mysql/queries.conf694
-rw-r--r--raddb/mods-config/sql/main/mysql/schema.sql179
-rwxr-xr-xraddb/mods-config/sql/main/mysql/setup.sql40
-rw-r--r--raddb/mods-config/sql/main/ndb/README5
-rw-r--r--raddb/mods-config/sql/main/ndb/schema.sql144
-rw-r--r--raddb/mods-config/sql/main/ndb/setup.sql25
-rw-r--r--raddb/mods-config/sql/main/oracle/process-radacct.sql147
-rw-r--r--raddb/mods-config/sql/main/oracle/queries.conf694
-rw-r--r--raddb/mods-config/sql/main/oracle/schema.sql205
-rw-r--r--raddb/mods-config/sql/main/postgresql/extras/cisco_h323_db_schema.sql295
-rw-r--r--raddb/mods-config/sql/main/postgresql/extras/voip-postpaid.conf70
-rw-r--r--raddb/mods-config/sql/main/postgresql/process-radacct.sql288
-rw-r--r--raddb/mods-config/sql/main/postgresql/queries.conf742
-rw-r--r--raddb/mods-config/sql/main/postgresql/schema.sql178
-rw-r--r--raddb/mods-config/sql/main/postgresql/setup.sql58
-rwxr-xr-xraddb/mods-config/sql/main/sqlite/process-radacct-close-after-reload.pl119
-rwxr-xr-xraddb/mods-config/sql/main/sqlite/process-radacct-new-data-usage-period.sh124
-rw-r--r--raddb/mods-config/sql/main/sqlite/process-radacct-schema.sql95
-rw-r--r--raddb/mods-config/sql/main/sqlite/queries.conf635
-rw-r--r--raddb/mods-config/sql/main/sqlite/schema.sql164
-rw-r--r--raddb/mods-config/sql/moonshot-targeted-ids/mysql/queries.conf15
-rw-r--r--raddb/mods-config/sql/moonshot-targeted-ids/mysql/schema.sql8
-rw-r--r--raddb/mods-config/sql/moonshot-targeted-ids/postgresql/queries.conf15
-rw-r--r--raddb/mods-config/sql/moonshot-targeted-ids/postgresql/schema.sql8
-rw-r--r--raddb/mods-config/sql/moonshot-targeted-ids/sqlite/queries.conf15
-rw-r--r--raddb/mods-config/sql/moonshot-targeted-ids/sqlite/schema.sql8
-rw-r--r--raddb/mods-config/unbound/default.conf2
-rw-r--r--raddb/panic.gdb4
-rw-r--r--raddb/policy.d/abfab-tr106
-rw-r--r--raddb/policy.d/accounting127
-rw-r--r--raddb/policy.d/canonicalization113
-rw-r--r--raddb/policy.d/control40
-rw-r--r--raddb/policy.d/cui131
-rw-r--r--raddb/policy.d/debug64
-rw-r--r--raddb/policy.d/dhcp327
-rw-r--r--raddb/policy.d/eap54
-rw-r--r--raddb/policy.d/filter211
-rw-r--r--raddb/policy.d/moonshot-targeted-ids249
-rw-r--r--raddb/policy.d/operator-name46
-rw-r--r--raddb/policy.d/rfc754246
-rw-r--r--raddb/proxy.conf872
-rw-r--r--raddb/radiusd.conf.in902
-rw-r--r--raddb/radrelay.conf.in170
-rw-r--r--raddb/sites-available/README333
-rw-r--r--raddb/sites-available/abfab-tls118
-rw-r--r--raddb/sites-available/abfab-tr-idp198
-rw-r--r--raddb/sites-available/aws-nlb46
-rw-r--r--raddb/sites-available/buffered-sql161
-rw-r--r--raddb/sites-available/challenge123
-rw-r--r--raddb/sites-available/channel_bindings17
-rw-r--r--raddb/sites-available/check-eap-tls135
-rw-r--r--raddb/sites-available/coa49
-rw-r--r--raddb/sites-available/coa-relay366
-rw-r--r--raddb/sites-available/control-socket92
-rw-r--r--raddb/sites-available/copy-acct-to-home-server202
-rw-r--r--raddb/sites-available/decoupled-accounting139
-rw-r--r--raddb/sites-available/default1159
-rw-r--r--raddb/sites-available/dhcp595
-rw-r--r--raddb/sites-available/dhcp.relay44
-rw-r--r--raddb/sites-available/dynamic-clients222
-rw-r--r--raddb/sites-available/example122
-rw-r--r--raddb/sites-available/google-ldap-auth225
-rw-r--r--raddb/sites-available/inner-tunnel468
-rw-r--r--raddb/sites-available/originate-coa185
-rw-r--r--raddb/sites-available/proxy-inner-tunnel47
-rw-r--r--raddb/sites-available/resource-check140
-rw-r--r--raddb/sites-available/robust-proxy-accounting177
-rw-r--r--raddb/sites-available/soh34
-rw-r--r--raddb/sites-available/status127
-rw-r--r--raddb/sites-available/tls696
-rw-r--r--raddb/sites-available/tls-cache144
-rw-r--r--raddb/sites-available/totp85
-rw-r--r--raddb/sites-available/virtual.example.com32
-rw-r--r--raddb/sites-available/vmps98
-rw-r--r--raddb/templates.conf108
-rw-r--r--raddb/trigger.conf281
-rw-r--r--raddb/vmpsd.conf.in405
-rw-r--r--redhat/.gitignore1
-rw-r--r--redhat/README10
-rw-r--r--redhat/freeradius-logrotate61
-rw-r--r--redhat/freeradius-pam-conf6
-rwxr-xr-xredhat/freeradius-radiusd-init191
-rw-r--r--redhat/freeradius-tmpfiles-conf1
-rw-r--r--redhat/freeradius.spec956
-rw-r--r--redhat/radiusd-pam7
-rw-r--r--redhat/radiusd.service67
-rw-r--r--scripts/.gitignore8
-rwxr-xr-xscripts/Ssha2Passwd144
-rw-r--r--scripts/all.mk22
-rw-r--r--scripts/bbedit/unlanglaguage.plist116
-rw-r--r--scripts/bin/README.md9
-rwxr-xr-xscripts/bin/gdb5
-rwxr-xr-xscripts/bin/lldb5
l---------scripts/bin/radclient1
-rwxr-xr-xscripts/bin/radict5
-rwxr-xr-xscripts/bin/radiusd5
l---------scripts/bin/radmin1
l---------scripts/bin/radsniff1
l---------scripts/bin/unit_test_module1
-rw-r--r--scripts/boiler.mk674
-rw-r--r--scripts/ci/Dockerfile10
-rw-r--r--scripts/ci/Jenkinsfile66
-rwxr-xr-xscripts/ci/eapol_test-build.sh121
-rw-r--r--scripts/ci/eapol_test/.gitignore1
-rw-r--r--scripts/ci/eapol_test/config_freebsd520
-rw-r--r--scripts/ci/eapol_test/config_linux520
-rw-r--r--scripts/ci/eapol_test/config_osx515
-rw-r--r--scripts/ci/haproxy.conf16
-rwxr-xr-xscripts/ci/ldap-setup.sh51
-rw-r--r--scripts/ci/ldap/slapd.conf51
-rw-r--r--scripts/ci/ldap/slapd2.conf61
-rwxr-xr-xscripts/ci/ldap2-setup.sh63
-rwxr-xr-xscripts/ci/mysql-setup.sh19
-rwxr-xr-xscripts/ci/openresty-setup.sh144
-rw-r--r--scripts/ci/openresty/.htpasswd1
-rw-r--r--scripts/ci/openresty/auth-api.lua19
-rw-r--r--scripts/ci/openresty/delay-api.lua6
-rw-r--r--scripts/ci/openresty/json-api.lua145
-rw-r--r--scripts/ci/openresty/post-api.lua19
-rw-r--r--scripts/ci/openresty/test.txt1
-rw-r--r--scripts/ci/package-test.mk41
-rwxr-xr-xscripts/ci/postgresql-setup.sh26
-rw-r--r--scripts/ci/radsecproxy.conf33
-rw-r--r--scripts/ci/start.sh37
-rw-r--r--scripts/ci/stunnel.conf16
-rwxr-xr-xscripts/clients.pl68
-rw-r--r--scripts/collectd/radsniff_types.db10
-rwxr-xr-xscripts/create-users.pl64
-rw-r--r--scripts/cron/radiusd.cron.daily.in34
-rw-r--r--scripts/cron/radiusd.cron.monthly.in19
-rw-r--r--scripts/crossbuild/README.md122
-rw-r--r--scripts/crossbuild/build/.gitignore4
-rw-r--r--scripts/crossbuild/crossbuild.mk236
-rw-r--r--scripts/crossbuild/docker/centos7/Dockerfile92
-rw-r--r--scripts/crossbuild/docker/centos8/Dockerfile81
-rw-r--r--scripts/crossbuild/docker/debian10/Dockerfile89
-rw-r--r--scripts/crossbuild/docker/debian8/Dockerfile84
-rw-r--r--scripts/crossbuild/docker/debian9/Dockerfile84
-rw-r--r--scripts/crossbuild/docker/debian9/README15
-rw-r--r--scripts/crossbuild/docker/ubuntu16/Dockerfile86
-rw-r--r--scripts/crossbuild/docker/ubuntu18/Dockerfile65
-rw-r--r--scripts/crossbuild/docker/ubuntu20/Dockerfile65
-rwxr-xr-xscripts/cryptpasswd.in83
-rwxr-xr-xscripts/dhcp/isc2ippool.pl189
-rwxr-xr-xscripts/dhcp/rlm_iscfixed2ippool422
-rwxr-xr-xscripts/dict_alias.sh22
-rw-r--r--scripts/docker/README.md200
-rw-r--r--scripts/docker/alpine/Dockerfile83
-rwxr-xr-xscripts/docker/alpine/docker-entrypoint.sh27
-rw-r--r--scripts/docker/centos7/Dockerfile96
-rwxr-xr-xscripts/docker/centos7/docker-entrypoint.sh24
-rw-r--r--scripts/docker/debian10/Dockerfile59
-rwxr-xr-xscripts/docker/debian10/docker-entrypoint.sh24
-rw-r--r--scripts/docker/debian11/Dockerfile64
-rwxr-xr-xscripts/docker/debian11/docker-entrypoint.sh24
-rw-r--r--scripts/docker/debian9/Dockerfile59
-rwxr-xr-xscripts/docker/debian9/docker-entrypoint.sh24
-rw-r--r--scripts/docker/debiansid/Dockerfile64
-rwxr-xr-xscripts/docker/debiansid/docker-entrypoint.sh24
-rw-r--r--scripts/docker/docker.mk86
-rw-r--r--scripts/docker/rocky8/Dockerfile108
-rwxr-xr-xscripts/docker/rocky8/docker-entrypoint.sh24
-rw-r--r--scripts/docker/ubuntu18/Dockerfile59
-rwxr-xr-xscripts/docker/ubuntu18/docker-entrypoint.sh24
-rw-r--r--scripts/docker/ubuntu20/Dockerfile61
-rwxr-xr-xscripts/docker/ubuntu20/docker-entrypoint.sh24
-rw-r--r--scripts/docker/ubuntu22/Dockerfile66
-rwxr-xr-xscripts/docker/ubuntu22/docker-entrypoint.sh24
-rwxr-xr-xscripts/exec-program-wait62
-rwxr-xr-xscripts/git/post-receive151
-rw-r--r--scripts/install.mk250
-rw-r--r--scripts/jlibtool.c2608
-rwxr-xr-xscripts/ldap/radiusd2ldif.pl307
-rw-r--r--scripts/ldap/schema_to_samba.py132
-rw-r--r--scripts/libtool.mk243
-rw-r--r--scripts/logrotate/freeradius59
-rwxr-xr-xscripts/min-includes.pl238
-rw-r--r--scripts/monit/freeradius.monitrc18
-rwxr-xr-xscripts/munin/freeradius_acct88
-rwxr-xr-xscripts/munin/freeradius_auth103
-rwxr-xr-xscripts/munin/freeradius_proxy_acct88
-rwxr-xr-xscripts/munin/freeradius_proxy_auth103
-rwxr-xr-xscripts/munin/radsniff246
-rw-r--r--scripts/osx/README2
-rw-r--r--scripts/osx/org.freeradius.radiusd.plist21
-rwxr-xr-xscripts/raddebug140
-rw-r--r--scripts/radiusd.sh17
-rwxr-xr-xscripts/radtee563
-rwxr-xr-xscripts/raduat366
-rwxr-xr-xscripts/rc.radiusd.in100
-rw-r--r--scripts/snmp-proxy/README32
-rw-r--r--scripts/snmp-proxy/dictionary.hacked132
-rw-r--r--scripts/snmp-proxy/freeradius-snmp.pl585
-rw-r--r--scripts/snmp-proxy/net-radius-freeradius-dictionary.diff81
-rw-r--r--scripts/solaris/.gitignore1
-rw-r--r--scripts/solaris/README.md58
-rw-r--r--scripts/solaris/radius.xml68
-rwxr-xr-xscripts/solaris/svc-radius.in99
-rwxr-xr-xscripts/sql/align_sql_pools.pl311
-rwxr-xr-xscripts/sql/generate_pool_addresses.pl456
-rwxr-xr-xscripts/sql/radsqlrelay342
-rwxr-xr-xscripts/sql/rlm_sqlippool_tool961
-rw-r--r--scripts/sql/users2mysql.pl157
-rw-r--r--share/LICENSE339
-rw-r--r--share/Makefile13
-rwxr-xr-xshare/attrnew.pl93
-rwxr-xr-xshare/attrsort.pl87
-rwxr-xr-xshare/backref.pl192
-rwxr-xr-xshare/dct2fr31
-rw-r--r--share/dictionary340
-rw-r--r--share/dictionary.3com54
-rw-r--r--share/dictionary.3gpp76
-rw-r--r--share/dictionary.3gpp2192
-rw-r--r--share/dictionary.acc260
-rw-r--r--share/dictionary.acme241
-rw-r--r--share/dictionary.actelis19
-rw-r--r--share/dictionary.adtran18
-rw-r--r--share/dictionary.adva41
-rw-r--r--share/dictionary.aerohive75
-rw-r--r--share/dictionary.airespace33
-rw-r--r--share/dictionary.alcatel101
-rw-r--r--share/dictionary.alcatel-lucent.aaa88
-rw-r--r--share/dictionary.alcatel.esam253
-rw-r--r--share/dictionary.alcatel.sr420
-rw-r--r--share/dictionary.alteon32
-rw-r--r--share/dictionary.altiga163
-rw-r--r--share/dictionary.alvarion313
-rw-r--r--share/dictionary.alvarion.wimax.v2_236
-rw-r--r--share/dictionary.apc39
-rw-r--r--share/dictionary.aptilo154
-rw-r--r--share/dictionary.aptis184
-rw-r--r--share/dictionary.arbor21
-rw-r--r--share/dictionary.arista29
-rw-r--r--share/dictionary.aruba101
-rw-r--r--share/dictionary.ascend899
-rw-r--r--share/dictionary.ascend.illegal432
-rw-r--r--share/dictionary.asn96
-rw-r--r--share/dictionary.audiocodes23
-rw-r--r--share/dictionary.avaya32
-rw-r--r--share/dictionary.azaire53
-rw-r--r--share/dictionary.bay295
-rw-r--r--share/dictionary.bigswitch17
-rw-r--r--share/dictionary.bintec49
-rw-r--r--share/dictionary.bluecoat27
-rw-r--r--share/dictionary.boingo48
-rw-r--r--share/dictionary.bristol23
-rw-r--r--share/dictionary.broadsoft371
-rw-r--r--share/dictionary.brocade24
-rw-r--r--share/dictionary.bskyb26
-rw-r--r--share/dictionary.bt19
-rw-r--r--share/dictionary.cablelabs202
-rw-r--r--share/dictionary.cabletron28
-rw-r--r--share/dictionary.calix29
-rw-r--r--share/dictionary.cambium78
-rw-r--r--share/dictionary.camiant24
-rw-r--r--share/dictionary.centec18
-rw-r--r--share/dictionary.checkpoint13
-rw-r--r--share/dictionary.chillispot40
-rw-r--r--share/dictionary.ciena41
-rw-r--r--share/dictionary.cisco226
-rw-r--r--share/dictionary.cisco.asa369
-rw-r--r--share/dictionary.cisco.bbsm15
-rw-r--r--share/dictionary.cisco.vpn3000243
-rw-r--r--share/dictionary.cisco.vpn500021
-rw-r--r--share/dictionary.citrix25
-rw-r--r--share/dictionary.clavister22
-rw-r--r--share/dictionary.cnergee52
-rw-r--r--share/dictionary.colubris13
-rw-r--r--share/dictionary.columbia_university29
-rw-r--r--share/dictionary.compat44
-rw-r--r--share/dictionary.compatible22
-rw-r--r--share/dictionary.cosine26
-rw-r--r--share/dictionary.covaro43
-rw-r--r--share/dictionary.dante20
-rw-r--r--share/dictionary.dellemc19
-rw-r--r--share/dictionary.dhcp608
-rw-r--r--share/dictionary.digium39
-rw-r--r--share/dictionary.dlink37
-rw-r--r--share/dictionary.dragonwave31
-rw-r--r--share/dictionary.efficientip31
-rw-r--r--share/dictionary.eleven52
-rw-r--r--share/dictionary.eltex26
-rw-r--r--share/dictionary.epygi118
-rw-r--r--share/dictionary.equallogic43
-rw-r--r--share/dictionary.ericsson134
-rw-r--r--share/dictionary.ericsson.ab451
-rw-r--r--share/dictionary.ericsson.packet.core.networks15
-rw-r--r--share/dictionary.erx433
-rw-r--r--share/dictionary.extreme36
-rw-r--r--share/dictionary.f551
-rw-r--r--share/dictionary.fdxtended19
-rw-r--r--share/dictionary.force1010
-rw-r--r--share/dictionary.fortinet55
-rw-r--r--share/dictionary.foundry58
-rw-r--r--share/dictionary.freedhcp369
-rw-r--r--share/dictionary.freeradius202
-rw-r--r--share/dictionary.freeradius.evs522
-rw-r--r--share/dictionary.freeradius.internal890
-rw-r--r--share/dictionary.freeswitch112
-rw-r--r--share/dictionary.gandalf103
-rw-r--r--share/dictionary.garderos25
-rw-r--r--share/dictionary.gemtek20
-rw-r--r--share/dictionary.h3c95
-rw-r--r--share/dictionary.hillstone51
-rw-r--r--share/dictionary.hp103
-rw-r--r--share/dictionary.huawei243
-rw-r--r--share/dictionary.iana48
-rw-r--r--share/dictionary.iea19
-rw-r--r--share/dictionary.infinera12
-rw-r--r--share/dictionary.infoblox21
-rw-r--r--share/dictionary.infonet50
-rw-r--r--share/dictionary.ipunplugged29
-rw-r--r--share/dictionary.issanni44
-rw-r--r--share/dictionary.itk45
-rw-r--r--share/dictionary.juniper79
-rw-r--r--share/dictionary.karlnet2076
-rw-r--r--share/dictionary.kineto119
-rw-r--r--share/dictionary.lancom42
-rw-r--r--share/dictionary.lantronix13
-rw-r--r--share/dictionary.livingston63
-rw-r--r--share/dictionary.localweb35
-rw-r--r--share/dictionary.lucent454
-rw-r--r--share/dictionary.manzara33
-rw-r--r--share/dictionary.meinberg19
-rw-r--r--share/dictionary.mellanox18
-rw-r--r--share/dictionary.meraki15
-rw-r--r--share/dictionary.merit17
-rw-r--r--share/dictionary.meru18
-rw-r--r--share/dictionary.microsemi22
-rw-r--r--share/dictionary.microsoft170
-rw-r--r--share/dictionary.mikrotik68
-rw-r--r--share/dictionary.mimosa39
-rw-r--r--share/dictionary.motorola74
-rw-r--r--share/dictionary.motorola.illegal29
-rw-r--r--share/dictionary.motorola.wimax37
-rw-r--r--share/dictionary.navini22
-rw-r--r--share/dictionary.net132
-rw-r--r--share/dictionary.netelastic55
-rw-r--r--share/dictionary.netscreen34
-rw-r--r--share/dictionary.networkphysics19
-rw-r--r--share/dictionary.nexans21
-rw-r--r--share/dictionary.nile20
-rw-r--r--share/dictionary.nokia41
-rw-r--r--share/dictionary.nokia.conflict32
-rw-r--r--share/dictionary.nomadix34
-rw-r--r--share/dictionary.nortel77
-rw-r--r--share/dictionary.ntua46
-rw-r--r--share/dictionary.openser43
-rw-r--r--share/dictionary.packeteer26
-rw-r--r--share/dictionary.paloalto29
-rw-r--r--share/dictionary.patton156
-rw-r--r--share/dictionary.perle525
-rw-r--r--share/dictionary.pfsense18
-rw-r--r--share/dictionary.pica820
-rw-r--r--share/dictionary.propel17
-rw-r--r--share/dictionary.prosoft44
-rw-r--r--share/dictionary.proxim94
-rw-r--r--share/dictionary.purewave53
-rw-r--r--share/dictionary.quiconnect21
-rw-r--r--share/dictionary.quintum52
-rw-r--r--share/dictionary.rcntec19
-rw-r--r--share/dictionary.redcreek23
-rw-r--r--share/dictionary.rfc2865139
-rw-r--r--share/dictionary.rfc286659
-rw-r--r--share/dictionary.rfc286718
-rw-r--r--share/dictionary.rfc286856
-rw-r--r--share/dictionary.rfc286941
-rw-r--r--share/dictionary.rfc316215
-rw-r--r--share/dictionary.rfc357632
-rw-r--r--share/dictionary.rfc358018
-rw-r--r--share/dictionary.rfc407211
-rw-r--r--share/dictionary.rfc437210
-rw-r--r--share/dictionary.rfc460319
-rw-r--r--share/dictionary.rfc467530
-rw-r--r--share/dictionary.rfc467974
-rw-r--r--share/dictionary.rfc481814
-rw-r--r--share/dictionary.rfc484910
-rw-r--r--share/dictionary.rfc509029
-rw-r--r--share/dictionary.rfc517611
-rw-r--r--share/dictionary.rfc544717
-rw-r--r--share/dictionary.rfc558043
-rw-r--r--share/dictionary.rfc560732
-rw-r--r--share/dictionary.rfc590424
-rw-r--r--share/dictionary.rfc651911
-rw-r--r--share/dictionary.rfc657228
-rw-r--r--share/dictionary.rfc667720
-rw-r--r--share/dictionary.rfc691113
-rw-r--r--share/dictionary.rfc692926
-rw-r--r--share/dictionary.rfc693012
-rw-r--r--share/dictionary.rfc705512
-rw-r--r--share/dictionary.rfc715512
-rw-r--r--share/dictionary.rfc726870
-rw-r--r--share/dictionary.rfc749918
-rw-r--r--share/dictionary.rfc793010
-rw-r--r--share/dictionary.rfc804565
-rw-r--r--share/dictionary.rfc85599
-rw-r--r--share/dictionary.riverbed21
-rw-r--r--share/dictionary.riverstone45
-rw-r--r--share/dictionary.roaringpenguin32
-rw-r--r--share/dictionary.ruckus155
-rw-r--r--share/dictionary.ruggedcom12
-rw-r--r--share/dictionary.sangoma114
-rw-r--r--share/dictionary.sg149
-rw-r--r--share/dictionary.shasta26
-rw-r--r--share/dictionary.shiva131
-rw-r--r--share/dictionary.siemens28
-rw-r--r--share/dictionary.slipstream21
-rw-r--r--share/dictionary.sofaware39
-rw-r--r--share/dictionary.softbank32
-rw-r--r--share/dictionary.sonicwall64
-rw-r--r--share/dictionary.springtide34
-rw-r--r--share/dictionary.starent1383
-rw-r--r--share/dictionary.starent.vsa11202
-rw-r--r--share/dictionary.surfnet21
-rw-r--r--share/dictionary.symbol55
-rw-r--r--share/dictionary.t_systems_nova35
-rw-r--r--share/dictionary.telebit21
-rw-r--r--share/dictionary.telkom31
-rw-r--r--share/dictionary.telrad23
-rw-r--r--share/dictionary.terena19
-rw-r--r--share/dictionary.trapeze40
-rw-r--r--share/dictionary.travelping76
-rw-r--r--share/dictionary.tripplite63
-rw-r--r--share/dictionary.tropos55
-rw-r--r--share/dictionary.ukerna39
-rw-r--r--share/dictionary.unix21
-rw-r--r--share/dictionary.usr1618
-rw-r--r--share/dictionary.usr.illegal49
-rw-r--r--share/dictionary.utstarcom45
-rw-r--r--share/dictionary.valemount29
-rw-r--r--share/dictionary.vasexperts93
-rw-r--r--share/dictionary.verizon26
-rw-r--r--share/dictionary.versanet56
-rw-r--r--share/dictionary.vqp112
-rw-r--r--share/dictionary.walabi31
-rw-r--r--share/dictionary.waverider58
-rw-r--r--share/dictionary.wichorus26
-rw-r--r--share/dictionary.wifialliance94
-rw-r--r--share/dictionary.wimax619
-rw-r--r--share/dictionary.wimax.alvarion516
-rw-r--r--share/dictionary.wimax.wichorus409
-rw-r--r--share/dictionary.wispr41
-rw-r--r--share/dictionary.xedia26
-rw-r--r--share/dictionary.xylan56
-rw-r--r--share/dictionary.yubico25
-rw-r--r--share/dictionary.zeus18
-rw-r--r--share/dictionary.zte73
-rw-r--r--share/dictionary.zyxel27
-rwxr-xr-xshare/format.pl235
-rw-r--r--site.yml17
-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
-rw-r--r--suse/README.SuSE14
-rw-r--r--suse/freeradius-server-rpmlintrc7
-rw-r--r--suse/freeradius-server-tmpfiles.conf1
-rw-r--r--suse/freeradius.spec260
-rw-r--r--suse/radiusd-logrotate68
-rw-r--r--suse/radiusd-pam6
-rw-r--r--suse/rcradiusd138
2098 files changed, 578195 insertions, 0 deletions
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..a76baa9
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,5 @@
+* text=auto
+* ident
+*.h linguist-language=c
+*.c linguist-language=c
+doc/* linguist-documentation
diff --git a/.github/workflows/ci-deb.yml b/.github/workflows/ci-deb.yml
new file mode 100644
index 0000000..965c926
--- /dev/null
+++ b/.github/workflows/ci-deb.yml
@@ -0,0 +1,230 @@
+name: CI DEB
+
+on:
+ push:
+ branches-ignore:
+ - coverity_scan
+ pull_request:
+
+env:
+ DEBIAN_FRONTEND: noninteractive
+ CC: gcc
+
+jobs:
+ deb-build:
+
+ strategy:
+ matrix:
+ env:
+ - { NAME: "ubuntu-18.04", OS: "ubuntu:bionic-20220801" }
+ - { NAME: "ubuntu-20.04", OS: "ubuntu:20.04" }
+ - { NAME: "ubuntu-22.04", OS: "ubuntu:22.04" }
+ - { NAME: "debian-10", OS: "debian:buster" }
+ - { NAME: "debian-11", OS: "debian:bullseye" }
+ - { NAME: "debian-sid", OS: "debian:sid" }
+ fail-fast: false
+
+ runs-on: ubuntu-latest
+
+ container:
+ image: ${{ matrix.env.OS }}
+
+ env:
+ HOSTAPD_BUILD_DIR: /tmp/eapol_test.ci
+ HOSTAPD_GIT_TAG: hostap_2_8
+
+ name: "DEB build"
+
+ steps:
+
+ - name: Package manager performance and stability improvements
+ run: |
+ if [ -f "/etc/apt/sources.list" ]; then
+ sed -i 's/deb.debian.org/debian-archive.trafficmanager.net/' /etc/apt/sources.list
+ sed -i 's/archive.ubuntu.com/azure.archive.ubuntu.com/' /etc/apt/sources.list
+ fi
+ echo 'Acquire::Retries "10";' > /etc/apt/apt.conf.d/80-retries
+ echo 'force-unsafe-io' > /etc/dpkg/dpkg.cfg.d/02speedup
+ echo 'man-db man-db/auto-update boolean false' | debconf-set-selections
+ apt-get update
+
+ - name: Install recent git
+ run: |
+ apt-get install -y --no-install-recommends git-core ca-certificates
+
+ - uses: actions/checkout@v3
+ with:
+ path: freeradius
+
+ - name: Prepare filesystem
+ run: |
+ pwd
+ ls -la
+ mkdir debs
+ ls -la
+
+ - name: Install build dependencies
+ run: |
+ apt-get install -y --no-install-recommends build-essential devscripts quilt equivs procps
+ debian/rules debian/control
+ mk-build-deps -irt"apt-get -y" debian/control
+ working-directory: freeradius
+
+ - name: Show versions
+ run: |
+ $CC --version
+ make --version
+ krb5-config --all || :
+ openssl version
+
+ - name: Build DEBs
+ run: |
+ make deb
+ working-directory: freeradius
+
+ - name: Collect DEBs
+ run: |
+ mv *.deb debs/
+
+ - name: Restore eapol_test build directory from cache
+ uses: actions/cache@v3
+ id: hostapd-cache
+ with:
+ path: ${{ env.HOSTAPD_BUILD_DIR }}
+ key: hostapd-${{ matrix.env.NAME }}-${{ env.HOSTAPD_GIT_TAG }}-v1
+
+ # Debian sid defaults to gcc12 which fails to build eapol_test
+ - name: Install GCC 10 for eapol_test build
+ run: |
+ apt-get install -y --no-install-recommends gcc-10
+ update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 60 && update-alternatives --set gcc /usr/bin/gcc-10
+ if: ${{ matrix.env.OS == 'debian:sid' }}
+
+ - name: Build eapol_test
+ run: |
+ apt-get install -y libnl-3-dev libnl-genl-3-dev
+ scripts/ci/eapol_test-build.sh
+ mv scripts/ci/eapol_test/eapol_test ../debs
+ working-directory: freeradius
+
+ - name: Store DEBs
+ uses: actions/upload-artifact@v3
+ with:
+ name: debs-${{ matrix.env.NAME }}
+ path: debs
+
+ #
+ # If the CI has failed and the branch is ci-debug then start a tmate
+ # session. SSH rendezvous point is emited continuously in the job output.
+ #
+ - name: "Debug: Package dependancies for tmate"
+ run: |
+ apt-get install -y --no-install-recommends xz-utils
+ if: ${{ github.ref == 'refs/heads/ci-debug' && failure() }}
+
+ - name: "Debug: Start tmate"
+ uses: mxschmitt/action-tmate@v3
+ with:
+ limit-access-to-actor: true
+ sudo: false
+ if: ${{ github.ref == 'refs/heads/ci-debug' && failure() }}
+
+
+ deb-test:
+
+ needs:
+ - deb-build
+
+ strategy:
+ matrix:
+ env:
+ - { NAME: "ubuntu-18.04", OS: "ubuntu:bionic-20220801" }
+ - { NAME: "ubuntu-20.04", OS: "ubuntu:20.04" }
+ - { NAME: "ubuntu-22.04", OS: "ubuntu:22.04" }
+ - { NAME: "debian-10", OS: "debian:buster" }
+ - { NAME: "debian-11", OS: "debian:bullseye" }
+ - { NAME: "debian-sid", OS: "debian:sid" }
+ fail-fast: false
+
+ runs-on: ubuntu-latest
+
+ container:
+ image: ${{ matrix.env.OS }}
+
+ name: "DEB install test"
+
+ steps:
+
+ - name: Load DEBs
+ uses: actions/download-artifact@v3
+ with:
+ name: debs-${{ matrix.env.NAME }}
+
+ - name: Package manager performance improvements
+ run: |
+ if [ -f "/etc/apt/sources.list" ]; then
+ sed -i 's/deb.debian.org/debian-archive.trafficmanager.net/' /etc/apt/sources.list
+ sed -i 's/archive.ubuntu.com/azure.archive.ubuntu.com/' /etc/apt/sources.list
+ fi
+ echo force-unsafe-io > /etc/dpkg/dpkg.cfg.d/02speedup
+ echo 'man-db man-db/auto-update boolean false' | debconf-set-selections
+ apt-get update
+
+ # For pkill and strings
+ - name: Install procps and binutils
+ run: |
+ apt-get update
+ apt-get install -y --no-install-recommends procps binutils
+
+ - name: Install DEBs
+ run: |
+ find . -maxdepth 1 -name '*.deb' | xargs apt-get install -y --no-install-recommends
+
+ - name: Config test
+ run: |
+ freeradius -XC
+
+ #
+ # We now perform some post-install tests that depend on the availability
+ # of the source tree
+ #
+ - name: Install pre-built eapol_test
+ run: |
+ apt-get install -y libssl1.? libdbus-1-? libnl-3-200 libnl-genl-3-200
+ mv eapol_test /usr/local/bin
+ chmod +x /usr/local/bin/eapol_test
+
+ - uses: actions/checkout@v3
+ with:
+ path: freeradius
+
+ - name: Run the post-install test target
+ run: |
+ echo "top_builddir := $(pwd)" > Make.inc
+ make -C src/tests/ OPENSSL_LIBS=1 EAPOL_TEST_BIN="$(which eapol_test)" $(pwd)/build/tests/eapol_test/eapol_test.mk
+ make -f scripts/ci/package-test.mk package-test
+ working-directory: freeradius
+
+ - name: Upload radius logs on failure
+ if: ${{ failure() }}
+ uses: actions/upload-artifact@v3
+ with:
+ name: radius-logs-${{ matrix.env.NAME }}.tgz
+ path: |
+ /var/log/freeradius
+ freeradius/build/tests/eapol_test
+
+ #
+ # See above comments for tmate
+ #
+ - name: "Debug: Package dependancies for tmate"
+ run: |
+ apt-get install -y --no-install-recommends xz-utils
+ if: ${{ github.ref == 'refs/heads/ci-debug' && failure() }}
+
+ - name: "Debug: Start tmate"
+ uses: mxschmitt/action-tmate@v3
+ with:
+ limit-access-to-actor: true
+ sudo: false
+ if: ${{ github.ref == 'refs/heads/ci-debug' && failure() }}
diff --git a/.github/workflows/ci-rpm.yml b/.github/workflows/ci-rpm.yml
new file mode 100644
index 0000000..94517f3
--- /dev/null
+++ b/.github/workflows/ci-rpm.yml
@@ -0,0 +1,332 @@
+name: CI RPM
+
+on:
+ push:
+ branches-ignore:
+ - coverity_scan
+ pull_request:
+
+env:
+ CC: gcc
+
+jobs:
+ rpm-build:
+
+ strategy:
+ matrix:
+ env:
+ - { NAME: "centos-7", OS: "centos:7" }
+ - { NAME: "centos-8", OS: "centos:8" }
+ - { NAME: "rocky-8", OS: "rockylinux/rockylinux:8" }
+ - { NAME: "rocky-9", OS: "rockylinux/rockylinux:9" }
+ fail-fast: false
+
+ runs-on: ubuntu-latest
+
+ container:
+ image: ${{ matrix.env.OS }}
+
+ env:
+ HOSTAPD_BUILD_DIR: /tmp/eapol_test.ci
+ HOSTAPD_GIT_TAG: hostapd_2_8
+
+ name: "RPM build"
+
+ steps:
+
+ #
+ # Centos9 is EOL, so we need the below tricks to get it to work.
+ #
+ # Converting from CentOS Linux 8 to CentOS Stream 8 is the "official" process
+ # (see centos.org/centos-stream/#centos-stream-8):
+ #
+ - name: Some hacks for CentOS 8 (EOL) to work again.
+ if: ${{ matrix.env.NAME == 'centos-8' }}
+ run: |
+ sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-Linux-*
+ sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-Linux-*
+ yum upgrade -y
+ yum -y --disablerepo '*' --enablerepo extras swap centos-linux-repos centos-stream-repos
+ yum clean all && yum makecache
+ yum distro-sync -y --allowerasing
+
+ # Required so that the checkout action uses git protocol rather than the GitHub REST API.
+ # make rpm requires the FR directory to be a git repository.
+ - name: Install recent git for CentOS 7
+ if: ${{ matrix.env.NAME == 'centos-7' }}
+ run: |
+ yum install -y https://packages.endpointdev.com/rhel/7/os/x86_64/git-core-2.30.1-1.ep7.x86_64.rpm
+
+ - name: Install distro git for Rocky and CentOS 8.
+ if: ${{ startsWith(matrix.env.NAME, 'rocky-') || matrix.env.NAME == 'centos-8' }}
+ run: |
+ yum install -y git-core
+
+ - uses: actions/checkout@v3
+ with:
+ path: freeradius
+
+ - name: Prepare filesystem
+ run: |
+ pwd
+ ls -la
+ mkdir rpms
+ ls -la
+
+ - name: LTB repo for CentOS and Rocky Linux 8
+ if: ${{ startsWith(matrix.env.NAME, 'centos-') || matrix.env.NAME == 'rocky-8' }}
+ run: |
+ echo '[ltb-project]' > /etc/yum.repos.d/ltb-project.repo
+ echo 'name=LTB project packages' >> /etc/yum.repos.d/ltb-project.repo
+ echo 'baseurl=https://ltb-project.org/rpm/$releasever/$basearch' >> /etc/yum.repos.d/ltb-project.repo
+ echo 'enabled=1' >> /etc/yum.repos.d/ltb-project.repo
+ echo 'gpgcheck=1' >> /etc/yum.repos.d/ltb-project.repo
+ echo 'gpgkey=https://www.ltb-project.org/documentation/_static/RPM-GPG-KEY-LTB-project' >> /etc/yum.repos.d/ltb-project.repo
+ rpm --import https://www.ltb-project.org/documentation/_static/RPM-GPG-KEY-LTB-project
+
+ - name: Enable EPEL for CentOS and Rocky Linux
+ if: ${{ startsWith(matrix.env.NAME, 'centos-') || startsWith(matrix.env.NAME, 'rocky-') }}
+ run: |
+ yum install -y epel-release
+
+ - name: Enable PowerTools on Rocky 8 and CentOS 8.
+ if: ${{ matrix.env.NAME == 'rocky-8' || matrix.env.NAME == 'centos-8' }}
+ run: |
+ yum install -y yum-utils
+ yum config-manager --enable PowerTools || :
+ yum config-manager --enable powertools || :
+
+ - name: Enable Code Ready Builer on Rocky 9.
+ if: ${{ matrix.env.NAME == 'rocky-9' }}
+ run: |
+ yum install -y yum-utils
+ yum config-manager --enable crb
+
+ - name: Install common tools
+ run: |
+ yum install -y \
+ bzip2 \
+ gcc \
+ make \
+ perl \
+ rpm-build \
+ yum-utils
+
+ #
+ # We just patch the SPEC file for Fedora since we want to use the standard
+ # make rpm target which wants to build with LDAP.
+ #
+ - name: Disable rlm_ldap on Fedora (no LTB packages)
+ if: ${{ startsWith(matrix.env.NAME, 'fedora-') }}
+ run: |
+ sed -ie 's/%bcond_without ldap/%global _without_ldap: 1/' freeradius/redhat/freeradius.spec
+
+ - name: Install build dependencies
+ run: |
+ yum-builddep -y freeradius/redhat/freeradius.spec
+
+ #
+ # It has been observed that sometimes not all the dependencies are
+ # installed on the first go. Give it a second chance.
+ #
+ - name: Second run of install build dependencies
+ run: |
+ yum-builddep -y redhat/freeradius.spec
+ working-directory: freeradius
+
+ - name: Show versions
+ run: |
+ $CC --version
+ make --version
+ krb5-config --all || :
+ openssl version
+
+ # For pkill and ps
+ - name: Enable procps-ng on Centos and Rocky
+ if: ${{ startsWith(matrix.env.NAME, 'centos-8') || startsWith(matrix.env.NAME, 'rocky-') }}
+ run: |
+ yum install -y procps-ng
+
+ - name: Build RPMs
+ run: |
+ [ -r /opt/rh/devtoolset-8/enable ] && source /opt/rh/devtoolset-8/enable || :
+ ./configure
+ make rpm
+ working-directory: freeradius
+
+ - name: Collect RPMs
+ run: |
+ mv freeradius/rpmbuild/RPMS/x86_64/*.rpm rpms/
+
+ - name: Restore eapol_test build directory from cache
+ uses: actions/cache@v3
+ id: hostapd-cache
+ with:
+ path: ${{ env.HOSTAPD_BUILD_DIR }}
+ key: hostapd-${{ matrix.env.NAME }}-${{ env.HOSTAPD_GIT_TAG }}-v1
+
+ - name: Build eapol_test
+ run: |
+ yum install -y libnl3-devel which
+ [ -r /opt/rh/devtoolset-8/enable ] && source /opt/rh/devtoolset-8/enable || :
+ scripts/ci/eapol_test-build.sh
+ mv scripts/ci/eapol_test/eapol_test ../rpms/
+ working-directory: freeradius
+
+ - name: Store RPMs
+ uses: actions/upload-artifact@v3
+ with:
+ name: rpms-${{ matrix.env.NAME }}
+ path: rpms
+
+ #
+ # If the CI has failed and the branch is ci-debug then start a tmate
+ # session. SSH rendezvous point is emited continuously in the job output.
+ #
+ - name: "Debug: Package dependancies for tmate"
+ run: |
+ yum install -y xz
+ ln -s /bin/true /bin/apt-get
+ if: ${{ github.ref == 'refs/heads/ci-debug' && failure() }}
+
+ - name: "Debug: Start tmate"
+ uses: mxschmitt/action-tmate@v3
+ with:
+ limit-access-to-actor: true
+ sudo: false
+ if: ${{ github.ref == 'refs/heads/ci-debug' && failure() }}
+
+
+ rpm-test:
+
+ needs:
+ - rpm-build
+
+ strategy:
+ matrix:
+ env:
+ - { NAME: "centos-7", OS: "centos:7" }
+ - { NAME: "centos-8", OS: "centos:8" }
+ - { NAME: "rocky-8", OS: "rockylinux/rockylinux:8" }
+ - { NAME: "rocky-9", OS: "rockylinux/rockylinux:9" }
+ fail-fast: false
+
+ runs-on: ubuntu-latest
+
+ container:
+ image: ${{ matrix.env.OS }}
+
+ name: "RPM install test"
+
+ steps:
+
+ #
+ # Centos9 is EOL, so we need the below tricks to get it to work.
+ #
+ # Converting from CentOS Linux 8 to CentOS Stream 8 is the "official" process
+ # (see centos.org/centos-stream/#centos-stream-8):
+ #
+ - name: Some hacks for CentOS 8 (EOL) to work again.
+ if: ${{ matrix.env.NAME == 'centos-8' }}
+ run: |
+ sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-Linux-*
+ sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-Linux-*
+ yum upgrade -y
+ yum -y --disablerepo '*' --enablerepo extras swap centos-linux-repos centos-stream-repos
+ yum clean all && yum makecache
+ yum distro-sync -y --allowerasing
+
+ - name: LTB repo for CentOS and Rocky 8
+ if: ${{ startsWith(matrix.env.NAME, 'centos-') || matrix.env.NAME == 'rocky-8' }}
+ run: |
+ echo '[ltb-project]' > /etc/yum.repos.d/ltb-project.repo
+ echo 'name=LTB project packages' >> /etc/yum.repos.d/ltb-project.repo
+ echo 'baseurl=https://ltb-project.org/rpm/$releasever/$basearch' >> /etc/yum.repos.d/ltb-project.repo
+ echo 'enabled=1' >> /etc/yum.repos.d/ltb-project.repo
+ echo 'gpgcheck=1' >> /etc/yum.repos.d/ltb-project.repo
+ echo 'gpgkey=https://www.ltb-project.org/documentation/_static/RPM-GPG-KEY-LTB-project' >> /etc/yum.repos.d/ltb-project.repo
+ rpm --import https://www.ltb-project.org/documentation/_static/RPM-GPG-KEY-LTB-project
+
+ - name: Enable EPEL for CentOS and Rocky Linux
+ if: ${{ startsWith(matrix.env.NAME, 'centos-') || startsWith(matrix.env.NAME, 'rocky-') }}
+ run: |
+ yum install -y epel-release
+
+ - name: Enable PowerTools on Centos 8 and Rocky 8
+ if: ${{ matrix.env.NAME == 'centos-8' || matrix.env.NAME == 'rocky-8' }}
+ run: |
+ yum install -y yum-utils
+ yum config-manager --enable PowerTools || :
+ yum config-manager --enable powertools || :
+
+ - name: Enable Code Ready Builer on Rocky 9.
+ if: ${{ matrix.env.NAME == 'rocky-9' }}
+ run: |
+ yum install -y yum-utils
+ yum config-manager --enable crb
+
+ # For pkill
+ - name: Enable procps-ng on Centos and Rocky
+ if: ${{ startsWith(matrix.env.NAME, 'centos-') || startsWith(matrix.env.NAME, 'rocky-') }}
+ run: |
+ yum install -y procps-ng
+
+ - name: Load RPMs
+ uses: actions/download-artifact@v3
+ with:
+ name: rpms-${{ matrix.env.NAME }}
+
+ - name: Install RPMs
+ run: |
+ yum install -y *.rpm
+
+ - name: Config check
+ run: |
+ radiusd -XC
+
+ #
+ # We now perform some post-install tests that depend on the availability
+ # of the source tree
+ #
+ - name: Install pre-built eapol_test
+ run: |
+ yum install -y libnl3 make gdb which
+ mv eapol_test /usr/local/bin
+ chmod +x /usr/local/bin/eapol_test
+
+ - uses: actions/checkout@v3
+ with:
+ path: freeradius
+
+ - name: Run the post-install test target
+ run: |
+ echo "top_builddir := $(pwd)" > Make.inc
+ make -C src/tests/ OPENSSL_LIBS=1 EAPOL_TEST_BIN="$(which eapol_test)" $(pwd)/build/tests/eapol_test/eapol_test.mk
+ make -f scripts/ci/package-test.mk package-test
+ working-directory: freeradius
+
+ - name: Upload radius logs on failure
+ if: ${{ failure() }}
+ uses: actions/upload-artifact@v3
+ with:
+ name: radius-logs-${{ matrix.env.NAME }}.tgz
+ path: |
+ /var/log/radius
+ freeradius/build/tests/eapol_test
+
+ #
+ # See above comments for tmate
+ #
+ - name: "Debug: Package dependancies for tmate"
+ run: |
+ yum install -y xz
+ ln -s /bin/true /bin/apt-get
+ if: ${{ github.ref == 'refs/heads/ci-debug' && failure() }}
+
+ - name: "Debug: Start tmate"
+ uses: mxschmitt/action-tmate@v3
+ with:
+ limit-access-to-actor: true
+ sudo: false
+ if: ${{ github.ref == 'refs/heads/ci-debug' && failure() }}
+
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..de5e7ed
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,483 @@
+name: CI
+
+on:
+ push:
+ branches-ignore:
+ - coverity_scan
+ pull_request:
+
+env:
+ PANIC_ACTION: "gdb -batch -x raddb/panic.gdb %e %p 1>&0 2>&0"
+ ALT_OPENSSL: "3.0.8"
+ CI: 1
+ GH_ACTIONS: 1
+ DEBIAN_FRONTEND: noninteractive
+ APT_OPTS: "-y --no-install-recommends"
+ LDAP_TEST_SERVER: 127.0.0.1
+ LDAP_TEST_SERVER_PORT: 3890
+ REST_TEST_SERVER: 127.0.0.1
+ REST_TEST_SERVER_PORT: 8080
+ REST_TEST_SERVER_SSL_PORT: 8443
+ SQL_MYSQL_TEST_SERVER: mariadb
+ SQL_POSTGRESQL_TEST_SERVER: postgres
+ ASAN_OPTIONS: symbolize=1 detect_leaks=1 detect_stack_use_after_return=1
+ LSAN_OPTIONS: fast_unwind_on_malloc=0:malloc_context_size=50
+ UBSAN_OPTIONS: print_stacktrace=1
+
+jobs:
+ pre-ci:
+ runs-on: ubuntu-latest
+ outputs:
+ should_skip: ${{ steps.skip_check.outputs.should_skip }}
+ selfhosted: ${{ github.repository_owner == 'FreeRADIUS' && '1' || '0' }}
+ docker_prefix: ${{ github.repository_owner == 'FreeRADIUS' && 'docker.internal.networkradius.com/' || '' }}
+ steps:
+ - id: skip_check
+ uses: fkirc/skip-duplicate-actions@master
+
+ ci:
+ needs: pre-ci
+ if: ${{ needs.pre-ci.outputs.should_skip != 'true' }}
+
+ runs-on: ${{ matrix.os.runs_on }}
+
+ container:
+ image: ${{ matrix.os.docker }}
+
+ strategy:
+ fail-fast: false
+ matrix:
+ os:
+#
+# runs_on - where GitHub will spin up the runner, either
+# "self-hosted", or the name of a GitHub VM image.
+# code - the name/version of the OS (for step evaluations below)
+# docker - the docker image name, if containers are being used
+# name - used in the job name only
+#
+ - runs_on: "${{ needs.pre-ci.outputs.selfhosted == '1' && 'self-hosted' || 'ubuntu-20.04' }}"
+ docker: "${{ needs.pre-ci.outputs.selfhosted == '1' && 'docker.internal.networkradius.com/self-hosted' || 'ubuntu:20.04' }}"
+ name: "${{ needs.pre-ci.outputs.selfhosted == '1' && 'self' || 'gh' }}-ubuntu20"
+ code: "ubuntu2004"
+
+ env:
+ - { CC: gcc, DO_BUILD: yes, LIBS_OPTIONAL: no, LIBS_ALT: no, REPRODUCIBLE: no, SANITIZER: no, BUILD_CFLAGS: "-DWITH_EVAL_DEBUG", NAME: linux-gcc-lean }
+ - { CC: gcc, DO_BUILD: yes, LIBS_OPTIONAL: yes, LIBS_ALT: no, REPRODUCIBLE: no, SANITIZER: no, BUILD_CFLAGS: "-DWITH_EVAL_DEBUG", NAME: linux-gcc }
+ - { CC: gcc, DO_BUILD: yes, LIBS_OPTIONAL: yes, LIBS_ALT: no, REPRODUCIBLE: yes, SANITIZER: no, BUILD_CFLAGS: "-DWITH_EVAL_DEBUG", NAME: linux-gcc-reproducible }
+ - { CC: gcc, DO_BUILD: yes, LIBS_OPTIONAL: yes, LIBS_ALT: no, REPRODUCIBLE: no, SANITIZER: no, BUILD_CFLAGS: "-DWITH_EVAL_DEBUG -O2 -g3", NAME: linux-gcc-O2-g3 }
+ - { CC: clang, DO_BUILD: yes, LIBS_OPTIONAL: no, LIBS_ALT: no, REPRODUCIBLE: no, SANITIZER: no, BUILD_CFLAGS: "-DWITH_EVAL_DEBUG", NAME: linux-clang-lean }
+ - { CC: clang, DO_BUILD: yes, LIBS_OPTIONAL: yes, LIBS_ALT: no, REPRODUCIBLE: no, SANITIZER: no, BUILD_CFLAGS: "-DWITH_EVAL_DEBUG", NAME: linux-clang }
+ - { CC: clang, DO_BUILD: yes, LIBS_OPTIONAL: yes, LIBS_ALT: yes, REPRODUCIBLE: no, SANITIZER: no, BUILD_CFLAGS: "-DWITH_EVAL_DEBUG", NAME: linux-clang-altlibs }
+ - { CC: clang, DO_BUILD: yes, LIBS_OPTIONAL: yes, LIBS_ALT: no, REPRODUCIBLE: yes, SANITIZER: no, BUILD_CFLAGS: "-DWITH_EVAL_DEBUG", NAME: linux-clang-reproducible }
+ - { CC: clang, DO_BUILD: yes, LIBS_OPTIONAL: yes, LIBS_ALT: no, REPRODUCIBLE: no, SANITIZER: yes, BUILD_CFLAGS: "-DWITH_EVAL_DEBUG", NAME: linux-clang-sanitizer }
+ - { CC: clang, DO_BUILD: yes, LIBS_OPTIONAL: yes, LIBS_ALT: no, REPRODUCIBLE: no, SANITIZER: no, BUILD_CFLAGS: "-DWITH_EVAL_DEBUG -O2 -g3", NAME: linux-clang-O2-g3 }
+
+ env: ${{ matrix.env }}
+
+ # Test names are used in the branch protection rules in GitHub
+ # If you change the names here, or add additional matrix entries, you
+ # must also amend the branch protection fules.
+ name: "v3.2.x-${{ matrix.os.name }}-${{ matrix.env.NAME }}"
+
+ # The standard GitHub environment contains PostgreSQL and
+ # MySQL already. However when running on hosted GitHub runners
+ # we need to run separate database containers to provide these.
+ services:
+ mariadb:
+ image: ${{ needs.pre-ci.outputs.docker_prefix }}mariadb
+ env:
+ MARIADB_ALLOW_EMPTY_ROOT_PASSWORD: yes
+ ports:
+ - 3306:3306
+ options: --health-cmd="mysqladmin ping" --health-interval 10s --health-timeout 5s --health-retries 10
+
+ postgres:
+ image: ${{ needs.pre-ci.outputs.docker_prefix }}postgres
+ env:
+ POSTGRES_HOST_AUTH_METHOD: trust
+ ports:
+ - 5432:5432
+ options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
+
+ steps:
+
+ - name: Self-hosted runner container fixes
+ run: |
+ ln -fs /usr/bin/env /usr/local/bin/sudo
+ rm -rf "$HOME"/*
+
+ - name: Package manager performance improvements
+ run: |
+ sudo sh -c 'echo force-unsafe-io > /etc/dpkg/dpkg.cfg.d/02speedup'
+ if command -v mandb >/dev/null; then
+ echo 'man-db man-db/auto-update boolean false' | sudo debconf-set-selections
+ sudo dpkg-reconfigure man-db
+ fi
+
+ - name: Freshen APT repo metadata
+ run: |
+ sudo apt-get update
+
+ - name: Install common build dependencies
+ run: |
+ sudo apt-get install ${APT_OPTS} \
+ autoconf \
+ build-essential \
+ debhelper \
+ devscripts \
+ dh-make \
+ fakeroot \
+ firebird-dev \
+ freetds-dev \
+ gawk \
+ git \
+ git-lfs \
+ gnupg \
+ libcap-dev \
+ libcollectdclient-dev \
+ libcurl4-openssl-dev \
+ libgdbm-dev \
+ libhiredis-dev \
+ libidn11-dev \
+ libiodbc2 \
+ libiodbc2-dev \
+ libjson-c-dev \
+ libkqueue-dev \
+ libkrb5-dev \
+ libldap2-dev \
+ libmemcached-dev \
+ libmysqlclient-dev \
+ libnl-3-dev \
+ libnl-genl-3-dev \
+ libpam0g-dev \
+ libpcap-dev \
+ libpcre3-dev \
+ libperl-dev \
+ libpq-dev \
+ libreadline-dev \
+ libruby \
+ libsnmp-dev \
+ libsqlite3-dev \
+ libssl-dev \
+ libtalloc-dev \
+ libunbound-dev \
+ libwbclient-dev \
+ libykclient-dev \
+ libyubikey-dev \
+ lintian \
+ pbuilder \
+ python-dev \
+ python3-dev \
+ ruby-dev \
+ snmp \
+ software-properties-common \
+ quilt
+
+ - name: Install LLVM 15 for 20.04
+ if: ${{ matrix.os.code == 'ubuntu2004' && matrix.env.CC == 'clang' }}
+ run: |
+ wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add
+ sudo apt-add-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-15 main"
+ sudo apt-get install ${APT_OPTS} clang-15 llvm-15 gdb libclang-rt-15-dev
+ sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-15 60 && sudo update-alternatives --set clang /usr/bin/clang-15
+ sudo update-alternatives --install /usr/bin/llvm-symbolizer llvm-symbolizer /usr/bin/llvm-symbolizer-15 60 && sudo update-alternatives --set llvm-symbolizer /usr/bin/llvm-symbolizer-15
+
+ - name: Install GCC
+ if: ${{ matrix.env.CC == 'gcc' }}
+ run: |
+ sudo apt-get install ${APT_OPTS} gcc gdb
+
+ #
+ # Build using some alternative libraries
+ #
+ # MIT Kerberos -> HEIMDAL Kerberos
+ # OpenSSL 1.0 -> OpenSSL 3.0
+ #
+ - name: 'Fetch OpenSSL 3.0 SHA'
+ id: opensslshasum
+ if: ${{ matrix.env.LIBS_ALT == 'yes' }}
+ run: |
+ wget -qO- http://www.openssl.org/source/openssl-$ALT_OPENSSL.tar.gz.sha256 | sed -ne 's/^\s\+/shasum=/p' >> $GITHUB_OUTPUT
+
+ - name: 'Restore OpenSSL 3.0 from the cache'
+ if: ${{ matrix.env.LIBS_ALT == 'yes' }}
+ uses: actions/cache@v3
+ id: openssl-cache
+ with:
+ path: /opt/openssl/
+ key: openssl3-${{ steps.opensslshasum.outputs.shasum }}
+
+ - name: 'Build OpenSSL 3.0 (if cache stale)'
+ if: ${{ matrix.env.LIBS_ALT == 'yes' && steps.openssl-cache.outputs.cache-hit != 'true' }}
+ run: |
+ cd ~
+ wget https://www.openssl.org/source/openssl-$ALT_OPENSSL.tar.gz
+ tar xzf openssl-$ALT_OPENSSL.tar.gz
+ cd openssl-$ALT_OPENSSL
+ ./Configure --prefix=/opt/openssl --openssldir=.
+ make -j `nproc`
+ make install
+
+ - name: Use alternative libraries
+ if: ${{ matrix.env.LIBS_ALT == 'yes' }}
+ run: |
+ echo /opt/openssl/lib64 | sudo tee /etc/ld.so.conf.d/openssl3.conf >/dev/null
+ sudo ldconfig
+ sudo apt-get install ${APT_OPTS} heimdal-dev
+
+ - name: Show versions
+ run: |
+ printf "$CC: " ; $CC --version
+ printf "\nmake: " ; make --version
+ printf "\nkrb5: " ; krb5-config --all || :
+ [ -d /opt/openssl ] && export PATH=/opt/openssl/bin:$PATH
+ printf "\nopenssl: " ; openssl version
+
+ - uses: actions/checkout@v3
+
+ - name: Build eapol_test
+ run: |
+ if [ -d /opt/openssl ]; then
+ # Used by scripts/ci/eapol_test-build.sh
+ export PATH=/opt/openssl/bin:$PATH
+ export EAPOL_TEST_CFLAGS="-I/opt/openssl/include"
+ export EAPOL_TEST_LDFLAGS="-L/opt/openssl/lib64"
+ fi
+ ./scripts/ci/eapol_test-build.sh
+
+ - name: Build FreeRADIUS
+ run: |
+ export PATH=$(echo "$PATH" | sed -e 's#:/home/linuxbrew/[^:]\+##g')
+ if [ -d /opt/openssl ]; then
+ export PATH=/opt/openssl/bin:$PATH
+ CONFIG_OPENSSL="--with-openssl-lib-dir=/opt/openssl/lib64 --with-openssl-include-dir=/opt/openssl/include"
+ fi
+
+ if [ $SANITIZER = "yes" ]; then
+ echo "Enabling sanitizers"
+ enable_sanitizers="--enable-address-sanitizer --enable-undefined-behaviour-sanitizer"
+ if [ "`uname`" != "Darwin" ]; then
+ enable_sanitizers="$enable_sanitizers --enable-leak-sanitizer"
+ fi
+ # TODO: libunbound is broken when built with LSAN/ASAN, let's disable it for now.
+ extra_cflags="--without-rlm_unbound"
+
+ # Temporary hack just to skip and see the result.
+ # memory leak in rlm_{ldap,rest} and problems in perl+llvm
+ rm -rf src/tests/modules/ldap/
+ rm -rf src/tests/modules/rest/
+ else
+ enable_sanitizers=""
+ extra_cflags=""
+ fi
+ CFLAGS="${BUILD_CFLAGS}" ./configure -C \
+ --enable-developer \
+ ${enable_sanitizers} \
+ $CONFIG_OPENSSL \
+ $extra_cflags \
+ --enable-werror \
+ --prefix=$HOME/freeradius \
+ --with-threads=$LIBS_OPTIONAL \
+ --with-udpfromto=$LIBS_OPTIONAL \
+ --with-openssl=$LIBS_OPTIONAL \
+ --with-pcre=$LIBS_OPTIONAL \
+ --enable-reproducible-builds=${REPRODUCIBLE}
+ make -j $(($(nproc) + 1))
+
+ - name: clang scan
+ run: |
+ make -j $(($(nproc) + 1)) scan && [ "$(find build/plist/ -name *.html)" = '' ]
+ if: ${{ matrix.env.CC == 'clang' }}
+
+ - name: "Clang Static Analyzer: Store assets on failure"
+ uses: actions/upload-artifact@v3
+ with:
+ name: clang-scan.tgz
+ path: build/plist/**/*.html
+ if: ${{ matrix.env.CC == 'clang' && failure() }}
+
+ - name: Add OpenResty repository
+ shell: bash
+ run: |
+ wget -O - https://openresty.org/package/pubkey.gpg | sudo apt-key add -
+ echo "deb http://openresty.org/package/ubuntu $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/openresty.list
+
+ sudo apt-get update
+
+ - name: Setup git
+ shell: bash
+ run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
+
+ - name: Install test requisites
+ run: |
+ # Temporarily replace ucf (for config merge) with cp since it's
+ # terribly slow!
+ sudo mv /usr/bin/ucf /usr/bin/ucf.disabled
+ sudo sh -c 'echo "#!/bin/sh" > /usr/bin/ucf'
+ sudo sh -c 'echo "shift && cp -v \$@" >> /usr/bin/ucf'
+ sudo chmod +x /usr/bin/ucf
+
+ sudo apt-get install ${APT_OPTS} \
+ apparmor-utils \
+ ldap-utils \
+ openresty \
+ slapd
+
+ sudo mv -f /usr/bin/ucf.disabled /usr/bin/ucf
+
+ - name: Database dependencies
+ run: |
+ sudo apt-get install ${APT_OPTS} \
+ mariadb-client \
+ postgresql-client
+
+ slapd
+
+ - name: Build certificates for REST tests
+ run: |
+ cp -r raddb/certs raddb/restcerts
+ cd ./raddb/restcerts && make ca && make server
+
+ - name: Setup test databases
+ run: |
+ for i in \
+ postgresql-setup.sh \
+ mysql-setup.sh \
+ openresty-setup.sh \
+ ldap-setup.sh \
+ ldap2-setup.sh; do
+
+ script="./scripts/ci/$i"
+ echo "Calling $i"
+ $script
+ done
+
+ - name: Configure test database access
+ run: |
+ mysql -h mariadb -uroot -e "CREATE USER 'radius'@'%' IDENTIFIED BY 'radpass';"
+ mysql -u root -h mariadb -e "GRANT ALL ON radius.* TO 'radius'; FLUSH PRIVILEGES;"
+
+ - name: Run tests
+ run: |
+ [ -d /opt/openssl ] && export PATH=/opt/openssl/bin:$PATH
+
+ openssl dhparam -out ./raddb/certs/dh -2 128 || \
+ openssl dhparam -out ./raddb/certs/dh -2 512 || \
+ true
+
+ make ci-test
+
+ - name: Show debug logs on failure
+ if: ${{ failure() }}
+ run: |
+ cat src/tests/radius.log || :
+
+ #
+ # If the CI has failed and the branch is ci-debug then start a tmate
+ # session. SSH rendezvous point is emited continuously in the job output.
+ #
+ - name: "Debug: Start tmate"
+ uses: mxschmitt/action-tmate@v3
+ with:
+ limit-access-to-actor: true
+ if: ${{ github.ref == 'refs/heads/ci-debug' && failure() }}
+
+##########################################################################################
+# FREERADIUS CORE DEVELOPERS ONLY
+##########################################################################################
+#
+# Direct push access to the main freeradius-server repo has been disabled in an attempt
+# to keep CI passing reliably.
+#
+# The code below will automatically push to the main repository if a commit passes CI in
+# your fork on a branch that exists in the main repository.
+#
+# The code below will only run if PERSONAL_ACCESS_TOKEN is defined in the repository
+# secrets for your fork of the freeradius-server repo.
+#
+# If the above CI checks pass then we auto-merge into the same branch in the
+# main FR repo (only on push) if the PERSONAL_ACCESS_TOKEN secret is defined, i.e. when
+# the actor claims to be a FreeRADIUS developer with push access.
+#
+# Personal access tokens can be generated via the GitHub website:
+#
+# - Click on the Profile menu (top right)
+# > Settings
+# > Developer settings
+# > Personal access tokens
+# > Generate New Token
+# - Next, add the following settings and scopes:
+# Note: FreeRADIUS CI Push
+# public_repo (checked)
+#
+# This will allow any git operations using this PERSONAL_ACCESS_TOKEN to commit code to any
+# public repository you have access to.
+#
+# As this PERSONAL_ACCESS_TOKEN will only ever be accessible from GitHub actions when they are
+# running from your fork of the FreeRADIUS repo, this shouldn't be a security issue.
+#
+# After generating your PERSONAL_ACCESS_TOKEN you will need to add it as a secret to your
+# repository.
+#
+# - Copy your new token
+# - Click on the Profile menu (top right)
+# > Your repositories
+# - Search for freeradius-server
+# > Click freeradius-server
+# - Click settings in the tabs on the left
+# - Click secrets in the menu items on the left
+# - Click New repository secret
+# - Name: PERSONAL_ACCESS_TOKEN
+# Value: <value you copied>
+# - Click Add secret
+ #
+ # Needed because secrets are not available for evaluation in if conditions
+ # at the job level, so we evaluate the existence of the PERSONAL_ACCESS_TOKEN secret
+ # within a step and export the result instead. We also extract the short
+ # branch name here because it's convenient to do so.
+ #
+ merge-preflight:
+ needs:
+ - ci
+ if: ( github.event_name == 'push' ) && ( github.repository_owner != 'FreeRADIUS' ) && ( github.ref == 'refs/heads/master' || github.ref == 'refs/heads/v3.2.x' )
+ name: "Merge preflight"
+ runs-on: ubuntu-latest
+ steps:
+ - name: "Report whether PERSONAL_ACCESS_TOKEN secret exists"
+ id: merge-preflight
+ run: |
+ [ -z "$PERSONAL_ACCESS_TOKEN" ] || echo "::set-output name=PERSONAL_ACCESS_TOKEN_EXISTS::1"
+ env:
+ PERSONAL_ACCESS_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
+ outputs:
+ PERSONAL_ACCESS_TOKEN_EXISTS: ${{ steps.merge-preflight.outputs.PERSONAL_ACCESS_TOKEN_EXISTS }}
+
+ merge-upstream:
+ needs:
+ - ci
+ - merge-preflight
+ if: needs.merge-preflight.outputs.PERSONAL_ACCESS_TOKEN_EXISTS == '1'
+ runs-on: ubuntu-latest
+ name: "Merge into upstream"
+ steps:
+ - uses: actions/checkout@v3
+ with:
+ fetch-depth: 0
+ lfs: false
+ persist-credentials: false
+ # Note: This also opportunistically updates the developer's branch with commits from
+ # the main repository.
+ # This update may fail if the developer has pushed additional commits since the
+ # workflow started. This is normal, and we ignore the failure.
+ - name: "Merge into upstream dev branch and update local branch"
+ run: |
+ BRANCH=${GITHUB_REF#refs/heads/}
+ git remote add upstream https://$USERNAME:$REPO_KEY@github.com/FreeRADIUS/freeradius-server.git
+ git fetch --no-recurse-submodules upstream +refs/heads/*:refs/remotes/upstream/* +refs/tags/*:refs/tags/upstream/*
+ git checkout --progress --force -B upstream-branch "refs/remotes/upstream/$BRANCH"
+ git merge "$BRANCH" --ff-only
+ git push upstream "upstream-branch:$BRANCH"
+ git push origin "$BRANCH" || true
+ env:
+ USERNAME: ${{ github.actor }}
+ REPO_KEY: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..d0b46d2
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,74 @@
+*~
+*.o
+*.a
+*.buildinfo
+*.changes
+*.lo
+*.loT
+*.la
+*.so
+*.lai
+*.bz2
+*.gz
+*.sig
+*.orig
+*.rej
+.libs
+.depends
+*.log
+*.substvars
+*-stamp
+*.swp
+*.cache
+*.dist
+*.dylib
+*.rej
+*.orig
+*.dSYM
+*.patch
+.pc
+
+# Editor projects
+*.kdev4
+*.cproject
+*.project
+*.bbprojectd
+
+# Exuberant ctags
+tags
+
+# Local icon files
+icon.png
+
+# OS specific cruft
+.DS_Store
+
+# Certificates and signing requests
+*.pem
+*.der
+*.csr
+*.key
+
+# Autoconf and libtool output
+build
+config.status
+*confdefs.h
+*conftest*
+*confcache
+Make.inc
+libtool
+autom4te.cache
+aclocal.m4
+config.guess
+config.report
+config.sub
+config.h
+src/main/radattr
+src/modules/lib/
+warnings.txt
+
+# Analyzer output
+/*.plist
+
+# rpm packages
+rpmbuild/
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..e35729f
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,95 @@
+language: c
+compiler:
+ - clang
+ - gcc
+sudo: false
+cache:
+ apt: true
+env:
+ global:
+ - PANIC_ACTION="gdb -batch -x raddb/panic.gdb %e %p 1>&0 2>&0"
+ - secure: "H+uQeyOgsIyXtIPPG2VzAG8S/8KYGHlHaWhdiNuz1LM3SMcEKoPqG6o/P+HO8HVvYnA6nelyGuEryV90UfuwGY9YC6A/pqPQvx/gXSso63Zt66XSaiZjulCSm9OV8EB3wyWF7VSQ/ZHcn+L01hIlsQXTqLprMaC33cM0FYPr9fY="
+ matrix:
+ - DO_BUILD=yes LIBS_OPTIONAL=no LIBS_SHARED=yes REPRODUCIBLE=no BUILD_CFLAGS="-DWITH_EVAL_DEBUG"
+ - DO_BUILD=yes LIBS_OPTIONAL=yes LIBS_SHARED=yes REPRODUCIBLE=no BUILD_CFLAGS="-DWITH_EVAL_DEBUG"
+ - DO_BUILD=yes LIBS_OPTIONAL=yes LIBS_SHARED=yes REPRODUCIBLE=yes BUILD_CFLAGS="-DWITH_EVAL_DEBUG"
+ - DO_BUILD=yes LIBS_OPTIONAL=yes LIBS_SHARED=yes REPRODUCIBLE=no BUILD_CFLAGS="-DWITH_EVAL_DEBUG -O2 -g3"
+ - DO_BUILD=no
+addons:
+ coverity_scan:
+ project:
+ name: FreeRADIUS/freeradius-server
+ version: v3.2.x
+ description: The FreeRADIUS server project
+ notification_email: freeradius-devel@lists.freeradius.org
+ build_command_prepend: ./configure
+ build_command: make
+ branch_pattern: coverity_scan
+ apt:
+ config:
+ retries: true
+ sources:
+ - couchbase-precise
+ packages:
+ - autoconf
+ - build-essential
+ - debhelper
+ - devscripts
+ - dh-make
+ - doxygen
+ - fakeroot
+ - gdb
+ - graphviz
+ - lintian
+ - pbuilder
+ - python-dev
+ - python3-dev
+ - quilt
+ - libruby
+ - ruby-dev
+ - libcollectdclient-dev
+ - firebird-dev
+ - freetds-dev
+ - libcap-dev
+ - libcouchbase2-libevent
+ - libcouchbase-dev
+ - libcurl4-openssl-dev
+ - libgdbm-dev
+ - libhiredis-dev
+ - libidn11-dev
+ - libiodbc2-dev libiodbc2
+ - libjson0
+ - libjson0-dev
+ - libkrb5-dev
+ - libldap2-dev
+ - libmemcached-dev
+ - libmysqlclient-dev
+ - libpam0g-dev
+ - libpcap-dev
+ - libpcre3-dev
+ - libperl-dev
+ - libpq-dev
+ - libreadline-dev
+ - libsnmp-dev
+ - libssl-dev
+ - libtalloc-dev
+ - libtalloc2-dbg
+ - libunbound-dev
+ - libwbclient-dev
+ - libykclient-dev
+ - libyubikey-dev
+before_install:
+ - $CC --version
+before_script:
+# Configure the server
+ - if [ "${DO_BUILD}" = 'yes' ]; then CFLAGS="${BUILD_CFLAGS}" ./configure -C --enable-werror --prefix=$HOME/freeradius --with-shared-libs=$LIBS_SHARED --with-threads=$LIBS_OPTIONAL --with-udpfromto=$LIBS_OPTIONAL --with-openssl=$LIBS_OPTIONAL --with-pcre=$LIBS_OPTIONAL --enable-reproducible-builds=${REPRODUCIBLE}; fi
+ - if [ "${DO_BUILD}" = 'no' ]; then ./configure -C --without-modules; fi
+# Build the server
+ - if [ "${DO_BUILD}" = 'yes' ]; then make -j8; fi
+# Run CLANG analyzer if we're building with CLANG
+ - if [ "${DO_BUILD}" = 'yes' -a "${COVERITY_SCAN_BRANCH}" != 1 -a ${CC} = 'clang' ]; then make -j8 scan && [ "$(find build/plist/ -name *.html)" = '' ]; fi
+script:
+ - if [ "${DO_BUILD}" = 'yes' -a "${COVERITY_SCAN_BRANCH}" != 1 ]; then make ci-test; fi
+# - if [ "${DO_BUILD}" = 'no' ]; then make deb; fi
+# Build the doxygen documentation
+ - if [ "${DO_BUILD}" = 'no' ]; then cd doc/source; doxygen 3>&1 1>&2 2>&3 | grep -iv '^warning:' | tee doxygen_stderr.log && [ ! -n "$(cat doxygen_stderr.log)" ]; fi
diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json
new file mode 100644
index 0000000..4ae342a
--- /dev/null
+++ b/.vscode/c_cpp_properties.json
@@ -0,0 +1,28 @@
+{
+ "configurations": [
+ {
+ "name": "Linux",
+ "includePath": [
+ "/usr/include/**",
+ "${workspaceFolder}/src/**"
+ ],
+ "defines": [],
+ "compilerPath": "/usr/bin/clang",
+ "cStandard": "c11",
+ "cppStandard": "c++14",
+ "intelliSenseMode": "linux-clang-x64"
+ },
+ {
+ "name": "Mac",
+ "includePath": [
+ "${workspaceFolder}/src/**"
+ ],
+ "defines": [],
+ "compilerPath": "/usr/bin/clang",
+ "cStandard": "c11",
+ "cppStandard": "c++14",
+ "intelliSenseMode": "linux-clang-x64"
+ }
+ ],
+ "version": 4
+}
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..a8c6e49
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,52 @@
+{
+ // Use IntelliSense to learn about possible attributes.
+ // Hover to view descriptions of existing attributes.
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "type": "lldb",
+ "request": "launch",
+ "name": "Debug (lldb)",
+ "program": "${workspaceFolder}/build/bin/local/radiusd",
+ "args": [
+ "-X",
+ "-D",
+ "${workspaceFolder}/share",
+ "-d",
+ "${workspaceFolder}/raddb"
+ ],
+ "cwd": "${workspaceFolder}",
+ "env": {
+ "FR_LIBRARY_PATH": "${workspaceFolder}/build/lib/local/.libs",
+ "DEBUGGER_ATTACHED": "yes"
+ }
+ },
+ {
+ "type": "cppdbg",
+ "request": "launch",
+ "name": "Debug (gdb)",
+ "program": "${workspaceFolder}/build/bin/local/radiusd",
+ "args": [
+ "-X",
+ "-D",
+ "${workspaceFolder}/share",
+ "-d",
+ "${workspaceFolder}/raddb"
+ ],
+ "cwd": "${workspaceFolder}",
+ "environment": [
+ { "name": "FR_LIBRARY_PATH", "value": "${workspaceFolder}/build/lib/local/.libs" },
+ { "name": "LD_LIBRARY_PATH", "value": "${workspaceFolder}/build/lib/local/.libs" },
+ { "name": "DEBUGGER_ATTACHED", "value": "yes" }
+ ],
+ "MIMode": "gdb",
+ "setupCommands": [
+ {
+ "description": "Set solib",
+ "text": "set solib-search-path ${workspaceFolder}"
+ }
+ ]
+ }
+ ]
+}
diff --git a/CONTRIBUTING b/CONTRIBUTING
new file mode 100644
index 0000000..28a0d87
--- /dev/null
+++ b/CONTRIBUTING
@@ -0,0 +1,109 @@
+0.INTRODUCTION
+
+ The FreeRADIUS project wouldn't exist without contributions from a significant number of developers.
+
+ We greatly value all comments, defect reports, patches/pull-requests, but must balance individual
+ contributor's desires and practices against what's required for the project to operate efficiently.
+
+ This document describes best practices when interacting with members of the FreeRADIUS project team
+ via GitHub. If you follow these guidelines, it is very likely that your question, bug report or pull
+ request will be acted on, and in a timely manor.
+
+ If you choose to ignore these guidelines our response will be a link to this document.
+
+
+1.GITHUB ISSUE TRACKER
+
+ The GitHub issue tracker is for non-security related defect reports, feature requests, and
+ pull-requests ONLY.
+
+ It is not for support requests or questions regarding configuration/operation of the server, they
+ belong on the users mailing list:
+
+ https://freeradius.org/support/
+
+ Raising support requests or questions as issues will result in them being closed and locked. If you
+ continue to raise these questions as issues you will be banned from the FreeRADIUS project's GitHub
+ repositories.
+
+ Security issues should be reported to security@freeradius.org, especially if they can be remotely
+ exploited. This ensures that patches can be developed before the exploit is made public.
+
+
+2.BEFORE REPORTING A DEFECT
+
+ Verify it's still present in the Git HEAD. Checkout the appropriate branch for the version of the
+ server you're working with as listed here (http://doc.freeradius.org), build the server, and attempt
+ to reproduce your issue.
+
+ The ChangeLog (https://github.com/FreeRADIUS/freeradius-server/blob/v3.2.x/doc/ChangeLog) for the
+ current stable branch may also be used to determine if your issue has already been addressed.
+ The ChangeLog is updated as fixes are made to the server code, and usually reflects the state of the
+ Git HEAD.
+
+ Do not report non-security defects for EOL branches (as listed on doc.freeradius.org), they will be
+ closed and locked.
+
+
+3.CONTENTS OF A DEFECT REPORT
+
+ See doc/bugs (https://github.com/FreeRADIUS/freeradius-server/blob/v3.2.x/doc/bugs) for information
+ on what to include, and how to obtain it.
+
+ When logging bug reports using the GitHub issue tracker, pay attention to formatting. You should
+ ensure any log output is surrounded by two sets of tripple backticks (```). If you don't do this
+ Github will automatically link your issue to other pre-existing issues when it encounters a #<num>
+ string.
+
+
+4.PULL REQUESTS AND CODING STANDARDS
+
+ If you're developing a new feature, module, or writing large amounts of code to fix a defect, contact
+ a member of the FreeRADIUS development team first. For simpler one or two line fixes, go ahead and
+ open a pull-request immediately.
+
+ The dev team can be contacted via the devel mailing list (https://freeradius.org/support/),
+ or via GitHub by using the GitHub issue tracker.
+
+ Contacting the dev team gives us the opportunity to offer feedback. We may have a solution to your
+ problem that doesn't require additional code, or may have ideas as to how your problem can be solved
+ in a way that will better fit with the long-term vision for the server.
+
+ Once you've got the go ahead, read through the coding standards document:
+
+ https://wiki.freeradius.org/contributing/coding-standards
+
+ If you're creating a new module you may wish to read the module creation guide:
+
+ https://wiki.freeradius.org/contributing/Modules3
+
+ You may also wish to utilise the doxygen site to review code documentation:
+
+ http://doc.freeradius.org
+
+ The doxygen site contains the complete reference of all API functions with doxygen headers, as well
+ as structs, and callback declarations. doc.freeradius.org is updated within one minute of each commit
+ to the master branch of the main freeradius-server repo.
+
+ Finally, this file was written to be displayed automatically on the GitHub issue tracker, so
+ Git/GitHub knowledge is assumed. If you're wondering what the heck a pull-request is, this
+ document may be of some use:
+
+ https://wiki.freeradius.org/contributing/GitHub
+
+
+5.CONTINUOUS INTEGRATION TESTS
+
+ If possible include test cases in your pull-requests.
+
+ There are currently three test frameworks for different elements of the server:
+
+ Unit tests - src/tests/unit/*.txt - Tests for conditions and protocol encoders/decoders.
+ Module tests - src/tests/modules/<module name> - Tests for module functionality.
+ Unlang tests - src/tests/unlang/<test series> - Tests for unlang keywords and functions.
+
+ See README.* docs in the directories above for basic information on writing test cases. The easiest
+ way to write new tests is to use the existing tests as examples.
+
+ Tests are run via a GitHub Actions workflow for each pull-request, and on every commit by a develope
+ with repository access.
diff --git a/COPYRIGHT b/COPYRIGHT
new file mode 100644
index 0000000..73f2555
--- /dev/null
+++ b/COPYRIGHT
@@ -0,0 +1,95 @@
+1. COPYRIGHT
+
+Unless otherwise mentioned, the copyrights described in section 4,
+below, apply to all files in this distribution.
+
+2. INDIVIDUAL DIRECTORIES
+
+2.1 doc/rfc/
+
+Most of the files in this directory are copyrighted by the Internet
+Society, Inc. See the contents of the files for details.
+
+2.2 src/lib/
+
+Copyright for files in this directory is held by the contributors.
+See the contents of the files for details
+
+2.2.1 LICENSE
+
+The license for all files in the src/lib directory is the GNU LGPL
+version 2, which is included with this program in the file
+src/lib/LICENSE.
+
+3. ALL OTHER FILES
+
+Copyright for files in this directory is held by the contributors.
+See the contents of the files for details. Files without explicit
+copyright notices are copyright The FreeRADIUS Server Project. See
+section 4.2 for more information.
+
+3.1 LICENSE
+
+The license for all other source code and documentation except the
+files in src/lib directory is the GNU GPL version 2, which is included
+with this program in the LICENSE file in this directory.
+
+3.2 LIST OF COPYRIGHT HOLDERS
+
+Portions of the source code and documentation included here are
+copyright by one or more of the following organizations and
+individuals. This list is not exhaustive. Consult the individual
+files for more detailed copyright statements.
+
+
+Copyright (C) 1999-2021 The FreeRADIUS Server Project
+
+Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Alan DeKok
+<aland@deployingradius.com>
+
+Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005 Free
+Software Foundation, Inc.
+
+Copyright (C) 2011-2015 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+
+Copyright (C) 2012-2018 Matthew Newton <matthew-git@newtoncomputing.co.uk>
+
+Copyright (C) 2003, 2004, 2005 Kostas Kalevras <kkalev@noc.ntua.gr>
+
+Copyright (C) 2004 Cladju Consulting, Inc.
+
+Copyright (C) 2001, 2002, 2003, 2004, 2005 Google, Inc.
+
+Copyright (C) 2003, 2004 Michael Richardson <mcr@sandelman.ottawa.on.ca>
+
+Copyright (C) 2002, 2003, 2004 Novell, Inc.
+
+Copyright (C) 2002 Miguel A.L. Paraz <mparaz@mparaz.com>
+
+Copyright (C) 2002 Simon Ekstrand <simon@routemeister.net>
+
+Copyright (C) 2001 Chad Miller <cmiller@surfsouth.com>
+
+Copyright (C) 2001 hereUare Communications, Inc.
+
+Copyright (C) 2000 Jochen Friedrich <jochen@scram.de>
+
+Copyright (C) 2000, 2002 Miquel van Smoorenburg
+
+Copyright (C) 2000 Jeff Carneal <jeff@apex.net>
+
+Copyright (C) 2000 Alan Curry <pacman@world.std.com>
+
+Copyright (C) 2000 David Kerry <davidk@snti.com>
+
+Copyright (C) 2000 Dmitri Ageev <d_ageev@ortcc.ru>
+
+Copyright (C) 2000 Nathan Neulinger <nneul@umr.edu>
+
+Copyright (C) 2000 Mike Machado <mike@innercite.com>
+
+Copyright (C) 2000, 2001 Chad Miller <cmiller@surfsouth.com>
+
+Copyright (C) 1997, 1998, 1999 Cistron Internet Services B.V.
+
+Copyright (C) 1999 Kunihiro Ishiguro <kunihiro@zebra.org>
diff --git a/CREDITS b/CREDITS
new file mode 100644
index 0000000..2dcb96b
--- /dev/null
+++ b/CREDITS
@@ -0,0 +1,2 @@
+Please see:
+ https://wiki.freeradius.org/project/Acknowledgements
diff --git a/INSTALL.rst b/INSTALL.rst
new file mode 100644
index 0000000..6edb34d
--- /dev/null
+++ b/INSTALL.rst
@@ -0,0 +1,169 @@
+Installation
+============
+
+1. INTRODUCTION
+---------------
+
+Ignore the installation instructions in this file if you have a
+pre-installed binary package. When upgrading from older versions of
+FreeRADIUS, you should read ALL of this file, especially the section
+on "UPGRADING" below which gives information on how to update your
+configuration.
+
+Whether you are installing from source or a pre-built binary
+package, you should read the section below "RUNNING THE SERVER".
+
+
+2. SIMPLE INSTALLATION
+----------------------
+
+If you do not need to modify the default configuration, then take
+the following steps to build and install the server::
+
+ $ ./configure
+ $ make
+ $ make install
+
+
+3. CUSTOM INSTALLATION
+----------------------
+
+FreeRADIUS has autoconf support. This means you have to run
+``./configure``, and then run make. To see which configuration options
+are supported, run ``./configure --help``, and read it's output. The
+following list is a selection from the available flags::
+
+ --enable-shared[=PKGS] build shared libraries [default=yes]
+ --enable-static[=PKGS] build static libraries [default=yes]
+ --with-logdir=DIR Directory for logfiles [LOCALSTATEDIR/log]
+ --with-radacctdir=PATH Directory for detail files [LOGDIR/radacct]
+ --with-raddbdir=DIR Directory for config files [SYSCONFDIR/raddb]
+ --with-threads Use threads, if available. (default=yes)
+ --with-snmp Compile in SNMP support. (default=yes)
+ --with-dhcp Compile in DHCP support. (default=yes)
+ --with-experimental-modules Use experimental and unstable modules.
+ (default=no)
+ --enable-developer Turns on super-duper-extra-compile-warnings
+ when using gcc, as well as experimental modules.
+
+The ``make install`` stage will install the binaries, the 'man' pages,
+and MAY install the configuration files. If you have not installed a
+RADIUS server before, then the configuration files for FreeRADIUS will
+be installed. If you already have a RADIUS server installed, then
+
+**FreeRADIUS WILL NOT over-write your current configuration.**
+
+The ``make install`` process will warn you about the files it could
+not install.
+
+If you see a warning message about files that could not be
+installed, then you MUST ensure that the new server is using the new
+configuration files, and not the old configuration files. The initial
+output from running in debugging mode (``radiusd -X``) will tell you which
+configuration files are being used. See UPGRADING above for
+information about upgrading from older versions. There MAY be changes
+in the dictionary files which are REQUIRED for a new version of the
+software. These files will NOT be installed over your current
+configuration, so you MUST verify and install any problem files by
+hand, for example using ``diff(1)`` to check for changes.
+
+It is EXTREMELY helpful to read the output of both ``./configure``,
+``make``, and ``make install``. If a particular module you expected to be
+installed was not installed, then the output of the
+``./configure; make; make install`` sequence will tell you why that module
+was not installed. Please do NOT post questions to the FreeRADIUS
+users list without first carefully reading the output of this process.
+
+
+4. UPGRADING
+------------
+
+The installation process will not over-write your existing
+configuration files. It will, however, warn you about the files it
+did not install.
+
+For users upgrading from any older version to 3.0, it is *NOT*
+possible to use the older configuration as-is. However, the version
+2.x configuration is largely compatible, so upgrading the
+configuration should not be too difficult. For details on what has
+changed, see ``raddb/README.rst``.
+
+We STRONGLY recommend that 3.0 be installed in a different location
+than any existing 1.x or 2.x installation. Any local policies can
+then be migrated gradually to the new 3.0 configuration. The number
+of differences in the new configuration mean that is is both simpler
+and safer to migrate your configurations rather than to try and just
+get the old configuration to work.
+
+
+5. RUNNING THE SERVER
+---------------------
+
+If the server builds and installs, but doesn't run correctly, then
+you should use debugging mode (radiusd -X) to figure out the problem.
+
+This is your BEST HOPE for understanding the problem. Read ALL of
+the messages which are printed to the screen, the answer to your
+problem will often be in a warning or error message.
+
+We really can't emphasize that last sentence enough. Configuring a
+RADIUS server for complex local authentication isn't a trivial task.
+Your ONLY method for debugging it is to read the debug messages, where
+the server will tell you exactly what it's doing, and why. You should
+then compare its behaviour to what you intended, and edit the
+configuration files as appropriate.
+
+If you don't use debugging mode, and ask questions on the mailing
+list, then the responses will all tell you to use debugging mode. The
+server prints out a lot of information in this mode, including
+suggestions for fixes to common problems. Look especially for
+"WARNING" in the output, and read the related messages.
+
+Since the main developers of FreeRADIUS use debugging mode to track
+down their configuration problems with the server, it's a good idea
+for you to use it, too. If you don't, there is little hope for you to
+solve ANY configuration problem related to the server.
+
+To start the server in debugging mode, do::
+
+ $ radiusd -X
+
+You should see a lot of text printed on the screen as it starts up.
+If you don't, or if you see error messages, please read the FAQ:
+
+ http://www.freeradius.org/faq/
+
+If the server says "Ready to process requests.", then it is running
+properly. From another shell (or another window), type::
+
+ $ radtest test test localhost 0 testing123
+
+You should see the server print out more messages as it receives the
+request, and responds to it. The 'radtest' program should receive the
+response within a few seconds. It doesn't matter if the
+authentication request is accepted or rejected, what matters is that
+the server received the request, and responded to it.
+
+You can now edit the configuration files for your local system. You
+will usually want to start with ``sites-enabled/default``. To set
+which NASes (clients) can communicate with this server,
+edit ``clients.conf``.
+Please read the configuration files carefully, as many configuration
+options are only documented in comments in the file.
+
+Note that is is HIGHLY recommended that you use some sort of version
+control system to manage your configuration, such as git or
+Subversion. You should then make small changes to the configuration,
+checking in and testing as you go. When a config change causes the
+server to stop working, you will be able to easily step back and find
+out what update broke the configuraiton.
+
+Configuring and running the server MAY be complicated. Many modules
+have ``man`` pages. See ``man rlm_pap``, or ``man rlm_*`` for
+information.
+Please read the documentation in the doc/ directory. The comments in
+the configuration files also contain a lot of documentation.
+
+If you have any additional issues, the FAQ is also a good place to
+start.
+
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..3912109
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 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.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, 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 or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+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 give any other recipients of the Program a copy of this License
+along with the Program.
+
+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 Program or any portion
+of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+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 Program, 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 Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) 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; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, 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 executable. However, as a
+special exception, the source code 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.
+
+If distribution of executable or 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 counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program 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.
+
+ 5. 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 Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program 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 to
+this License.
+
+ 7. 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 Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program 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 Program.
+
+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.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program 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.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the 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 Program
+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 Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, 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
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "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 PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. 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 PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), 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 Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. 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 program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/Make.inc.in b/Make.inc.in
new file mode 100644
index 0000000..05f8277
--- /dev/null
+++ b/Make.inc.in
@@ -0,0 +1,186 @@
+# -*- makefile -*-
+# Make.inc.in
+#
+# Version: $Id$
+#
+
+# Location of files.
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+sysconfdir = @sysconfdir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+bindir = @bindir@
+sbindir = @sbindir@
+docdir = @docdir@
+mandir = @mandir@
+datadir = @datadir@
+dictdir = @dictdir@
+logdir = @logdir@
+includedir = @includedir@
+
+#
+# In some systems, we don't want to over-write ANY configuration.
+# So we do:
+#
+# $./configure
+# $ make
+# $ make -Draddbdir=/tmp/garbage install
+#
+# and all of the configuration files go into /tmp/garbage
+#
+ifeq "${raddbdir}" ""
+raddbdir = @raddbdir@
+endif
+modconfdir = @modconfdir@
+radacctdir = @radacctdir@
+top_builddir = @abs_top_builddir@
+top_build_prefix=@abs_top_builddir@/
+top_srcdir = @abs_top_srcdir@
+datarootdir = @datarootdir@
+
+MAKE = @MAKE@
+
+# Makeflags set within the makefile appear to be additive and override
+# flags set on the command line and the environmental variables
+MAKEFLAGS = @FR_MAKEFLAGS@
+
+CC = @CC@
+RANLIB = @RANLIB@
+INCLUDE = -I. -Isrc \
+ -include src/freeradius-devel/autoconf.h \
+ -include src/freeradius-devel/build.h \
+ -include src/freeradius-devel/features.h \
+ -include src/freeradius-devel/radpaths.h
+CFLAGS = $(INCLUDE) -fno-strict-aliasing @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+LIBPREFIX = @LIBPREFIX@
+EXEEXT = @EXEEXT@
+
+LIBTOOL = JLIBTOOL
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+INSTALL = ${top_builddir}/install-sh -c
+INSTALL_PROGRAM = ${INSTALL}
+INSTALL_DATA = ${INSTALL} -m 644
+INSTALL_SCRIPT = ${INSTALL_PROGRAM}
+INSTALLSTRIP = @INSTALLSTRIP@
+
+#
+# Linker arguments for libraries searched for by the main
+# configure script.
+#
+TALLOC_LIBS = @TALLOC_LIBS@
+TALLOC_LDFLAGS = @TALLOC_LDFLAGS@
+
+OPENSSL_LIBS = @OPENSSL_LIBS@
+OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@
+OPENSSL_CPPFLAGS = @OPENSSL_CPPFLAGS@
+
+PCAP_LIBS = @PCAP_LIBS@
+PCAP_LDFLAGS = @PCAP_LDFLAGS@
+
+COLLECTDC_LIBS = @COLLECTDC_LIBS@
+COLLECTDC_LDFLAGS = @COLLECTDC_LDFLAGS@
+
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
+SYSTEMD_LDFLAGS = @SYSTEMD_LDFLAGS@
+
+LCRYPT = @CRYPTLIB@
+
+#
+# OpenSSL libs (if used) must be linked everywhere in order for
+# the server to work properly on on all platforms.
+#
+LIBS = $(OPENSSL_LIBS) $(TALLOC_LIBS) @LIBS@
+LDFLAGS = $(OPENSSL_LDFLAGS) $(TALLOC_LDFLAGS) @LDFLAGS@
+
+LOGDIR = ${logdir}
+RADDBDIR = ${raddbdir}
+RUNDIR = ${localstatedir}/run/radiusd
+SBINDIR = ${sbindir}
+RADIR = ${radacctdir}
+LIBRADIUS = $(top_builddir)/src/lib/$(LIBPREFIX)freeradius-radius.la $(TALLOC_LIBS)
+
+USE_SHARED_LIBS = @USE_SHARED_LIBS@
+bm_shared_libs = @USE_SHARED_LIBS@
+USE_STATIC_LIBS = @USE_STATIC_LIBS@
+bm_static_libs = @USE_STATIC_LIBS@
+
+STATIC_MODULES = @STATIC_MODULES@
+LIBREADLINE = @LIBREADLINE@
+
+WITH_DHCP = @WITH_DHCP@
+
+#
+# Version to use for packaging and other Make related things
+#
+RADIUSD_VERSION_STRING = @RADIUSD_VERSION_STRING@
+
+#
+# This allows dlopen to do runtime checks for version mismatches
+# between what it was originally linked with, and the library it's
+# actually loading.
+#
+MODULES = @MODULES@
+HOSTINFO = @HOSTINFO@
+
+#
+# If the system has OpenSSL, use it's version of MD4/MD5/SHA1, instead of
+# using ours.
+#
+# We don't use OpenSSL SHA1 by default because src/modules/rlm_eap/libeap/fips186prf.c
+# needs access to the SHA internals.
+#
+ifeq "$(WITH_OPENSSL)" "yes"
+CFLAGS += -DWITH_OPENSSL_MD4 -DWITH_OPENSSL_MD5
+CPPFLAGS := "$(OPENSSL_CPPFLAGS) $(CPPFLAGS)"
+endif
+
+OPENSSL_LIBS = @OPENSSL_LIBS@
+
+ifneq ($(WITH_OPENSSL_MD5),)
+LIBRADIUS_WITH_OPENSSL = 1
+CFLAGS += -DWITH_OPENSSL_MD5
+endif
+
+ifneq ($(WITH_OPENSSL_SHA1),)
+LIBRADIUS_WITH_OPENSSL = 1
+CFLAGS += -DWITH_OPENSSL_SHA1
+endif
+
+ifneq ($(LIBRADIUS_WITH_OPENSSL),)
+ifeq ($(OPENSSL_LIBS),)
+$(error OPENSSL_LIBS must be define in order to use WITH_OPENSSL_*)
+else
+LIBRADIUS += $(OPENSSL_LIBS)
+endif
+endif
+
+# Path to clang, setting this enables the 'scan.*' build targets
+# which perform static analysis on various server components.
+ANALYZE.c := @clang_path@
+
+#
+# With shared libs, the test binaries are in a different place
+# AND the method we use to run those binaries changes.
+#
+ifeq "$(USE_SHARED_LIBS)" "yes"
+ TESTBINDIR = ./$(BUILD_DIR)/bin/local
+ TESTBIN = FR_LIBRARY_PATH=./build/lib/.libs $(JLIBTOOL) --quiet --mode=execute $(TESTBINDIR)
+else
+ TESTBINDIR = ./$(BUILD_DIR)/bin
+ TESTBIN = ./$(BUILD_DIR)/bin
+endif
+
+
+#
+# For creating documentation via doc/all.mk
+#
+ASCIIDOCTOR := @ASCIIDOCTOR@
+PANDOC := @PANDOC@
+PANDOC_ENGINE := @PANDOC_ENGINE@
+DOXYGEN := @DOXYGEN@
+GRAPHVIZ_DOT := @GRAPHVIZ_DOT@
+ANTORA := @ANTORA@
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..60e183c
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,401 @@
+#
+# Makefile
+#
+# NOTE: This top-level Makefile must not
+# use GNU-make extensions. The lower ones can.
+#
+# Version: $Id$
+#
+
+#
+# If we didn't call ./configure just define the version.
+#
+RADIUSD_VERSION_STRING := $(shell cat VERSION)
+
+#
+# The default rule is "all".
+#
+all:
+
+#
+# Catch people who try to use BSD make
+#
+ifeq "0" "1"
+.error GNU Make is required to build FreeRADIUS
+endif
+
+#
+# We require Make.inc, UNLESS the target is "make deb"
+#
+# Since "make deb" re-runs configure... there's no point in
+# requiring the developer to run configure *before* making
+# the debian packages.
+#
+ifneq "$(MAKECMDGOALS)" "deb"
+ifneq "$(MAKECMDGOALS)" "rpm"
+ifeq "$(findstring docker,$(MAKECMDGOALS))" ""
+ifeq "$(findstring crossbuild,$(MAKECMDGOALS))" ""
+$(if $(wildcard Make.inc),,$(error Missing 'Make.inc' Run './configure [options]' and retry))
+
+include Make.inc
+endif
+endif
+endif
+endif
+
+MFLAGS += --no-print-directory
+
+#
+# The version of GNU Make is too old, don't use it (.FEATURES
+# variable was added in 3.81)
+#
+ifndef .FEATURES
+$(error The build system requires GNU Make 3.81 or later.)
+endif
+
+export DESTDIR := $(R)
+
+#
+# And over-ride all of the other magic.
+#
+ifneq "$(MAKECMDGOALS)" "deb"
+ifneq "$(MAKECMDGOALS)" "rpm"
+ifeq "$(findstring docker,$(MAKECMDGOALS))" ""
+ifeq "$(findstring crossbuild,$(MAKECMDGOALS))" ""
+include scripts/boiler.mk
+endif
+endif
+endif
+endif
+
+#
+# To work around OpenSSL issues within CI.
+#
+.PHONY:
+raddb/test.conf:
+ @echo 'security {' >> $@
+ @echo ' allow_vulnerable_openssl = yes' >> $@
+ @echo '}' >> $@
+ @echo '$$INCLUDE radiusd.conf' >> $@
+
+#
+# Run "radiusd -C", looking for errors.
+#
+# Only redirect STDOUT, which should contain details of why the test failed.
+# Don't molest STDERR as this may be used to receive output from a debugger.
+#
+$(BUILD_DIR)/tests/radiusd-c: raddb/test.conf ${BUILD_DIR}/bin/radiusd | build.raddb
+ ${Q}$(MAKE) -C raddb/certs
+ ${Q}printf "radiusd -C... "
+ ${Q}if ! $(TESTBIN)/radiusd -XCMd ./raddb -D ./share -n test > $(BUILD_DIR)/tests/radiusd.config.log; then \
+ rm -f raddb/test.conf; \
+ cat $(BUILD_DIR)/tests/radiusd.config.log; \
+ echo "fail"; \
+ exit 1; \
+ fi
+ ${Q}rm -f raddb/test.conf
+ ${Q}echo "ok"
+ ${Q}touch $@
+
+test: ${BUILD_DIR}/bin/radiusd ${BUILD_DIR}/bin/radclient tests.unit tests.xlat tests.keywords tests.modules tests.auth test.sql_nas_table $(BUILD_DIR)/tests/radiusd-c | build.raddb
+ ${Q}$(MAKE) -C src/tests tests
+
+#
+# Tests specifically for CI. We do a LOT more than just
+# the above tests
+#
+ci-test: raddb/test.conf test
+ ${Q}$(TESTBIN)/radiusd -xxxv -n test
+ ${Q}rm -f raddb/test.conf
+ ${Q}$(MAKE) install
+ ${Q}perl -p -i -e 's/allow_vulnerable_openssl = no/allow_vulnerable_openssl = yes/' ${raddbdir}/radiusd.conf
+ ${Q}sh ${HOME}/freeradius/etc/raddb/certs
+ ${Q}${sbindir}/radiusd -XC
+
+#
+# The $(R) is a magic variable not defined anywhere in this source.
+# It's purpose is to allow an admin to create an installation 'tar'
+# file *without* actually installing it. e.g.:
+#
+# $ R=/home/root/tmp make install
+# $ cd /home/root/tmp
+# $ tar -cf ~/freeradius-package.tar *
+#
+# The 'tar' file can then be un-tar'd on any similar machine. It's a
+# cheap way of creating packages, without using a package manager.
+# Many of the platform-specific packaging tools use the $(R) variable
+# when creating their packages.
+#
+# For compatibility with typical GNU packages (e.g. as seen in libltdl),
+# we make sure DESTDIR is defined.
+#
+export DESTDIR := $(R)
+
+DICTIONARIES := $(wildcard share/dictionary*)
+install.share: $(addprefix $(R)$(dictdir)/,$(notdir $(DICTIONARIES)))
+
+.PHONY: dictionary.format
+dictionary.format: $(DICTIONARIES)
+ ${Q}./share/format.pl $(DICTIONARIES)
+
+$(R)$(dictdir)/%: share/%
+ @echo INSTALL $(notdir $<)
+ ${Q}$(INSTALL) -m 644 $< $@
+
+MANFILES := $(wildcard man/man*/*.?)
+MANDIR := $(wildcard man/man*)
+install.man: $(subst man/,$(R)$(mandir)/,$(MANFILES))
+
+$(MANDIR):
+ ${Q}echo INSTALL $(patsubst $(R)$(mandir)/%,man/%,$@)
+ ${Q}$(INSTALL) -d -m 755 $@
+
+$(R)$(mandir)/%: man/% | $(dir $@)
+ ${Q}echo INSTALL $(notdir $<)
+ ${Q}sed -e "s,/etc/raddb,$(raddbdir),g" \
+ -e "s,/usr/local/share,$(datarootdir),g" \
+ $< > $<.subst
+ ${Q}$(INSTALL) -m 644 $<.subst $@
+ ${Q}rm $<.subst
+
+#
+# Don't install rlm_test
+#
+ALL_INSTALL := $(patsubst %rlm_test.la,,$(ALL_INSTALL))
+
+install: install.share install.man
+ ${Q}$(INSTALL) -d -m 700 $(R)$(logdir)
+ ${Q}$(INSTALL) -d -m 700 $(R)$(radacctdir)
+
+ifneq ($(RADMIN),)
+ifneq ($(RGROUP),)
+.PHONY: install-chown
+install-chown:
+ chown -R $(RADMIN) $(R)$(raddbdir)
+ chgrp -R $(RGROUP) $(R)$(raddbdir)
+ chmod u=rwx,g=rx,o= `find $(R)$(raddbdir) -type d -print`
+ chmod u=rw,g=r,o= `find $(R)$(raddbdir) -type f -print`
+ chown -R $(RADMIN) $(R)$(logdir)
+ chgrp -R $(RGROUP) $(R)$(logdir)
+ find $(R)$(logdir) -type d -exec chmod u=rwx,g=rwx,o= {} \;
+ find $(R)$(logdir) -type d -exec chmod g+s {} \;
+ find $(R)$(logdir) -type f -exec chmod u=rw,g=rw,o= {} \;
+ chown -R $(RADMIN) $(R)$(RUNDIR)
+ chgrp -R $(RGROUP) $(R)$(RUNDIR)
+ find $(R)$(RUNDIR) -type d -exec chmod u=rwx,g=rwx,o= {} \;
+ find $(R)$(RUNDIR) -type d -exec chmod g+s {} \;
+ find $(R)$(RUNDIR) -type f -exec chmod u=rw,g=rw,o= {} \;
+endif
+endif
+
+distclean: clean
+ @-find src/modules -regex .\*/config[.][^.]*\$$ -delete
+ @-find src/modules -name autom4te.cache -exec rm -rf '{}' \;
+ @rm -rf config.cache config.log config.status libtool \
+ src/include/radpaths.h src/include/stamp-h \
+ libltdl/config.log libltdl/config.status \
+ libltdl/libtool autom4te.cache build
+ @-find . ! -name configure.ac -name \*.in -print | \
+ sed 's/\.in$$//' | \
+ while read file; do rm -f $$file; done
+
+######################################################################
+#
+# Automatic remaking rules suggested by info:autoconf#Automatic_Remaking
+#
+######################################################################
+#
+# Do these checks ONLY if we're re-building the "configure"
+# scripts, and ONLY the "configure" scripts. If we leave
+# these rules enabled by default, then they're run too often.
+#
+ifeq "$(MAKECMDGOALS)" "reconfig"
+
+CONFIGURE_AC_FILES := $(shell find . -name configure.ac -print)
+CONFIGURE_FILES := $(patsubst %.ac,%,$(CONFIGURE_AC_FILES))
+
+#
+# The GNU tools make autoconf=="missing autoconf", which then returns
+# 0, even when autoconf doesn't exist. This check is to ensure that
+# we run AUTOCONF only when it exists.
+#
+AUTOCONF_EXISTS := $(shell autoconf --version 2>/dev/null)
+
+ifeq "$(AUTOCONF_EXISTS)" ""
+$(error You need to install autoconf to re-build the "configure" scripts)
+endif
+
+# Configure files depend on ".ac" files, and on the top-level macro files
+# If there are headers, run auto-header, too.
+src/%configure: src/%configure.ac acinclude.m4 aclocal.m4 $(wildcard $(dir $@)m4/*m4) | src/freeradius-devel
+ @echo AUTOCONF $(dir $@)
+ ${Q}cd $(dir $@) && \
+ $(ACLOCAL) --force -I $(top_builddir) -I $(top_builddir)/m4 && \
+ $(AUTOCONF) --force
+ ${Q}if grep AC_CONFIG_HEADERS $@ >/dev/null; then\
+ echo AUTOHEADER $@ \
+ cd $(dir $@) && $(AUTOHEADER) --force; \
+ fi
+
+# "%configure" doesn't match "configure"
+configure: configure.ac $(wildcard ac*.m4) $(wildcard m4/*.m4)
+ @echo AUTOCONF $@
+ @$(ACLOCAL) --force
+ @$(AUTOCONF) --force
+
+src/include/autoconf.h.in: configure.ac
+ @echo AUTOHEADER $@
+ @$(AUTOHEADER) --force
+
+reconfig: $(CONFIGURE_FILES) src/include/autoconf.h.in
+
+config.status: configure
+ ./config.status --recheck
+
+# target is "reconfig"
+endif
+
+#
+# If we've already run configure, then add rules which cause the
+# module-specific "all.mk" files to depend on the mk.in files, and on
+# the configure script.
+#
+ifneq "$(wildcard config.log)" ""
+CONFIGURE_ARGS := $(shell head -10 config.log | grep '^ \$$' | sed 's/^....//;s:.*configure ::')
+
+src/%all.mk: src/%all.mk.in src/%configure
+ ${Q}echo CONFIGURE $(dir $@)
+ ${Q}rm -f ./config.cache $(dir $<)/config.cache
+ ${Q}cd $(dir $<) && ./configure $(CONFIGURE_ARGS) && touch $(notdir $@)
+endif
+
+.PHONY: check-includes
+check-includes:
+ scripts/min-includes.pl `find . -name "*.c" -print`
+
+.PHONY: TAGS
+TAGS:
+ etags `find src -type f -name '*.[ch]' -print` > $@
+
+#
+# Make test certificates.
+#
+.PHONY: certs
+certs:
+ ${Q}$(MAKE) -C raddb/certs
+
+######################################################################
+#
+# Make a release.
+#
+# Note that "Make.inc" has to be updated with the release number
+# BEFORE running this command!
+#
+######################################################################
+BRANCH = $(shell git rev-parse --abbrev-ref HEAD)
+
+freeradius-server-$(RADIUSD_VERSION_STRING).tar.gz: .git/HEAD
+ git archive --format=tar --prefix=freeradius-server-$(RADIUSD_VERSION_STRING)/ $(BRANCH) | gzip > $@
+
+freeradius-server-$(RADIUSD_VERSION_STRING).tar.bz2: .git/HEAD
+ git archive --format=tar --prefix=freeradius-server-$(RADIUSD_VERSION_STRING)/ $(BRANCH) | bzip2 > $@
+
+%.sig: %
+ gpg --default-key packages@freeradius.org -b $<
+
+#
+# High-level targets
+#
+.PHONY: dist-check
+dist-check: redhat/freeradius.spec suse/freeradius.spec debian/changelog
+ ${Q}if [ `grep ^Version: redhat/freeradius.spec | sed 's/.*://;s/ //g'` != "$(RADIUSD_VERSION_STRING)" ]; then \
+ cat redhat/freeradius.spec | sed 's/^Version:.*/Version: $(RADIUSD_VERSION_STRING)/' > redhat/.foo; \
+ mv redhat/.foo redhat/freeradius.spec; \
+ echo redhat/freeradius.spec 'Version' needs to be updated; \
+ exit 1; \
+ fi
+ ${Q}if [ `grep ^Version: suse/freeradius.spec | sed 's/.*://;s/ //g'` != "$(RADIUSD_VERSION_STRING)" ]; then \
+ cat suse/freeradius.spec | sed 's/^Version: .*/Version: $(RADIUSD_VERSION_STRING)/' > suse/.foo; \
+ mv suse/.foo suse/freeradius.spec; \
+ echo suse/freeradius.spec 'Version' needs to be updated; \
+ exit 1; \
+ fi
+ ${Q}if [ `head -n 1 doc/ChangeLog | awk '/^FreeRADIUS/{print $$2}'` != "$(RADIUSD_VERSION_STRING)" ]; then \
+ echo doc/ChangeLog needs to be updated; \
+ exit 1; \
+ fi
+ ${Q}if [ `head -n 1 debian/changelog | sed 's/.*(//;s/-0).*//;s/-1).*//;s/\+.*//'` != "$(RADIUSD_VERSION_STRING)" ]; then \
+ echo debian/changelog needs to be updated; \
+ exit 1; \
+ fi
+ ${Q}if [ `grep version doc/antora/antora.yml | sed 's/^.*version: //'` != "'$(RADIUSD_VERSION_STRING)'" ]; then \
+ echo doc/antora/antora.yml needs to be updated with: version '$(RADIUSD_VERSION_STRING)'; \
+ exit 1; \
+ fi
+
+dist: dist-check freeradius-server-$(RADIUSD_VERSION_STRING).tar.gz freeradius-server-$(RADIUSD_VERSION_STRING).tar.bz2
+
+dist-sign: dist-check freeradius-server-$(RADIUSD_VERSION_STRING).tar.gz.sig freeradius-server-$(RADIUSD_VERSION_STRING).tar.bz2.sig
+
+dist-publish: freeradius-server-$(RADIUSD_VERSION_STRING).tar.gz.sig freeradius-server-$(RADIUSD_VERSION_STRING).tar.gz freeradius-server-$(RADIUSD_VERSION_STRING).tar.gz.sig freeradius-server-$(RADIUSD_VERSION_STRING).tar.bz2 freeradius-server-$(RADIUSD_VERSION_STRING).tar.gz.sig freeradius-server-$(RADIUSD_VERSION_STRING).tar.bz2.sig
+ scp $^ freeradius.org@ftp.freeradius.org:public_ftp
+
+#
+# Note that we do NOT do the tagging here! We just print out what
+# to do!
+#
+dist-tag: freeradius-server-$(RADIUSD_VERSION_STRING).tar.gz freeradius-server-$(RADIUSD_VERSION_STRING).tar.bz2
+ ${Q}echo "git tag release_`echo $(RADIUSD_VERSION_STRING) | tr .- __`"
+
+#
+# Docker-related targets (main Docker images and crossbuild)
+#
+ifneq "$(findstring docker,$(MAKECMDGOALS))" ""
+include scripts/docker/docker.mk
+endif
+
+ifneq "$(findstring crossbuild,$(MAKECMDGOALS))" ""
+include scripts/crossbuild/crossbuild.mk
+endif
+
+#
+# Build a Debian package
+#
+DEBBUILDEXTRA = --jobs=auto
+.PHONY: deb
+deb:
+ fakeroot debian/rules debian/control #clean
+ fakeroot dpkg-buildpackage $(DEBBUILDEXTRA) -b -uc
+
+#
+# Build an RPM package
+#
+.PHONY: rpm
+rpmbuild/SOURCES/freeradius-server-$(RADIUSD_VERSION_STRING).tar.bz2: freeradius-server-$(RADIUSD_VERSION_STRING).tar.bz2
+ ${Q}mkdir -p $(addprefix rpmbuild/,SOURCES SPECS BUILD RPMS SRPMS BUILDROOT)
+ ${Q}for file in `awk '/^Source...:/ {print $$2}' redhat/freeradius.spec` ; do cp redhat/$$file rpmbuild/SOURCES/$$file ; done
+ ${Q}cp $< $@
+
+rpm: rpmbuild/SOURCES/freeradius-server-$(RADIUSD_VERSION_STRING).tar.bz2
+ ${Q}if ! yum-builddep -q -C --assumeno redhat/freeradius.spec 1> /dev/null 2>&1; then \
+ echo "ERROR: Required depdendencies not found, install them with: yum-builddep redhat/freeradius.spec"; \
+ exit 1; \
+ fi
+ ${Q}QA_RPATHS=0x0003 rpmbuild --define "_topdir `pwd`/rpmbuild" -bb redhat/freeradius.spec
+
+#
+# Developer checks
+#
+.PHONY: warnings
+warnings:
+ ${Q}(make clean all 2>&1) | egrep -v '^/|deprecated|^In file included|: In function| from |^HEADER|^CC|^LN|^LINK' > warnings.txt
+ ${Q}@wc -l warnings.txt
+
+#
+# Ensure we're using tabs in the configuration files,
+# and remove trailing whitespace in source files.
+#
+.PHONY: whitespace
+whitespace:
+ ${Q}for x in $$(git ls-files raddb/ src/); do unexpand $$x > $$x.bak; cp $$x.bak $$x; rm -f $$x.bak;done
+ ${Q}perl -p -i -e 'trim' $$(git ls-files src/)
diff --git a/README.rst b/README.rst
new file mode 100644
index 0000000..75cc11c
--- /dev/null
+++ b/README.rst
@@ -0,0 +1,179 @@
+The FreeRADIUS server
+=====================
+
+|BuildStatus|_ |CoverityStatus|_
+
+.. contents::
+ :local:
+
+Introduction
+------------
+
+The FreeRADIUS Server Project is a high performance and highly
+configurable multi-protocol policy server, supporting RADIUS, DHCPv4
+and VMPS. It is available under the terms of the GNU GPLv2.
+Using RADIUS allows authentication and authorization for a network
+to be centralized, and minimizes the number of changes that have to
+be done when adding or deleting new users to a network.
+
+FreeRADIUS can authenticate users on systems such as 802.1X (WiFi),
+dialup, PPPoE, VPN's, VoIP, and many others. It supports back-end
+databases such as MySQL, PostgreSQL, Oracle, Microsoft Active
+Directory, Redis, OpenLDAP, and many more. It is used daily to
+authenticate the Internet access for hundreds of millions of people,
+in sites ranging from 10 to 10 million+ users.
+
+Version 3.0 of the server is largely compatible with version 2.x, but
+we highly recommend that you recreate your configuration, rather than
+trying to get the older configuration to work.
+
+For a list of changes in version 3.0, please see ``doc/ChangeLog``.
+
+See ``raddb/README.rst`` for information on what to do to update your
+configuration.
+
+Administrators upgrading from a previous version should install this
+version in a different location from their existing systems. Any
+existing configuration should be carefully migrated to the new
+version, in order to take advantage of the new features which can
+greatly simply configuration.
+
+Please see https://freeradius.org and https://wiki.freeradius.org for
+more information.
+
+
+Installation
+------------
+
+To install the server, please see the INSTALL file in this directory.
+
+Configuring the server
+----------------------
+
+We understand that the server may be difficult to configure,
+install, or administer. It is, after all, a complex system with many
+different configuration possibilities.
+
+The most common problem is that people change large amounts of the
+configuration without understanding what they're doing, and without
+testing their changes. The preferred method of operation is the
+following:
+
+1. Start off with the default configuration files.
+2. Save a copy of the default configuration: It WORKS. Don't change it!
+3. Verify that the server starts - in debugging mode (``radiusd -X``).
+4. Send it test packets using "radclient", or a NAS or AP.
+5. Verify that the server does what you expect
+
+ - If it does not work, change the configuration, and go to step (3)
+ - If you're stuck, revert to using the "last working" configuration.
+ - If it works, proceed to step (6).
+
+6. Save a copy of the working configuration, along with a note of what
+ you changed, and why.
+7. Make a SMALL change to the configuration.
+8. Repeat from step (3).
+
+This method will ensure that you have a working configuration that
+is customized to your site as quickly as possible. While it may seem
+frustrating to proceed via a series of small steps, the alternative
+will always take more time. The "fast and loose" way will be MORE
+frustrating than quickly making forward progress!
+
+Debugging the Server
+--------------------
+
+Run the server in debugging mode, (``radiusd -X``) and READ the output.
+We cannot emphasize this point strongly enough. The vast majority of
+problems can be solved by carefully reading the debugging output,
+which includes WARNINGs about common issues, and suggestions for how
+they may be fixed.
+
+Many questions are answered on the Wiki:
+
+https://wiki.freeradius.org
+
+Read the configuration files. Many parts of the server are
+documented only with extensive comments in the configuration files.
+
+Search the mailing lists. For example, using Google, searching
+"site:lists.freeradius.org <search term>" will return results from
+the FreeRADIUS mailing lists.
+
+https://freeradius.org/support/
+
+
+Feedback, Defects, and Community Support
+----------------------------------------
+
+If you have any comments, or are having difficulty getting FreeRADIUS
+to do what you want, please post to the 'freeradius-users' list
+(see the URL above). The FreeRADIUS mailing list is operated, and
+contributed to, by the FreeRADIUS community. Users of the list will be
+more than happy to answer your questions, with the caveat that you've
+read documentation relevant to your issue first.
+
+If you suspect a defect in the server, would like to request a feature,
+or submit a code patch, please use the GitHub issue tracker for the
+freeradius-server `repository
+<https://github.com/FreeRADIUS/freeradius-server>`_. However, it
+is nearly always best to raise the issue on the mailing lists
+first to determine whether it really is a defect or missing
+feature.
+
+Instructions for gathering data for defect reports can be found in
+``doc/bugs`` or on the `wiki
+<https://wiki.freeradius.org/project/bug-reports>`_.
+
+Under no circumstances should the issue tracker be used for support
+requests, those questions belong on the user's mailing list. If you
+post questions related to the server in the issue tracker, the issue
+will be closed and locked. If you persist in positing questions to
+the issue tracker you will be banned from all FreeRADIUS project
+repositories on GitHub.
+
+Please do NOT complain that the developers aren't answering your
+questions quickly enough, or aren't fixing the problems quickly
+enough. Please do NOT complain if you're told to go read
+documentation. We recognize that the documentation isn't perfect, but
+it *does* exist, and reading it can solve most common questions.
+
+FreeRADIUS is the cumulative effort of many years of work by many
+people, and you've gotten it for free. No one is getting paid to answer
+your questions. This is free software, and the only way it gets better
+is if you make a contribution back to the project ($$, code, or
+documentation).
+
+We will note that the people who get most upset about any answers to
+their questions usually do not have any intention of contributing to
+the project. We will repeat the comments above: no one is getting
+paid to answer your questions or to fix your bugs. If you don't like
+the responses you are getting, then fix the bug yourself, or pay
+someone to address your concerns. Either way, make sure that any fix
+is contributed back to the project so that no one else runs into the
+same issue.
+
+Books on RADIUS
+---------------
+
+See ``doc/README`` for more information about FreeRADIUS.
+
+There is an O'Reilly book available. It serves as a good
+introduction for anyone new to RADIUS. However, it is almost 20 years
+old, and is not much more than a basic introduction to the subject.
+
+https://www.amazon.com/exec/obidos/ASIN/0596003226/freeradiusorg-20/
+
+Commercial support
+------------------
+
+Technical support, managed systems support, custom deployments,
+sponsored feature development and many other commercial services
+are available from `Network RADIUS <https://networkradius.com>`_.
+
+
+.. |CoverityStatus| image:: https://scan.coverity.com/projects/58/badge.svg?
+.. _CoverityStatus: https://scan.coverity.com/projects/58
+
+.. |BuildStatus| image:: https://github.com/FreeRADIUS/freeradius-server/workflows/CI/badge.svg?branch=v3.2.x
+.. _BuildStatus: https://github.com/FreeRADIUS/freeradius-server/actions?query=workflow%3ACI
diff --git a/VERSION b/VERSION
new file mode 100644
index 0000000..b347b11
--- /dev/null
+++ b/VERSION
@@ -0,0 +1 @@
+3.2.3
diff --git a/config.guess b/config.guess
new file mode 100644
index 0000000..f772702
--- /dev/null
+++ b/config.guess
@@ -0,0 +1,1701 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+# Copyright 1992-2021 Free Software Foundation, Inc.
+
+timestamp='2021-01-01'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <https://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that
+# program. This Exception is an additional permission under section 7
+# of the GNU General Public License, version 3 ("GPLv3").
+#
+# Originally written by Per Bothner; maintained since 2000 by Ben Elliston.
+#
+# You can get the latest version of this script from:
+# https://git.savannah.gnu.org/cgit/config.git/plain/config.guess
+#
+# Please send patches to <config-patches@gnu.org>.
+
+
+me=$(echo "$0" | sed -e 's,.*/,,')
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Options:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright 1992-2021 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help" >&2
+ exit 1 ;;
+ * )
+ break ;;
+ esac
+done
+
+if test $# != 0; then
+ echo "$me: too many arguments$help" >&2
+ exit 1
+fi
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+tmp=
+# shellcheck disable=SC2172
+trap 'test -z "$tmp" || rm -fr "$tmp"' 0 1 2 13 15
+
+set_cc_for_build() {
+ # prevent multiple calls if $tmp is already set
+ test "$tmp" && return 0
+ : "${TMPDIR=/tmp}"
+ # shellcheck disable=SC2039
+ { tmp=$( (umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null) && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir "$tmp" 2>/dev/null) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; }
+ dummy=$tmp/dummy
+ case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in
+ ,,) echo "int x;" > "$dummy.c"
+ for driver in cc gcc c89 c99 ; do
+ if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then
+ CC_FOR_BUILD="$driver"
+ break
+ fi
+ done
+ if test x"$CC_FOR_BUILD" = x ; then
+ CC_FOR_BUILD=no_compiler_found
+ fi
+ ;;
+ ,,*) CC_FOR_BUILD=$CC ;;
+ ,*,*) CC_FOR_BUILD=$HOST_CC ;;
+ esac
+}
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if test -f /.attbin/uname ; then
+ PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=$( (uname -m) 2>/dev/null) || UNAME_MACHINE=unknown
+UNAME_RELEASE=$( (uname -r) 2>/dev/null) || UNAME_RELEASE=unknown
+UNAME_SYSTEM=$( (uname -s) 2>/dev/null) || UNAME_SYSTEM=unknown
+UNAME_VERSION=$( (uname -v) 2>/dev/null) || UNAME_VERSION=unknown
+
+case "$UNAME_SYSTEM" in
+Linux|GNU|GNU/*)
+ LIBC=unknown
+
+ set_cc_for_build
+ cat <<-EOF > "$dummy.c"
+ #include <features.h>
+ #if defined(__UCLIBC__)
+ LIBC=uclibc
+ #elif defined(__dietlibc__)
+ LIBC=dietlibc
+ #elif defined(__GLIBC__)
+ LIBC=gnu
+ #else
+ #include <stdarg.h>
+ /* First heuristic to detect musl libc. */
+ #ifdef __DEFINED_va_list
+ LIBC=musl
+ #endif
+ #endif
+ EOF
+ eval "$($CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g')"
+
+ # Second heuristic to detect musl libc.
+ if [ "$LIBC" = unknown ] &&
+ command -v ldd >/dev/null &&
+ ldd --version 2>&1 | grep -q ^musl; then
+ LIBC=musl
+ fi
+
+ # If the system lacks a compiler, then just pick glibc.
+ # We could probably try harder.
+ if [ "$LIBC" = unknown ]; then
+ LIBC=gnu
+ fi
+ ;;
+esac
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
+ *:NetBSD:*:*)
+ # NetBSD (nbsd) targets should (where applicable) match one or
+ # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,
+ # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
+ # switched to ELF, *-*-netbsd* would select the old
+ # object file format. This provides both forward
+ # compatibility and a consistent mechanism for selecting the
+ # object file format.
+ #
+ # Note: NetBSD doesn't particularly care about the vendor
+ # portion of the name. We always set it to "unknown".
+ sysctl="sysctl -n hw.machine_arch"
+ UNAME_MACHINE_ARCH=$( (uname -p 2>/dev/null || \
+ "/sbin/$sysctl" 2>/dev/null || \
+ "/usr/sbin/$sysctl" 2>/dev/null || \
+ echo unknown))
+ case "$UNAME_MACHINE_ARCH" in
+ aarch64eb) machine=aarch64_be-unknown ;;
+ armeb) machine=armeb-unknown ;;
+ arm*) machine=arm-unknown ;;
+ sh3el) machine=shl-unknown ;;
+ sh3eb) machine=sh-unknown ;;
+ sh5el) machine=sh5le-unknown ;;
+ earmv*)
+ arch=$(echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,')
+ endian=$(echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p')
+ machine="${arch}${endian}"-unknown
+ ;;
+ *) machine="$UNAME_MACHINE_ARCH"-unknown ;;
+ esac
+ # The Operating System including object format, if it has switched
+ # to ELF recently (or will in the future) and ABI.
+ case "$UNAME_MACHINE_ARCH" in
+ earm*)
+ os=netbsdelf
+ ;;
+ arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+ set_cc_for_build
+ if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ELF__
+ then
+ # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+ # Return netbsd for either. FIX?
+ os=netbsd
+ else
+ os=netbsdelf
+ fi
+ ;;
+ *)
+ os=netbsd
+ ;;
+ esac
+ # Determine ABI tags.
+ case "$UNAME_MACHINE_ARCH" in
+ earm*)
+ expr='s/^earmv[0-9]/-eabi/;s/eb$//'
+ abi=$(echo "$UNAME_MACHINE_ARCH" | sed -e "$expr")
+ ;;
+ esac
+ # The OS release
+ # Debian GNU/NetBSD machines have a different userland, and
+ # thus, need a distinct triplet. However, they do not need
+ # kernel version information, so it can be replaced with a
+ # suitable tag, in the style of linux-gnu.
+ case "$UNAME_VERSION" in
+ Debian*)
+ release='-gnu'
+ ;;
+ *)
+ release=$(echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2)
+ ;;
+ esac
+ # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+ # contains redundant information, the shorter form:
+ # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+ echo "$machine-${os}${release}${abi-}"
+ exit ;;
+ *:Bitrig:*:*)
+ UNAME_MACHINE_ARCH=$(arch | sed 's/Bitrig.//')
+ echo "$UNAME_MACHINE_ARCH"-unknown-bitrig"$UNAME_RELEASE"
+ exit ;;
+ *:OpenBSD:*:*)
+ UNAME_MACHINE_ARCH=$(arch | sed 's/OpenBSD.//')
+ echo "$UNAME_MACHINE_ARCH"-unknown-openbsd"$UNAME_RELEASE"
+ exit ;;
+ *:LibertyBSD:*:*)
+ UNAME_MACHINE_ARCH=$(arch | sed 's/^.*BSD\.//')
+ echo "$UNAME_MACHINE_ARCH"-unknown-libertybsd"$UNAME_RELEASE"
+ exit ;;
+ *:MidnightBSD:*:*)
+ echo "$UNAME_MACHINE"-unknown-midnightbsd"$UNAME_RELEASE"
+ exit ;;
+ *:ekkoBSD:*:*)
+ echo "$UNAME_MACHINE"-unknown-ekkobsd"$UNAME_RELEASE"
+ exit ;;
+ *:SolidBSD:*:*)
+ echo "$UNAME_MACHINE"-unknown-solidbsd"$UNAME_RELEASE"
+ exit ;;
+ *:OS108:*:*)
+ echo "$UNAME_MACHINE"-unknown-os108_"$UNAME_RELEASE"
+ exit ;;
+ macppc:MirBSD:*:*)
+ echo powerpc-unknown-mirbsd"$UNAME_RELEASE"
+ exit ;;
+ *:MirBSD:*:*)
+ echo "$UNAME_MACHINE"-unknown-mirbsd"$UNAME_RELEASE"
+ exit ;;
+ *:Sortix:*:*)
+ echo "$UNAME_MACHINE"-unknown-sortix
+ exit ;;
+ *:Twizzler:*:*)
+ echo "$UNAME_MACHINE"-unknown-twizzler
+ exit ;;
+ *:Redox:*:*)
+ echo "$UNAME_MACHINE"-unknown-redox
+ exit ;;
+ mips:OSF1:*.*)
+ echo mips-dec-osf1
+ exit ;;
+ alpha:OSF1:*:*)
+ case $UNAME_RELEASE in
+ *4.0)
+ UNAME_RELEASE=$(/usr/sbin/sizer -v | awk '{print $3}')
+ ;;
+ *5.*)
+ UNAME_RELEASE=$(/usr/sbin/sizer -v | awk '{print $4}')
+ ;;
+ esac
+ # According to Compaq, /usr/sbin/psrinfo has been available on
+ # OSF/1 and Tru64 systems produced since 1995. I hope that
+ # covers most systems running today. This code pipes the CPU
+ # types through head -n 1, so we only detect the type of CPU 0.
+ ALPHA_CPU_TYPE=$(/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1)
+ case "$ALPHA_CPU_TYPE" in
+ "EV4 (21064)")
+ UNAME_MACHINE=alpha ;;
+ "EV4.5 (21064)")
+ UNAME_MACHINE=alpha ;;
+ "LCA4 (21066/21068)")
+ UNAME_MACHINE=alpha ;;
+ "EV5 (21164)")
+ UNAME_MACHINE=alphaev5 ;;
+ "EV5.6 (21164A)")
+ UNAME_MACHINE=alphaev56 ;;
+ "EV5.6 (21164PC)")
+ UNAME_MACHINE=alphapca56 ;;
+ "EV5.7 (21164PC)")
+ UNAME_MACHINE=alphapca57 ;;
+ "EV6 (21264)")
+ UNAME_MACHINE=alphaev6 ;;
+ "EV6.7 (21264A)")
+ UNAME_MACHINE=alphaev67 ;;
+ "EV6.8CB (21264C)")
+ UNAME_MACHINE=alphaev68 ;;
+ "EV6.8AL (21264B)")
+ UNAME_MACHINE=alphaev68 ;;
+ "EV6.8CX (21264D)")
+ UNAME_MACHINE=alphaev68 ;;
+ "EV6.9A (21264/EV69A)")
+ UNAME_MACHINE=alphaev69 ;;
+ "EV7 (21364)")
+ UNAME_MACHINE=alphaev7 ;;
+ "EV7.9 (21364A)")
+ UNAME_MACHINE=alphaev79 ;;
+ esac
+ # A Pn.n version is a patched version.
+ # A Vn.n version is a released version.
+ # A Tn.n version is a released field test version.
+ # A Xn.n version is an unreleased experimental baselevel.
+ # 1.2 uses "1.2" for uname -r.
+ echo "$UNAME_MACHINE"-dec-osf"$(echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz)"
+ # Reset EXIT trap before exiting to avoid spurious non-zero exit code.
+ exitcode=$?
+ trap '' 0
+ exit $exitcode ;;
+ Amiga*:UNIX_System_V:4.0:*)
+ echo m68k-unknown-sysv4
+ exit ;;
+ *:[Aa]miga[Oo][Ss]:*:*)
+ echo "$UNAME_MACHINE"-unknown-amigaos
+ exit ;;
+ *:[Mm]orph[Oo][Ss]:*:*)
+ echo "$UNAME_MACHINE"-unknown-morphos
+ exit ;;
+ *:OS/390:*:*)
+ echo i370-ibm-openedition
+ exit ;;
+ *:z/VM:*:*)
+ echo s390-ibm-zvmoe
+ exit ;;
+ *:OS400:*:*)
+ echo powerpc-ibm-os400
+ exit ;;
+ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+ echo arm-acorn-riscix"$UNAME_RELEASE"
+ exit ;;
+ arm*:riscos:*:*|arm*:RISCOS:*:*)
+ echo arm-unknown-riscos
+ exit ;;
+ SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+ echo hppa1.1-hitachi-hiuxmpp
+ exit ;;
+ Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+ # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+ if test "$( (/bin/universe) 2>/dev/null)" = att ; then
+ echo pyramid-pyramid-sysv3
+ else
+ echo pyramid-pyramid-bsd
+ fi
+ exit ;;
+ NILE*:*:*:dcosx)
+ echo pyramid-pyramid-svr4
+ exit ;;
+ DRS?6000:unix:4.0:6*)
+ echo sparc-icl-nx6
+ exit ;;
+ DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+ case $(/usr/bin/uname -p) in
+ sparc) echo sparc-icl-nx7; exit ;;
+ esac ;;
+ s390x:SunOS:*:*)
+ echo "$UNAME_MACHINE"-ibm-solaris2"$(echo "$UNAME_RELEASE" | sed -e 's/[^.]*//')"
+ exit ;;
+ sun4H:SunOS:5.*:*)
+ echo sparc-hal-solaris2"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')"
+ exit ;;
+ sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+ echo sparc-sun-solaris2"$(echo "$UNAME_RELEASE" | sed -e 's/[^.]*//')"
+ exit ;;
+ i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
+ echo i386-pc-auroraux"$UNAME_RELEASE"
+ exit ;;
+ i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+ set_cc_for_build
+ SUN_ARCH=i386
+ # If there is a compiler, see if it is configured for 64-bit objects.
+ # Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
+ # This test works for both compilers.
+ if test "$CC_FOR_BUILD" != no_compiler_found; then
+ if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
+ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
+ then
+ SUN_ARCH=x86_64
+ fi
+ fi
+ echo "$SUN_ARCH"-pc-solaris2"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')"
+ exit ;;
+ sun4*:SunOS:6*:*)
+ # According to config.sub, this is the proper way to canonicalize
+ # SunOS6. Hard to guess exactly what SunOS6 will be like, but
+ # it's likely to be more like Solaris than SunOS4.
+ echo sparc-sun-solaris3"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')"
+ exit ;;
+ sun4*:SunOS:*:*)
+ case "$(/usr/bin/arch -k)" in
+ Series*|S4*)
+ UNAME_RELEASE=$(uname -v)
+ ;;
+ esac
+ # Japanese Language versions have a version number like `4.1.3-JL'.
+ echo sparc-sun-sunos"$(echo "$UNAME_RELEASE"|sed -e 's/-/_/')"
+ exit ;;
+ sun3*:SunOS:*:*)
+ echo m68k-sun-sunos"$UNAME_RELEASE"
+ exit ;;
+ sun*:*:4.2BSD:*)
+ UNAME_RELEASE=$( (sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null)
+ test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3
+ case "$(/bin/arch)" in
+ sun3)
+ echo m68k-sun-sunos"$UNAME_RELEASE"
+ ;;
+ sun4)
+ echo sparc-sun-sunos"$UNAME_RELEASE"
+ ;;
+ esac
+ exit ;;
+ aushp:SunOS:*:*)
+ echo sparc-auspex-sunos"$UNAME_RELEASE"
+ exit ;;
+ # The situation for MiNT is a little confusing. The machine name
+ # can be virtually everything (everything which is not
+ # "atarist" or "atariste" at least should have a processor
+ # > m68000). The system name ranges from "MiNT" over "FreeMiNT"
+ # to the lowercase version "mint" (or "freemint"). Finally
+ # the system name "TOS" denotes a system which is actually not
+ # MiNT. But MiNT is downward compatible to TOS, so this should
+ # be no problem.
+ atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint"$UNAME_RELEASE"
+ exit ;;
+ atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint"$UNAME_RELEASE"
+ exit ;;
+ *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+ echo m68k-atari-mint"$UNAME_RELEASE"
+ exit ;;
+ milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+ echo m68k-milan-mint"$UNAME_RELEASE"
+ exit ;;
+ hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+ echo m68k-hades-mint"$UNAME_RELEASE"
+ exit ;;
+ *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+ echo m68k-unknown-mint"$UNAME_RELEASE"
+ exit ;;
+ m68k:machten:*:*)
+ echo m68k-apple-machten"$UNAME_RELEASE"
+ exit ;;
+ powerpc:machten:*:*)
+ echo powerpc-apple-machten"$UNAME_RELEASE"
+ exit ;;
+ RISC*:Mach:*:*)
+ echo mips-dec-mach_bsd4.3
+ exit ;;
+ RISC*:ULTRIX:*:*)
+ echo mips-dec-ultrix"$UNAME_RELEASE"
+ exit ;;
+ VAX*:ULTRIX*:*:*)
+ echo vax-dec-ultrix"$UNAME_RELEASE"
+ exit ;;
+ 2020:CLIX:*:* | 2430:CLIX:*:*)
+ echo clipper-intergraph-clix"$UNAME_RELEASE"
+ exit ;;
+ mips:*:*:UMIPS | mips:*:*:RISCos)
+ set_cc_for_build
+ sed 's/^ //' << EOF > "$dummy.c"
+#ifdef __cplusplus
+#include <stdio.h> /* for printf() prototype */
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+ #if defined (host_mips) && defined (MIPSEB)
+ #if defined (SYSTYPE_SYSV)
+ printf ("mips-mips-riscos%ssysv\\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_SVR4)
+ printf ("mips-mips-riscos%ssvr4\\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+ printf ("mips-mips-riscos%sbsd\\n", argv[1]); exit (0);
+ #endif
+ #endif
+ exit (-1);
+ }
+EOF
+ $CC_FOR_BUILD -o "$dummy" "$dummy.c" &&
+ dummyarg=$(echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p') &&
+ SYSTEM_NAME=$("$dummy" "$dummyarg") &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo mips-mips-riscos"$UNAME_RELEASE"
+ exit ;;
+ Motorola:PowerMAX_OS:*:*)
+ echo powerpc-motorola-powermax
+ exit ;;
+ Motorola:*:4.3:PL8-*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:Power_UNIX:*:*)
+ echo powerpc-harris-powerunix
+ exit ;;
+ m88k:CX/UX:7*:*)
+ echo m88k-harris-cxux7
+ exit ;;
+ m88k:*:4*:R4*)
+ echo m88k-motorola-sysv4
+ exit ;;
+ m88k:*:3*:R3*)
+ echo m88k-motorola-sysv3
+ exit ;;
+ AViiON:dgux:*:*)
+ # DG/UX returns AViiON for all architectures
+ UNAME_PROCESSOR=$(/usr/bin/uname -p)
+ if test "$UNAME_PROCESSOR" = mc88100 || test "$UNAME_PROCESSOR" = mc88110
+ then
+ if test "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx || \
+ test "$TARGET_BINARY_INTERFACE"x = x
+ then
+ echo m88k-dg-dgux"$UNAME_RELEASE"
+ else
+ echo m88k-dg-dguxbcs"$UNAME_RELEASE"
+ fi
+ else
+ echo i586-dg-dgux"$UNAME_RELEASE"
+ fi
+ exit ;;
+ M88*:DolphinOS:*:*) # DolphinOS (SVR3)
+ echo m88k-dolphin-sysv3
+ exit ;;
+ M88*:*:R3*:*)
+ # Delta 88k system running SVR3
+ echo m88k-motorola-sysv3
+ exit ;;
+ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+ echo m88k-tektronix-sysv3
+ exit ;;
+ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+ echo m68k-tektronix-bsd
+ exit ;;
+ *:IRIX*:*:*)
+ echo mips-sgi-irix"$(echo "$UNAME_RELEASE"|sed -e 's/-/_/g')"
+ exit ;;
+ ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+ echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
+ exit ;; # Note that: echo "'$(uname -s)'" gives 'AIX '
+ i*86:AIX:*:*)
+ echo i386-ibm-aix
+ exit ;;
+ ia64:AIX:*:*)
+ if test -x /usr/bin/oslevel ; then
+ IBM_REV=$(/usr/bin/oslevel)
+ else
+ IBM_REV="$UNAME_VERSION.$UNAME_RELEASE"
+ fi
+ echo "$UNAME_MACHINE"-ibm-aix"$IBM_REV"
+ exit ;;
+ *:AIX:2:3)
+ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+ set_cc_for_build
+ sed 's/^ //' << EOF > "$dummy.c"
+ #include <sys/systemcfg.h>
+
+ main()
+ {
+ if (!__power_pc())
+ exit(1);
+ puts("powerpc-ibm-aix3.2.5");
+ exit(0);
+ }
+EOF
+ if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=$("$dummy")
+ then
+ echo "$SYSTEM_NAME"
+ else
+ echo rs6000-ibm-aix3.2.5
+ fi
+ elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+ echo rs6000-ibm-aix3.2.4
+ else
+ echo rs6000-ibm-aix3.2
+ fi
+ exit ;;
+ *:AIX:*:[4567])
+ IBM_CPU_ID=$(/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }')
+ if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then
+ IBM_ARCH=rs6000
+ else
+ IBM_ARCH=powerpc
+ fi
+ if test -x /usr/bin/lslpp ; then
+ IBM_REV=$(/usr/bin/lslpp -Lqc bos.rte.libc |
+ awk -F: '{ print $3 }' | sed s/[0-9]*$/0/)
+ else
+ IBM_REV="$UNAME_VERSION.$UNAME_RELEASE"
+ fi
+ echo "$IBM_ARCH"-ibm-aix"$IBM_REV"
+ exit ;;
+ *:AIX:*:*)
+ echo rs6000-ibm-aix
+ exit ;;
+ ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*)
+ echo romp-ibm-bsd4.4
+ exit ;;
+ ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
+ echo romp-ibm-bsd"$UNAME_RELEASE" # 4.3 with uname added to
+ exit ;; # report: romp-ibm BSD 4.3
+ *:BOSX:*:*)
+ echo rs6000-bull-bosx
+ exit ;;
+ DPX/2?00:B.O.S.:*:*)
+ echo m68k-bull-sysv3
+ exit ;;
+ 9000/[34]??:4.3bsd:1.*:*)
+ echo m68k-hp-bsd
+ exit ;;
+ hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+ echo m68k-hp-bsd4.4
+ exit ;;
+ 9000/[34678]??:HP-UX:*:*)
+ HPUX_REV=$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//')
+ case "$UNAME_MACHINE" in
+ 9000/31?) HP_ARCH=m68000 ;;
+ 9000/[34]??) HP_ARCH=m68k ;;
+ 9000/[678][0-9][0-9])
+ if test -x /usr/bin/getconf; then
+ sc_cpu_version=$(/usr/bin/getconf SC_CPU_VERSION 2>/dev/null)
+ sc_kernel_bits=$(/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null)
+ case "$sc_cpu_version" in
+ 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0
+ 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1
+ 532) # CPU_PA_RISC2_0
+ case "$sc_kernel_bits" in
+ 32) HP_ARCH=hppa2.0n ;;
+ 64) HP_ARCH=hppa2.0w ;;
+ '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20
+ esac ;;
+ esac
+ fi
+ if test "$HP_ARCH" = ""; then
+ set_cc_for_build
+ sed 's/^ //' << EOF > "$dummy.c"
+
+ #define _HPUX_SOURCE
+ #include <stdlib.h>
+ #include <unistd.h>
+
+ int main ()
+ {
+ #if defined(_SC_KERNEL_BITS)
+ long bits = sysconf(_SC_KERNEL_BITS);
+ #endif
+ long cpu = sysconf (_SC_CPU_VERSION);
+
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+ case CPU_PA_RISC2_0:
+ #if defined(_SC_KERNEL_BITS)
+ switch (bits)
+ {
+ case 64: puts ("hppa2.0w"); break;
+ case 32: puts ("hppa2.0n"); break;
+ default: puts ("hppa2.0"); break;
+ } break;
+ #else /* !defined(_SC_KERNEL_BITS) */
+ puts ("hppa2.0"); break;
+ #endif
+ default: puts ("hppa1.0"); break;
+ }
+ exit (0);
+ }
+EOF
+ (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=$("$dummy")
+ test -z "$HP_ARCH" && HP_ARCH=hppa
+ fi ;;
+ esac
+ if test "$HP_ARCH" = hppa2.0w
+ then
+ set_cc_for_build
+
+ # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+ # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler
+ # generating 64-bit code. GNU and HP use different nomenclature:
+ #
+ # $ CC_FOR_BUILD=cc ./config.guess
+ # => hppa2.0w-hp-hpux11.23
+ # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+ # => hppa64-hp-hpux11.23
+
+ if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) |
+ grep -q __LP64__
+ then
+ HP_ARCH=hppa2.0w
+ else
+ HP_ARCH=hppa64
+ fi
+ fi
+ echo "$HP_ARCH"-hp-hpux"$HPUX_REV"
+ exit ;;
+ ia64:HP-UX:*:*)
+ HPUX_REV=$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//')
+ echo ia64-hp-hpux"$HPUX_REV"
+ exit ;;
+ 3050*:HI-UX:*:*)
+ set_cc_for_build
+ sed 's/^ //' << EOF > "$dummy.c"
+ #include <unistd.h>
+ int
+ main ()
+ {
+ long cpu = sysconf (_SC_CPU_VERSION);
+ /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
+ results, however. */
+ if (CPU_IS_PA_RISC (cpu))
+ {
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+ default: puts ("hppa-hitachi-hiuxwe2"); break;
+ }
+ }
+ else if (CPU_IS_HP_MC68K (cpu))
+ puts ("m68k-hitachi-hiuxwe2");
+ else puts ("unknown-hitachi-hiuxwe2");
+ exit (0);
+ }
+EOF
+ $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=$("$dummy") &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo unknown-hitachi-hiuxwe2
+ exit ;;
+ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*)
+ echo hppa1.1-hp-bsd
+ exit ;;
+ 9000/8??:4.3bsd:*:*)
+ echo hppa1.0-hp-bsd
+ exit ;;
+ *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+ echo hppa1.0-hp-mpeix
+ exit ;;
+ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*)
+ echo hppa1.1-hp-osf
+ exit ;;
+ hp8??:OSF1:*:*)
+ echo hppa1.0-hp-osf
+ exit ;;
+ i*86:OSF1:*:*)
+ if test -x /usr/sbin/sysversion ; then
+ echo "$UNAME_MACHINE"-unknown-osf1mk
+ else
+ echo "$UNAME_MACHINE"-unknown-osf1
+ fi
+ exit ;;
+ parisc*:Lites*:*:*)
+ echo hppa1.1-hp-lites
+ exit ;;
+ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+ echo c1-convex-bsd
+ exit ;;
+ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit ;;
+ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+ echo c34-convex-bsd
+ exit ;;
+ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+ echo c38-convex-bsd
+ exit ;;
+ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+ echo c4-convex-bsd
+ exit ;;
+ CRAY*Y-MP:*:*:*)
+ echo ymp-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*[A-Z]90:*:*:*)
+ echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \
+ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+ -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*TS:*:*:*)
+ echo t90-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*T3E:*:*:*)
+ echo alphaev5-cray-unicosmk"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*SV1:*:*:*)
+ echo sv1-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ *:UNICOS/mp:*:*)
+ echo craynv-cray-unicosmp"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+ FUJITSU_PROC=$(uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz)
+ FUJITSU_SYS=$(uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///')
+ FUJITSU_REL=$(echo "$UNAME_RELEASE" | sed -e 's/ /_/')
+ echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ 5000:UNIX_System_V:4.*:*)
+ FUJITSU_SYS=$(uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///')
+ FUJITSU_REL=$(echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/')
+ echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+ echo "$UNAME_MACHINE"-pc-bsdi"$UNAME_RELEASE"
+ exit ;;
+ sparc*:BSD/OS:*:*)
+ echo sparc-unknown-bsdi"$UNAME_RELEASE"
+ exit ;;
+ *:BSD/OS:*:*)
+ echo "$UNAME_MACHINE"-unknown-bsdi"$UNAME_RELEASE"
+ exit ;;
+ arm:FreeBSD:*:*)
+ UNAME_PROCESSOR=$(uname -p)
+ set_cc_for_build
+ if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ARM_PCS_VFP
+ then
+ echo "${UNAME_PROCESSOR}"-unknown-freebsd"$(echo ${UNAME_RELEASE}|sed -e 's/[-(].*//')"-gnueabi
+ else
+ echo "${UNAME_PROCESSOR}"-unknown-freebsd"$(echo ${UNAME_RELEASE}|sed -e 's/[-(].*//')"-gnueabihf
+ fi
+ exit ;;
+ *:FreeBSD:*:*)
+ UNAME_PROCESSOR=$(/usr/bin/uname -p)
+ case "$UNAME_PROCESSOR" in
+ amd64)
+ UNAME_PROCESSOR=x86_64 ;;
+ i386)
+ UNAME_PROCESSOR=i586 ;;
+ esac
+ echo "$UNAME_PROCESSOR"-unknown-freebsd"$(echo "$UNAME_RELEASE"|sed -e 's/[-(].*//')"
+ exit ;;
+ i*:CYGWIN*:*)
+ echo "$UNAME_MACHINE"-pc-cygwin
+ exit ;;
+ *:MINGW64*:*)
+ echo "$UNAME_MACHINE"-pc-mingw64
+ exit ;;
+ *:MINGW*:*)
+ echo "$UNAME_MACHINE"-pc-mingw32
+ exit ;;
+ *:MSYS*:*)
+ echo "$UNAME_MACHINE"-pc-msys
+ exit ;;
+ i*:PW*:*)
+ echo "$UNAME_MACHINE"-pc-pw32
+ exit ;;
+ *:Interix*:*)
+ case "$UNAME_MACHINE" in
+ x86)
+ echo i586-pc-interix"$UNAME_RELEASE"
+ exit ;;
+ authenticamd | genuineintel | EM64T)
+ echo x86_64-unknown-interix"$UNAME_RELEASE"
+ exit ;;
+ IA64)
+ echo ia64-unknown-interix"$UNAME_RELEASE"
+ exit ;;
+ esac ;;
+ i*:UWIN*:*)
+ echo "$UNAME_MACHINE"-pc-uwin
+ exit ;;
+ amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+ echo x86_64-pc-cygwin
+ exit ;;
+ prep*:SunOS:5.*:*)
+ echo powerpcle-unknown-solaris2"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')"
+ exit ;;
+ *:GNU:*:*)
+ # the GNU system
+ echo "$(echo "$UNAME_MACHINE"|sed -e 's,[-/].*$,,')-unknown-$LIBC$(echo "$UNAME_RELEASE"|sed -e 's,/.*$,,')"
+ exit ;;
+ *:GNU/*:*:*)
+ # other systems with GNU libc and userland
+ echo "$UNAME_MACHINE-unknown-$(echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]")$(echo "$UNAME_RELEASE"|sed -e 's/[-(].*//')-$LIBC"
+ exit ;;
+ *:Minix:*:*)
+ echo "$UNAME_MACHINE"-unknown-minix
+ exit ;;
+ aarch64:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ aarch64_be:Linux:*:*)
+ UNAME_MACHINE=aarch64_be
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ alpha:Linux:*:*)
+ case $(sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null) in
+ EV5) UNAME_MACHINE=alphaev5 ;;
+ EV56) UNAME_MACHINE=alphaev56 ;;
+ PCA56) UNAME_MACHINE=alphapca56 ;;
+ PCA57) UNAME_MACHINE=alphapca56 ;;
+ EV6) UNAME_MACHINE=alphaev6 ;;
+ EV67) UNAME_MACHINE=alphaev67 ;;
+ EV68*) UNAME_MACHINE=alphaev68 ;;
+ esac
+ objdump --private-headers /bin/sh | grep -q ld.so.1
+ if test "$?" = 0 ; then LIBC=gnulibc1 ; fi
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ arc:Linux:*:* | arceb:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ arm*:Linux:*:*)
+ set_cc_for_build
+ if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ARM_EABI__
+ then
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ else
+ if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ARM_PCS_VFP
+ then
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabi
+ else
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabihf
+ fi
+ fi
+ exit ;;
+ avr32*:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ cris:Linux:*:*)
+ echo "$UNAME_MACHINE"-axis-linux-"$LIBC"
+ exit ;;
+ crisv32:Linux:*:*)
+ echo "$UNAME_MACHINE"-axis-linux-"$LIBC"
+ exit ;;
+ e2k:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ frv:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ hexagon:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ i*86:Linux:*:*)
+ echo "$UNAME_MACHINE"-pc-linux-"$LIBC"
+ exit ;;
+ ia64:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ k1om:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ loongarch32:Linux:*:* | loongarch64:Linux:*:* | loongarchx32:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ m32r*:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ m68*:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ mips:Linux:*:* | mips64:Linux:*:*)
+ set_cc_for_build
+ IS_GLIBC=0
+ test x"${LIBC}" = xgnu && IS_GLIBC=1
+ sed 's/^ //' << EOF > "$dummy.c"
+ #undef CPU
+ #undef mips
+ #undef mipsel
+ #undef mips64
+ #undef mips64el
+ #if ${IS_GLIBC} && defined(_ABI64)
+ LIBCABI=gnuabi64
+ #else
+ #if ${IS_GLIBC} && defined(_ABIN32)
+ LIBCABI=gnuabin32
+ #else
+ LIBCABI=${LIBC}
+ #endif
+ #endif
+
+ #if ${IS_GLIBC} && defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6
+ CPU=mipsisa64r6
+ #else
+ #if ${IS_GLIBC} && !defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6
+ CPU=mipsisa32r6
+ #else
+ #if defined(__mips64)
+ CPU=mips64
+ #else
+ CPU=mips
+ #endif
+ #endif
+ #endif
+
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ MIPS_ENDIAN=el
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ MIPS_ENDIAN=
+ #else
+ MIPS_ENDIAN=
+ #endif
+ #endif
+EOF
+ eval "$($CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI')"
+ test "x$CPU" != x && { echo "$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI"; exit; }
+ ;;
+ mips64el:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ openrisc*:Linux:*:*)
+ echo or1k-unknown-linux-"$LIBC"
+ exit ;;
+ or32:Linux:*:* | or1k*:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ padre:Linux:*:*)
+ echo sparc-unknown-linux-"$LIBC"
+ exit ;;
+ parisc64:Linux:*:* | hppa64:Linux:*:*)
+ echo hppa64-unknown-linux-"$LIBC"
+ exit ;;
+ parisc:Linux:*:* | hppa:Linux:*:*)
+ # Look for CPU level
+ case $(grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2) in
+ PA7*) echo hppa1.1-unknown-linux-"$LIBC" ;;
+ PA8*) echo hppa2.0-unknown-linux-"$LIBC" ;;
+ *) echo hppa-unknown-linux-"$LIBC" ;;
+ esac
+ exit ;;
+ ppc64:Linux:*:*)
+ echo powerpc64-unknown-linux-"$LIBC"
+ exit ;;
+ ppc:Linux:*:*)
+ echo powerpc-unknown-linux-"$LIBC"
+ exit ;;
+ ppc64le:Linux:*:*)
+ echo powerpc64le-unknown-linux-"$LIBC"
+ exit ;;
+ ppcle:Linux:*:*)
+ echo powerpcle-unknown-linux-"$LIBC"
+ exit ;;
+ riscv32:Linux:*:* | riscv32be:Linux:*:* | riscv64:Linux:*:* | riscv64be:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ s390:Linux:*:* | s390x:Linux:*:*)
+ echo "$UNAME_MACHINE"-ibm-linux-"$LIBC"
+ exit ;;
+ sh64*:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ sh*:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ sparc:Linux:*:* | sparc64:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ tile*:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ vax:Linux:*:*)
+ echo "$UNAME_MACHINE"-dec-linux-"$LIBC"
+ exit ;;
+ x86_64:Linux:*:*)
+ set_cc_for_build
+ LIBCABI=$LIBC
+ if test "$CC_FOR_BUILD" != no_compiler_found; then
+ if (echo '#ifdef __ILP32__'; echo IS_X32; echo '#endif') | \
+ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_X32 >/dev/null
+ then
+ LIBCABI="$LIBC"x32
+ fi
+ fi
+ echo "$UNAME_MACHINE"-pc-linux-"$LIBCABI"
+ exit ;;
+ xtensa*:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ i*86:DYNIX/ptx:4*:*)
+ # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+ # earlier versions are messed up and put the nodename in both
+ # sysname and nodename.
+ echo i386-sequent-sysv4
+ exit ;;
+ i*86:UNIX_SV:4.2MP:2.*)
+ # Unixware is an offshoot of SVR4, but it has its own version
+ # number series starting with 2...
+ # I am not positive that other SVR4 systems won't match this,
+ # I just have to hope. -- rms.
+ # Use sysv4.2uw... so that sysv4* matches it.
+ echo "$UNAME_MACHINE"-pc-sysv4.2uw"$UNAME_VERSION"
+ exit ;;
+ i*86:OS/2:*:*)
+ # If we were able to find `uname', then EMX Unix compatibility
+ # is probably installed.
+ echo "$UNAME_MACHINE"-pc-os2-emx
+ exit ;;
+ i*86:XTS-300:*:STOP)
+ echo "$UNAME_MACHINE"-unknown-stop
+ exit ;;
+ i*86:atheos:*:*)
+ echo "$UNAME_MACHINE"-unknown-atheos
+ exit ;;
+ i*86:syllable:*:*)
+ echo "$UNAME_MACHINE"-pc-syllable
+ exit ;;
+ i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
+ echo i386-unknown-lynxos"$UNAME_RELEASE"
+ exit ;;
+ i*86:*DOS:*:*)
+ echo "$UNAME_MACHINE"-pc-msdosdjgpp
+ exit ;;
+ i*86:*:4.*:*)
+ UNAME_REL=$(echo "$UNAME_RELEASE" | sed 's/\/MP$//')
+ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+ echo "$UNAME_MACHINE"-univel-sysv"$UNAME_REL"
+ else
+ echo "$UNAME_MACHINE"-pc-sysv"$UNAME_REL"
+ fi
+ exit ;;
+ i*86:*:5:[678]*)
+ # UnixWare 7.x, OpenUNIX and OpenServer 6.
+ case $(/bin/uname -X | grep "^Machine") in
+ *486*) UNAME_MACHINE=i486 ;;
+ *Pentium) UNAME_MACHINE=i586 ;;
+ *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+ esac
+ echo "$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}"
+ exit ;;
+ i*86:*:3.2:*)
+ if test -f /usr/options/cb.name; then
+ UNAME_REL=$(sed -n 's/.*Version //p' </usr/options/cb.name)
+ echo "$UNAME_MACHINE"-pc-isc"$UNAME_REL"
+ elif /bin/uname -X 2>/dev/null >/dev/null ; then
+ UNAME_REL=$( (/bin/uname -X|grep Release|sed -e 's/.*= //'))
+ (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+ && UNAME_MACHINE=i586
+ (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+ && UNAME_MACHINE=i686
+ (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+ && UNAME_MACHINE=i686
+ echo "$UNAME_MACHINE"-pc-sco"$UNAME_REL"
+ else
+ echo "$UNAME_MACHINE"-pc-sysv32
+ fi
+ exit ;;
+ pc:*:*:*)
+ # Left here for compatibility:
+ # uname -m prints for DJGPP always 'pc', but it prints nothing about
+ # the processor, so we play safe by assuming i586.
+ # Note: whatever this is, it MUST be the same as what config.sub
+ # prints for the "djgpp" host, or else GDB configure will decide that
+ # this is a cross-build.
+ echo i586-pc-msdosdjgpp
+ exit ;;
+ Intel:Mach:3*:*)
+ echo i386-pc-mach3
+ exit ;;
+ paragon:*:*:*)
+ echo i860-intel-osf1
+ exit ;;
+ i860:*:4.*:*) # i860-SVR4
+ if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+ echo i860-stardent-sysv"$UNAME_RELEASE" # Stardent Vistra i860-SVR4
+ else # Add other i860-SVR4 vendors below as they are discovered.
+ echo i860-unknown-sysv"$UNAME_RELEASE" # Unknown i860-SVR4
+ fi
+ exit ;;
+ mini*:CTIX:SYS*5:*)
+ # "miniframe"
+ echo m68010-convergent-sysv
+ exit ;;
+ mc68k:UNIX:SYSTEM5:3.51m)
+ echo m68k-convergent-sysv
+ exit ;;
+ M680?0:D-NIX:5.3:*)
+ echo m68k-diab-dnix
+ exit ;;
+ M68*:*:R3V[5678]*:*)
+ test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+ 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+ OS_REL=''
+ test -r /etc/.relid \
+ && OS_REL=.$(sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid)
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;;
+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4; exit; } ;;
+ NCR*:*:4.2:* | MPRAS*:*:4.2:*)
+ OS_REL='.3'
+ test -r /etc/.relid \
+ && OS_REL=.$(sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid)
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
+ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;;
+ m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+ echo m68k-unknown-lynxos"$UNAME_RELEASE"
+ exit ;;
+ mc68030:UNIX_System_V:4.*:*)
+ echo m68k-atari-sysv4
+ exit ;;
+ TSUNAMI:LynxOS:2.*:*)
+ echo sparc-unknown-lynxos"$UNAME_RELEASE"
+ exit ;;
+ rs6000:LynxOS:2.*:*)
+ echo rs6000-unknown-lynxos"$UNAME_RELEASE"
+ exit ;;
+ PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
+ echo powerpc-unknown-lynxos"$UNAME_RELEASE"
+ exit ;;
+ SM[BE]S:UNIX_SV:*:*)
+ echo mips-dde-sysv"$UNAME_RELEASE"
+ exit ;;
+ RM*:ReliantUNIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ RM*:SINIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ *:SINIX-*:*:*)
+ if uname -p 2>/dev/null >/dev/null ; then
+ UNAME_MACHINE=$( (uname -p) 2>/dev/null)
+ echo "$UNAME_MACHINE"-sni-sysv4
+ else
+ echo ns32k-sni-sysv
+ fi
+ exit ;;
+ PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ # says <Richard.M.Bartel@ccMail.Census.GOV>
+ echo i586-unisys-sysv4
+ exit ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes <hewes@openmarket.com>.
+ # How about differentiating between stratus architectures? -djm
+ echo hppa1.1-stratus-sysv4
+ exit ;;
+ *:*:*:FTX*)
+ # From seanf@swdc.stratus.com.
+ echo i860-stratus-sysv4
+ exit ;;
+ i*86:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo "$UNAME_MACHINE"-stratus-vos
+ exit ;;
+ *:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo hppa1.1-stratus-vos
+ exit ;;
+ mc68*:A/UX:*:*)
+ echo m68k-apple-aux"$UNAME_RELEASE"
+ exit ;;
+ news*:NEWS-OS:6*:*)
+ echo mips-sony-newsos6
+ exit ;;
+ R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+ if test -d /usr/nec; then
+ echo mips-nec-sysv"$UNAME_RELEASE"
+ else
+ echo mips-unknown-sysv"$UNAME_RELEASE"
+ fi
+ exit ;;
+ BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
+ echo powerpc-be-beos
+ exit ;;
+ BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
+ echo powerpc-apple-beos
+ exit ;;
+ BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
+ echo i586-pc-beos
+ exit ;;
+ BePC:Haiku:*:*) # Haiku running on Intel PC compatible.
+ echo i586-pc-haiku
+ exit ;;
+ x86_64:Haiku:*:*)
+ echo x86_64-unknown-haiku
+ exit ;;
+ SX-4:SUPER-UX:*:*)
+ echo sx4-nec-superux"$UNAME_RELEASE"
+ exit ;;
+ SX-5:SUPER-UX:*:*)
+ echo sx5-nec-superux"$UNAME_RELEASE"
+ exit ;;
+ SX-6:SUPER-UX:*:*)
+ echo sx6-nec-superux"$UNAME_RELEASE"
+ exit ;;
+ SX-7:SUPER-UX:*:*)
+ echo sx7-nec-superux"$UNAME_RELEASE"
+ exit ;;
+ SX-8:SUPER-UX:*:*)
+ echo sx8-nec-superux"$UNAME_RELEASE"
+ exit ;;
+ SX-8R:SUPER-UX:*:*)
+ echo sx8r-nec-superux"$UNAME_RELEASE"
+ exit ;;
+ SX-ACE:SUPER-UX:*:*)
+ echo sxace-nec-superux"$UNAME_RELEASE"
+ exit ;;
+ Power*:Rhapsody:*:*)
+ echo powerpc-apple-rhapsody"$UNAME_RELEASE"
+ exit ;;
+ *:Rhapsody:*:*)
+ echo "$UNAME_MACHINE"-apple-rhapsody"$UNAME_RELEASE"
+ exit ;;
+ arm64:Darwin:*:*)
+ echo aarch64-apple-darwin"$UNAME_RELEASE"
+ exit ;;
+ *:Darwin:*:*)
+ UNAME_PROCESSOR=$(uname -p)
+ case $UNAME_PROCESSOR in
+ unknown) UNAME_PROCESSOR=powerpc ;;
+ esac
+ if command -v xcode-select > /dev/null 2> /dev/null && \
+ ! xcode-select --print-path > /dev/null 2> /dev/null ; then
+ # Avoid executing cc if there is no toolchain installed as
+ # cc will be a stub that puts up a graphical alert
+ # prompting the user to install developer tools.
+ CC_FOR_BUILD=no_compiler_found
+ else
+ set_cc_for_build
+ fi
+ if test "$CC_FOR_BUILD" != no_compiler_found; then
+ if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
+ then
+ case $UNAME_PROCESSOR in
+ i386) UNAME_PROCESSOR=x86_64 ;;
+ powerpc) UNAME_PROCESSOR=powerpc64 ;;
+ esac
+ fi
+ # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc
+ if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \
+ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_PPC >/dev/null
+ then
+ UNAME_PROCESSOR=powerpc
+ fi
+ elif test "$UNAME_PROCESSOR" = i386 ; then
+ # uname -m returns i386 or x86_64
+ UNAME_PROCESSOR=$UNAME_MACHINE
+ fi
+ echo "$UNAME_PROCESSOR"-apple-darwin"$UNAME_RELEASE"
+ exit ;;
+ *:procnto*:*:* | *:QNX:[0123456789]*:*)
+ UNAME_PROCESSOR=$(uname -p)
+ if test "$UNAME_PROCESSOR" = x86; then
+ UNAME_PROCESSOR=i386
+ UNAME_MACHINE=pc
+ fi
+ echo "$UNAME_PROCESSOR"-"$UNAME_MACHINE"-nto-qnx"$UNAME_RELEASE"
+ exit ;;
+ *:QNX:*:4*)
+ echo i386-pc-qnx
+ exit ;;
+ NEO-*:NONSTOP_KERNEL:*:*)
+ echo neo-tandem-nsk"$UNAME_RELEASE"
+ exit ;;
+ NSE-*:NONSTOP_KERNEL:*:*)
+ echo nse-tandem-nsk"$UNAME_RELEASE"
+ exit ;;
+ NSR-*:NONSTOP_KERNEL:*:*)
+ echo nsr-tandem-nsk"$UNAME_RELEASE"
+ exit ;;
+ NSV-*:NONSTOP_KERNEL:*:*)
+ echo nsv-tandem-nsk"$UNAME_RELEASE"
+ exit ;;
+ NSX-*:NONSTOP_KERNEL:*:*)
+ echo nsx-tandem-nsk"$UNAME_RELEASE"
+ exit ;;
+ *:NonStop-UX:*:*)
+ echo mips-compaq-nonstopux
+ exit ;;
+ BS2000:POSIX*:*:*)
+ echo bs2000-siemens-sysv
+ exit ;;
+ DS/*:UNIX_System_V:*:*)
+ echo "$UNAME_MACHINE"-"$UNAME_SYSTEM"-"$UNAME_RELEASE"
+ exit ;;
+ *:Plan9:*:*)
+ # "uname -m" is not consistent, so use $cputype instead. 386
+ # is converted to i386 for consistency with other x86
+ # operating systems.
+ # shellcheck disable=SC2154
+ if test "$cputype" = 386; then
+ UNAME_MACHINE=i386
+ else
+ UNAME_MACHINE="$cputype"
+ fi
+ echo "$UNAME_MACHINE"-unknown-plan9
+ exit ;;
+ *:TOPS-10:*:*)
+ echo pdp10-unknown-tops10
+ exit ;;
+ *:TENEX:*:*)
+ echo pdp10-unknown-tenex
+ exit ;;
+ KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+ echo pdp10-dec-tops20
+ exit ;;
+ XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+ echo pdp10-xkl-tops20
+ exit ;;
+ *:TOPS-20:*:*)
+ echo pdp10-unknown-tops20
+ exit ;;
+ *:ITS:*:*)
+ echo pdp10-unknown-its
+ exit ;;
+ SEI:*:*:SEIUX)
+ echo mips-sei-seiux"$UNAME_RELEASE"
+ exit ;;
+ *:DragonFly:*:*)
+ echo "$UNAME_MACHINE"-unknown-dragonfly"$(echo "$UNAME_RELEASE"|sed -e 's/[-(].*//')"
+ exit ;;
+ *:*VMS:*:*)
+ UNAME_MACHINE=$( (uname -p) 2>/dev/null)
+ case "$UNAME_MACHINE" in
+ A*) echo alpha-dec-vms ; exit ;;
+ I*) echo ia64-dec-vms ; exit ;;
+ V*) echo vax-dec-vms ; exit ;;
+ esac ;;
+ *:XENIX:*:SysV)
+ echo i386-pc-xenix
+ exit ;;
+ i*86:skyos:*:*)
+ echo "$UNAME_MACHINE"-pc-skyos"$(echo "$UNAME_RELEASE" | sed -e 's/ .*$//')"
+ exit ;;
+ i*86:rdos:*:*)
+ echo "$UNAME_MACHINE"-pc-rdos
+ exit ;;
+ i*86:AROS:*:*)
+ echo "$UNAME_MACHINE"-pc-aros
+ exit ;;
+ x86_64:VMkernel:*:*)
+ echo "$UNAME_MACHINE"-unknown-esx
+ exit ;;
+ amd64:Isilon\ OneFS:*:*)
+ echo x86_64-unknown-onefs
+ exit ;;
+ *:Unleashed:*:*)
+ echo "$UNAME_MACHINE"-unknown-unleashed"$UNAME_RELEASE"
+ exit ;;
+esac
+
+# No uname command or uname output not recognized.
+set_cc_for_build
+cat > "$dummy.c" <<EOF
+#ifdef _SEQUENT_
+#include <sys/types.h>
+#include <sys/utsname.h>
+#endif
+#if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__)
+#if defined (vax) || defined (__vax) || defined (__vax__) || defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__)
+#include <signal.h>
+#if defined(_SIZE_T_) || defined(SIGLOST)
+#include <sys/utsname.h>
+#endif
+#endif
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+ /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
+ I don't know.... */
+ printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+ printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+ "4"
+#else
+ ""
+#endif
+ ); exit (0);
+#endif
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+ int version;
+ version=$( (hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null);
+ if (version < 4)
+ printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+ else
+ printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+ exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+ printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+ printf ("ns32k-encore-mach\n"); exit (0);
+#else
+ printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+ printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+ printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+ printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+ struct utsname un;
+
+ uname(&un);
+ if (strncmp(un.version, "V2", 2) == 0) {
+ printf ("i386-sequent-ptx2\n"); exit (0);
+ }
+ if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+ printf ("i386-sequent-ptx1\n"); exit (0);
+ }
+ printf ("i386-sequent-ptx\n"); exit (0);
+#endif
+
+#if defined (vax)
+#if !defined (ultrix)
+#include <sys/param.h>
+#if defined (BSD)
+#if BSD == 43
+ printf ("vax-dec-bsd4.3\n"); exit (0);
+#else
+#if BSD == 199006
+ printf ("vax-dec-bsd4.3reno\n"); exit (0);
+#else
+ printf ("vax-dec-bsd\n"); exit (0);
+#endif
+#endif
+#else
+ printf ("vax-dec-bsd\n"); exit (0);
+#endif
+#else
+#if defined(_SIZE_T_) || defined(SIGLOST)
+ struct utsname un;
+ uname (&un);
+ printf ("vax-dec-ultrix%s\n", un.release); exit (0);
+#else
+ printf ("vax-dec-ultrix\n"); exit (0);
+#endif
+#endif
+#endif
+#if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__)
+#if defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__)
+#if defined(_SIZE_T_) || defined(SIGLOST)
+ struct utsname *un;
+ uname (&un);
+ printf ("mips-dec-ultrix%s\n", un.release); exit (0);
+#else
+ printf ("mips-dec-ultrix\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (alliant) && defined (i860)
+ printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+ exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=$($dummy) &&
+ { echo "$SYSTEM_NAME"; exit; }
+
+# Apollos put the system type in the environment.
+test -d /usr/apollo && { echo "$ISP-apollo-$SYSTYPE"; exit; }
+
+echo "$0: unable to guess system type" >&2
+
+case "$UNAME_MACHINE:$UNAME_SYSTEM" in
+ mips:Linux | mips64:Linux)
+ # If we got here on MIPS GNU/Linux, output extra information.
+ cat >&2 <<EOF
+
+NOTE: MIPS GNU/Linux systems require a C compiler to fully recognize
+the system type. Please install a C compiler and try again.
+EOF
+ ;;
+esac
+
+cat >&2 <<EOF
+
+This script (version $timestamp), has failed to recognize the
+operating system you are using. If your script is old, overwrite *all*
+copies of config.guess and config.sub with the latest versions from:
+
+ https://git.savannah.gnu.org/cgit/config.git/plain/config.guess
+and
+ https://git.savannah.gnu.org/cgit/config.git/plain/config.sub
+EOF
+
+year=$(echo $timestamp | sed 's,-.*,,')
+# shellcheck disable=SC2003
+if test "$(expr "$(date +%Y)" - "$year")" -lt 3 ; then
+ cat >&2 <<EOF
+
+If $0 has already been updated, send the following data and any
+information you think might be pertinent to config-patches@gnu.org to
+provide the necessary information to handle your system.
+
+config.guess timestamp = $timestamp
+
+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)
+/bin/uname -X = $( (/bin/uname -X) 2>/dev/null)
+
+hostinfo = $( (hostinfo) 2>/dev/null)
+/bin/universe = $( (/bin/universe) 2>/dev/null)
+/usr/bin/arch -k = $( (/usr/bin/arch -k) 2>/dev/null)
+/bin/arch = $( (/bin/arch) 2>/dev/null)
+/usr/bin/oslevel = $( (/usr/bin/oslevel) 2>/dev/null)
+/usr/convex/getsysinfo = $( (/usr/convex/getsysinfo) 2>/dev/null)
+
+UNAME_MACHINE = "$UNAME_MACHINE"
+UNAME_RELEASE = "$UNAME_RELEASE"
+UNAME_SYSTEM = "$UNAME_SYSTEM"
+UNAME_VERSION = "$UNAME_VERSION"
+EOF
+fi
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'before-save-hook 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/config.sub b/config.sub
new file mode 100644
index 0000000..0cbdae6
--- /dev/null
+++ b/config.sub
@@ -0,0 +1,1855 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+# Copyright 1992-2021 Free Software Foundation, Inc.
+
+timestamp='2021-01-01'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <https://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that
+# program. This Exception is an additional permission under section 7
+# of the GNU General Public License, version 3 ("GPLv3").
+
+
+# Please send patches to <config-patches@gnu.org>.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# You can get the latest version of this script from:
+# https://git.savannah.gnu.org/cgit/config.git/plain/config.sub
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support. The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=$(echo "$0" | sed -e 's,.*/,,')
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS
+
+Canonicalize a configuration name.
+
+Options:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright 1992-2021 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help" >&2
+ exit 1 ;;
+
+ *local*)
+ # First pass through any local machine types.
+ echo "$1"
+ exit ;;
+
+ * )
+ break ;;
+ esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+ exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+ exit 1;;
+esac
+
+# Split fields of configuration type
+# shellcheck disable=SC2162
+IFS="-" read field1 field2 field3 field4 <<EOF
+$1
+EOF
+
+# Separate into logical components for further validation
+case $1 in
+ *-*-*-*-*)
+ echo Invalid configuration \`"$1"\': more than four components >&2
+ exit 1
+ ;;
+ *-*-*-*)
+ basic_machine=$field1-$field2
+ basic_os=$field3-$field4
+ ;;
+ *-*-*)
+ # Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two
+ # parts
+ maybe_os=$field2-$field3
+ case $maybe_os in
+ nto-qnx* | linux-* | uclinux-uclibc* \
+ | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \
+ | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \
+ | storm-chaos* | os2-emx* | rtmk-nova*)
+ basic_machine=$field1
+ basic_os=$maybe_os
+ ;;
+ android-linux)
+ basic_machine=$field1-unknown
+ basic_os=linux-android
+ ;;
+ *)
+ basic_machine=$field1-$field2
+ basic_os=$field3
+ ;;
+ esac
+ ;;
+ *-*)
+ # A lone config we happen to match not fitting any pattern
+ case $field1-$field2 in
+ decstation-3100)
+ basic_machine=mips-dec
+ basic_os=
+ ;;
+ *-*)
+ # Second component is usually, but not always the OS
+ case $field2 in
+ # Prevent following clause from handling this valid os
+ sun*os*)
+ basic_machine=$field1
+ basic_os=$field2
+ ;;
+ # Manufacturers
+ dec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \
+ | att* | 7300* | 3300* | delta* | motorola* | sun[234]* \
+ | unicom* | ibm* | next | hp | isi* | apollo | altos* \
+ | convergent* | ncr* | news | 32* | 3600* | 3100* \
+ | hitachi* | c[123]* | convex* | sun | crds | omron* | dg \
+ | ultra | tti* | harris | dolphin | highlevel | gould \
+ | cbm | ns | masscomp | apple | axis | knuth | cray \
+ | microblaze* | sim | cisco \
+ | oki | wec | wrs | winbond)
+ basic_machine=$field1-$field2
+ basic_os=
+ ;;
+ *)
+ basic_machine=$field1
+ basic_os=$field2
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+ *)
+ # Convert single-component short-hands not valid as part of
+ # multi-component configurations.
+ case $field1 in
+ 386bsd)
+ basic_machine=i386-pc
+ basic_os=bsd
+ ;;
+ a29khif)
+ basic_machine=a29k-amd
+ basic_os=udi
+ ;;
+ adobe68k)
+ basic_machine=m68010-adobe
+ basic_os=scout
+ ;;
+ alliant)
+ basic_machine=fx80-alliant
+ basic_os=
+ ;;
+ altos | altos3068)
+ basic_machine=m68k-altos
+ basic_os=
+ ;;
+ am29k)
+ basic_machine=a29k-none
+ basic_os=bsd
+ ;;
+ amdahl)
+ basic_machine=580-amdahl
+ basic_os=sysv
+ ;;
+ amiga)
+ basic_machine=m68k-unknown
+ basic_os=
+ ;;
+ amigaos | amigados)
+ basic_machine=m68k-unknown
+ basic_os=amigaos
+ ;;
+ amigaunix | amix)
+ basic_machine=m68k-unknown
+ basic_os=sysv4
+ ;;
+ apollo68)
+ basic_machine=m68k-apollo
+ basic_os=sysv
+ ;;
+ apollo68bsd)
+ basic_machine=m68k-apollo
+ basic_os=bsd
+ ;;
+ aros)
+ basic_machine=i386-pc
+ basic_os=aros
+ ;;
+ aux)
+ basic_machine=m68k-apple
+ basic_os=aux
+ ;;
+ balance)
+ basic_machine=ns32k-sequent
+ basic_os=dynix
+ ;;
+ blackfin)
+ basic_machine=bfin-unknown
+ basic_os=linux
+ ;;
+ cegcc)
+ basic_machine=arm-unknown
+ basic_os=cegcc
+ ;;
+ convex-c1)
+ basic_machine=c1-convex
+ basic_os=bsd
+ ;;
+ convex-c2)
+ basic_machine=c2-convex
+ basic_os=bsd
+ ;;
+ convex-c32)
+ basic_machine=c32-convex
+ basic_os=bsd
+ ;;
+ convex-c34)
+ basic_machine=c34-convex
+ basic_os=bsd
+ ;;
+ convex-c38)
+ basic_machine=c38-convex
+ basic_os=bsd
+ ;;
+ cray)
+ basic_machine=j90-cray
+ basic_os=unicos
+ ;;
+ crds | unos)
+ basic_machine=m68k-crds
+ basic_os=
+ ;;
+ da30)
+ basic_machine=m68k-da30
+ basic_os=
+ ;;
+ decstation | pmax | pmin | dec3100 | decstatn)
+ basic_machine=mips-dec
+ basic_os=
+ ;;
+ delta88)
+ basic_machine=m88k-motorola
+ basic_os=sysv3
+ ;;
+ dicos)
+ basic_machine=i686-pc
+ basic_os=dicos
+ ;;
+ djgpp)
+ basic_machine=i586-pc
+ basic_os=msdosdjgpp
+ ;;
+ ebmon29k)
+ basic_machine=a29k-amd
+ basic_os=ebmon
+ ;;
+ es1800 | OSE68k | ose68k | ose | OSE)
+ basic_machine=m68k-ericsson
+ basic_os=ose
+ ;;
+ gmicro)
+ basic_machine=tron-gmicro
+ basic_os=sysv
+ ;;
+ go32)
+ basic_machine=i386-pc
+ basic_os=go32
+ ;;
+ h8300hms)
+ basic_machine=h8300-hitachi
+ basic_os=hms
+ ;;
+ h8300xray)
+ basic_machine=h8300-hitachi
+ basic_os=xray
+ ;;
+ h8500hms)
+ basic_machine=h8500-hitachi
+ basic_os=hms
+ ;;
+ harris)
+ basic_machine=m88k-harris
+ basic_os=sysv3
+ ;;
+ hp300 | hp300hpux)
+ basic_machine=m68k-hp
+ basic_os=hpux
+ ;;
+ hp300bsd)
+ basic_machine=m68k-hp
+ basic_os=bsd
+ ;;
+ hppaosf)
+ basic_machine=hppa1.1-hp
+ basic_os=osf
+ ;;
+ hppro)
+ basic_machine=hppa1.1-hp
+ basic_os=proelf
+ ;;
+ i386mach)
+ basic_machine=i386-mach
+ basic_os=mach
+ ;;
+ isi68 | isi)
+ basic_machine=m68k-isi
+ basic_os=sysv
+ ;;
+ m68knommu)
+ basic_machine=m68k-unknown
+ basic_os=linux
+ ;;
+ magnum | m3230)
+ basic_machine=mips-mips
+ basic_os=sysv
+ ;;
+ merlin)
+ basic_machine=ns32k-utek
+ basic_os=sysv
+ ;;
+ mingw64)
+ basic_machine=x86_64-pc
+ basic_os=mingw64
+ ;;
+ mingw32)
+ basic_machine=i686-pc
+ basic_os=mingw32
+ ;;
+ mingw32ce)
+ basic_machine=arm-unknown
+ basic_os=mingw32ce
+ ;;
+ monitor)
+ basic_machine=m68k-rom68k
+ basic_os=coff
+ ;;
+ morphos)
+ basic_machine=powerpc-unknown
+ basic_os=morphos
+ ;;
+ moxiebox)
+ basic_machine=moxie-unknown
+ basic_os=moxiebox
+ ;;
+ msdos)
+ basic_machine=i386-pc
+ basic_os=msdos
+ ;;
+ msys)
+ basic_machine=i686-pc
+ basic_os=msys
+ ;;
+ mvs)
+ basic_machine=i370-ibm
+ basic_os=mvs
+ ;;
+ nacl)
+ basic_machine=le32-unknown
+ basic_os=nacl
+ ;;
+ ncr3000)
+ basic_machine=i486-ncr
+ basic_os=sysv4
+ ;;
+ netbsd386)
+ basic_machine=i386-pc
+ basic_os=netbsd
+ ;;
+ netwinder)
+ basic_machine=armv4l-rebel
+ basic_os=linux
+ ;;
+ news | news700 | news800 | news900)
+ basic_machine=m68k-sony
+ basic_os=newsos
+ ;;
+ news1000)
+ basic_machine=m68030-sony
+ basic_os=newsos
+ ;;
+ necv70)
+ basic_machine=v70-nec
+ basic_os=sysv
+ ;;
+ nh3000)
+ basic_machine=m68k-harris
+ basic_os=cxux
+ ;;
+ nh[45]000)
+ basic_machine=m88k-harris
+ basic_os=cxux
+ ;;
+ nindy960)
+ basic_machine=i960-intel
+ basic_os=nindy
+ ;;
+ mon960)
+ basic_machine=i960-intel
+ basic_os=mon960
+ ;;
+ nonstopux)
+ basic_machine=mips-compaq
+ basic_os=nonstopux
+ ;;
+ os400)
+ basic_machine=powerpc-ibm
+ basic_os=os400
+ ;;
+ OSE68000 | ose68000)
+ basic_machine=m68000-ericsson
+ basic_os=ose
+ ;;
+ os68k)
+ basic_machine=m68k-none
+ basic_os=os68k
+ ;;
+ paragon)
+ basic_machine=i860-intel
+ basic_os=osf
+ ;;
+ parisc)
+ basic_machine=hppa-unknown
+ basic_os=linux
+ ;;
+ psp)
+ basic_machine=mipsallegrexel-sony
+ basic_os=psp
+ ;;
+ pw32)
+ basic_machine=i586-unknown
+ basic_os=pw32
+ ;;
+ rdos | rdos64)
+ basic_machine=x86_64-pc
+ basic_os=rdos
+ ;;
+ rdos32)
+ basic_machine=i386-pc
+ basic_os=rdos
+ ;;
+ rom68k)
+ basic_machine=m68k-rom68k
+ basic_os=coff
+ ;;
+ sa29200)
+ basic_machine=a29k-amd
+ basic_os=udi
+ ;;
+ sei)
+ basic_machine=mips-sei
+ basic_os=seiux
+ ;;
+ sequent)
+ basic_machine=i386-sequent
+ basic_os=
+ ;;
+ sps7)
+ basic_machine=m68k-bull
+ basic_os=sysv2
+ ;;
+ st2000)
+ basic_machine=m68k-tandem
+ basic_os=
+ ;;
+ stratus)
+ basic_machine=i860-stratus
+ basic_os=sysv4
+ ;;
+ sun2)
+ basic_machine=m68000-sun
+ basic_os=
+ ;;
+ sun2os3)
+ basic_machine=m68000-sun
+ basic_os=sunos3
+ ;;
+ sun2os4)
+ basic_machine=m68000-sun
+ basic_os=sunos4
+ ;;
+ sun3)
+ basic_machine=m68k-sun
+ basic_os=
+ ;;
+ sun3os3)
+ basic_machine=m68k-sun
+ basic_os=sunos3
+ ;;
+ sun3os4)
+ basic_machine=m68k-sun
+ basic_os=sunos4
+ ;;
+ sun4)
+ basic_machine=sparc-sun
+ basic_os=
+ ;;
+ sun4os3)
+ basic_machine=sparc-sun
+ basic_os=sunos3
+ ;;
+ sun4os4)
+ basic_machine=sparc-sun
+ basic_os=sunos4
+ ;;
+ sun4sol2)
+ basic_machine=sparc-sun
+ basic_os=solaris2
+ ;;
+ sun386 | sun386i | roadrunner)
+ basic_machine=i386-sun
+ basic_os=
+ ;;
+ sv1)
+ basic_machine=sv1-cray
+ basic_os=unicos
+ ;;
+ symmetry)
+ basic_machine=i386-sequent
+ basic_os=dynix
+ ;;
+ t3e)
+ basic_machine=alphaev5-cray
+ basic_os=unicos
+ ;;
+ t90)
+ basic_machine=t90-cray
+ basic_os=unicos
+ ;;
+ toad1)
+ basic_machine=pdp10-xkl
+ basic_os=tops20
+ ;;
+ tpf)
+ basic_machine=s390x-ibm
+ basic_os=tpf
+ ;;
+ udi29k)
+ basic_machine=a29k-amd
+ basic_os=udi
+ ;;
+ ultra3)
+ basic_machine=a29k-nyu
+ basic_os=sym1
+ ;;
+ v810 | necv810)
+ basic_machine=v810-nec
+ basic_os=none
+ ;;
+ vaxv)
+ basic_machine=vax-dec
+ basic_os=sysv
+ ;;
+ vms)
+ basic_machine=vax-dec
+ basic_os=vms
+ ;;
+ vsta)
+ basic_machine=i386-pc
+ basic_os=vsta
+ ;;
+ vxworks960)
+ basic_machine=i960-wrs
+ basic_os=vxworks
+ ;;
+ vxworks68)
+ basic_machine=m68k-wrs
+ basic_os=vxworks
+ ;;
+ vxworks29k)
+ basic_machine=a29k-wrs
+ basic_os=vxworks
+ ;;
+ xbox)
+ basic_machine=i686-pc
+ basic_os=mingw32
+ ;;
+ ymp)
+ basic_machine=ymp-cray
+ basic_os=unicos
+ ;;
+ *)
+ basic_machine=$1
+ basic_os=
+ ;;
+ esac
+ ;;
+esac
+
+# Decode 1-component or ad-hoc basic machines
+case $basic_machine in
+ # Here we handle the default manufacturer of certain CPU types. It is in
+ # some cases the only manufacturer, in others, it is the most popular.
+ w89k)
+ cpu=hppa1.1
+ vendor=winbond
+ ;;
+ op50n)
+ cpu=hppa1.1
+ vendor=oki
+ ;;
+ op60c)
+ cpu=hppa1.1
+ vendor=oki
+ ;;
+ ibm*)
+ cpu=i370
+ vendor=ibm
+ ;;
+ orion105)
+ cpu=clipper
+ vendor=highlevel
+ ;;
+ mac | mpw | mac-mpw)
+ cpu=m68k
+ vendor=apple
+ ;;
+ pmac | pmac-mpw)
+ cpu=powerpc
+ vendor=apple
+ ;;
+
+ # Recognize the various machine names and aliases which stand
+ # for a CPU type and a company and sometimes even an OS.
+ 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+ cpu=m68000
+ vendor=att
+ ;;
+ 3b*)
+ cpu=we32k
+ vendor=att
+ ;;
+ bluegene*)
+ cpu=powerpc
+ vendor=ibm
+ basic_os=cnk
+ ;;
+ decsystem10* | dec10*)
+ cpu=pdp10
+ vendor=dec
+ basic_os=tops10
+ ;;
+ decsystem20* | dec20*)
+ cpu=pdp10
+ vendor=dec
+ basic_os=tops20
+ ;;
+ delta | 3300 | motorola-3300 | motorola-delta \
+ | 3300-motorola | delta-motorola)
+ cpu=m68k
+ vendor=motorola
+ ;;
+ dpx2*)
+ cpu=m68k
+ vendor=bull
+ basic_os=sysv3
+ ;;
+ encore | umax | mmax)
+ cpu=ns32k
+ vendor=encore
+ ;;
+ elxsi)
+ cpu=elxsi
+ vendor=elxsi
+ basic_os=${basic_os:-bsd}
+ ;;
+ fx2800)
+ cpu=i860
+ vendor=alliant
+ ;;
+ genix)
+ cpu=ns32k
+ vendor=ns
+ ;;
+ h3050r* | hiux*)
+ cpu=hppa1.1
+ vendor=hitachi
+ basic_os=hiuxwe2
+ ;;
+ hp3k9[0-9][0-9] | hp9[0-9][0-9])
+ cpu=hppa1.0
+ vendor=hp
+ ;;
+ hp9k2[0-9][0-9] | hp9k31[0-9])
+ cpu=m68000
+ vendor=hp
+ ;;
+ hp9k3[2-9][0-9])
+ cpu=m68k
+ vendor=hp
+ ;;
+ hp9k6[0-9][0-9] | hp6[0-9][0-9])
+ cpu=hppa1.0
+ vendor=hp
+ ;;
+ hp9k7[0-79][0-9] | hp7[0-79][0-9])
+ cpu=hppa1.1
+ vendor=hp
+ ;;
+ hp9k78[0-9] | hp78[0-9])
+ # FIXME: really hppa2.0-hp
+ cpu=hppa1.1
+ vendor=hp
+ ;;
+ hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+ # FIXME: really hppa2.0-hp
+ cpu=hppa1.1
+ vendor=hp
+ ;;
+ hp9k8[0-9][13679] | hp8[0-9][13679])
+ cpu=hppa1.1
+ vendor=hp
+ ;;
+ hp9k8[0-9][0-9] | hp8[0-9][0-9])
+ cpu=hppa1.0
+ vendor=hp
+ ;;
+ i*86v32)
+ cpu=$(echo "$1" | sed -e 's/86.*/86/')
+ vendor=pc
+ basic_os=sysv32
+ ;;
+ i*86v4*)
+ cpu=$(echo "$1" | sed -e 's/86.*/86/')
+ vendor=pc
+ basic_os=sysv4
+ ;;
+ i*86v)
+ cpu=$(echo "$1" | sed -e 's/86.*/86/')
+ vendor=pc
+ basic_os=sysv
+ ;;
+ i*86sol2)
+ cpu=$(echo "$1" | sed -e 's/86.*/86/')
+ vendor=pc
+ basic_os=solaris2
+ ;;
+ j90 | j90-cray)
+ cpu=j90
+ vendor=cray
+ basic_os=${basic_os:-unicos}
+ ;;
+ iris | iris4d)
+ cpu=mips
+ vendor=sgi
+ case $basic_os in
+ irix*)
+ ;;
+ *)
+ basic_os=irix4
+ ;;
+ esac
+ ;;
+ miniframe)
+ cpu=m68000
+ vendor=convergent
+ ;;
+ *mint | mint[0-9]* | *MiNT | *MiNT[0-9]*)
+ cpu=m68k
+ vendor=atari
+ basic_os=mint
+ ;;
+ news-3600 | risc-news)
+ cpu=mips
+ vendor=sony
+ basic_os=newsos
+ ;;
+ next | m*-next)
+ cpu=m68k
+ vendor=next
+ case $basic_os in
+ openstep*)
+ ;;
+ nextstep*)
+ ;;
+ ns2*)
+ basic_os=nextstep2
+ ;;
+ *)
+ basic_os=nextstep3
+ ;;
+ esac
+ ;;
+ np1)
+ cpu=np1
+ vendor=gould
+ ;;
+ op50n-* | op60c-*)
+ cpu=hppa1.1
+ vendor=oki
+ basic_os=proelf
+ ;;
+ pa-hitachi)
+ cpu=hppa1.1
+ vendor=hitachi
+ basic_os=hiuxwe2
+ ;;
+ pbd)
+ cpu=sparc
+ vendor=tti
+ ;;
+ pbb)
+ cpu=m68k
+ vendor=tti
+ ;;
+ pc532)
+ cpu=ns32k
+ vendor=pc532
+ ;;
+ pn)
+ cpu=pn
+ vendor=gould
+ ;;
+ power)
+ cpu=power
+ vendor=ibm
+ ;;
+ ps2)
+ cpu=i386
+ vendor=ibm
+ ;;
+ rm[46]00)
+ cpu=mips
+ vendor=siemens
+ ;;
+ rtpc | rtpc-*)
+ cpu=romp
+ vendor=ibm
+ ;;
+ sde)
+ cpu=mipsisa32
+ vendor=sde
+ basic_os=${basic_os:-elf}
+ ;;
+ simso-wrs)
+ cpu=sparclite
+ vendor=wrs
+ basic_os=vxworks
+ ;;
+ tower | tower-32)
+ cpu=m68k
+ vendor=ncr
+ ;;
+ vpp*|vx|vx-*)
+ cpu=f301
+ vendor=fujitsu
+ ;;
+ w65)
+ cpu=w65
+ vendor=wdc
+ ;;
+ w89k-*)
+ cpu=hppa1.1
+ vendor=winbond
+ basic_os=proelf
+ ;;
+ none)
+ cpu=none
+ vendor=none
+ ;;
+ leon|leon[3-9])
+ cpu=sparc
+ vendor=$basic_machine
+ ;;
+ leon-*|leon[3-9]-*)
+ cpu=sparc
+ vendor=$(echo "$basic_machine" | sed 's/-.*//')
+ ;;
+
+ *-*)
+ # shellcheck disable=SC2162
+ IFS="-" read cpu vendor <<EOF
+$basic_machine
+EOF
+ ;;
+ # We use `pc' rather than `unknown'
+ # because (1) that's what they normally are, and
+ # (2) the word "unknown" tends to confuse beginning users.
+ i*86 | x86_64)
+ cpu=$basic_machine
+ vendor=pc
+ ;;
+ # These rules are duplicated from below for sake of the special case above;
+ # i.e. things that normalized to x86 arches should also default to "pc"
+ pc98)
+ cpu=i386
+ vendor=pc
+ ;;
+ x64 | amd64)
+ cpu=x86_64
+ vendor=pc
+ ;;
+ # Recognize the basic CPU types without company name.
+ *)
+ cpu=$basic_machine
+ vendor=unknown
+ ;;
+esac
+
+unset -v basic_machine
+
+# Decode basic machines in the full and proper CPU-Company form.
+case $cpu-$vendor in
+ # Here we handle the default manufacturer of certain CPU types in canonical form. It is in
+ # some cases the only manufacturer, in others, it is the most popular.
+ craynv-unknown)
+ vendor=cray
+ basic_os=${basic_os:-unicosmp}
+ ;;
+ c90-unknown | c90-cray)
+ vendor=cray
+ basic_os=${Basic_os:-unicos}
+ ;;
+ fx80-unknown)
+ vendor=alliant
+ ;;
+ romp-unknown)
+ vendor=ibm
+ ;;
+ mmix-unknown)
+ vendor=knuth
+ ;;
+ microblaze-unknown | microblazeel-unknown)
+ vendor=xilinx
+ ;;
+ rs6000-unknown)
+ vendor=ibm
+ ;;
+ vax-unknown)
+ vendor=dec
+ ;;
+ pdp11-unknown)
+ vendor=dec
+ ;;
+ we32k-unknown)
+ vendor=att
+ ;;
+ cydra-unknown)
+ vendor=cydrome
+ ;;
+ i370-ibm*)
+ vendor=ibm
+ ;;
+ orion-unknown)
+ vendor=highlevel
+ ;;
+ xps-unknown | xps100-unknown)
+ cpu=xps100
+ vendor=honeywell
+ ;;
+
+ # Here we normalize CPU types with a missing or matching vendor
+ dpx20-unknown | dpx20-bull)
+ cpu=rs6000
+ vendor=bull
+ basic_os=${basic_os:-bosx}
+ ;;
+
+ # Here we normalize CPU types irrespective of the vendor
+ amd64-*)
+ cpu=x86_64
+ ;;
+ blackfin-*)
+ cpu=bfin
+ basic_os=linux
+ ;;
+ c54x-*)
+ cpu=tic54x
+ ;;
+ c55x-*)
+ cpu=tic55x
+ ;;
+ c6x-*)
+ cpu=tic6x
+ ;;
+ e500v[12]-*)
+ cpu=powerpc
+ basic_os=${basic_os}"spe"
+ ;;
+ mips3*-*)
+ cpu=mips64
+ ;;
+ ms1-*)
+ cpu=mt
+ ;;
+ m68knommu-*)
+ cpu=m68k
+ basic_os=linux
+ ;;
+ m9s12z-* | m68hcs12z-* | hcs12z-* | s12z-*)
+ cpu=s12z
+ ;;
+ openrisc-*)
+ cpu=or32
+ ;;
+ parisc-*)
+ cpu=hppa
+ basic_os=linux
+ ;;
+ pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+ cpu=i586
+ ;;
+ pentiumpro-* | p6-* | 6x86-* | athlon-* | athalon_*-*)
+ cpu=i686
+ ;;
+ pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+ cpu=i686
+ ;;
+ pentium4-*)
+ cpu=i786
+ ;;
+ pc98-*)
+ cpu=i386
+ ;;
+ ppc-* | ppcbe-*)
+ cpu=powerpc
+ ;;
+ ppcle-* | powerpclittle-*)
+ cpu=powerpcle
+ ;;
+ ppc64-*)
+ cpu=powerpc64
+ ;;
+ ppc64le-* | powerpc64little-*)
+ cpu=powerpc64le
+ ;;
+ sb1-*)
+ cpu=mipsisa64sb1
+ ;;
+ sb1el-*)
+ cpu=mipsisa64sb1el
+ ;;
+ sh5e[lb]-*)
+ cpu=$(echo "$cpu" | sed 's/^\(sh.\)e\(.\)$/\1\2e/')
+ ;;
+ spur-*)
+ cpu=spur
+ ;;
+ strongarm-* | thumb-*)
+ cpu=arm
+ ;;
+ tx39-*)
+ cpu=mipstx39
+ ;;
+ tx39el-*)
+ cpu=mipstx39el
+ ;;
+ x64-*)
+ cpu=x86_64
+ ;;
+ xscale-* | xscalee[bl]-*)
+ cpu=$(echo "$cpu" | sed 's/^xscale/arm/')
+ ;;
+ arm64-*)
+ cpu=aarch64
+ ;;
+
+ # Recognize the canonical CPU Types that limit and/or modify the
+ # company names they are paired with.
+ cr16-*)
+ basic_os=${basic_os:-elf}
+ ;;
+ crisv32-* | etraxfs*-*)
+ cpu=crisv32
+ vendor=axis
+ ;;
+ cris-* | etrax*-*)
+ cpu=cris
+ vendor=axis
+ ;;
+ crx-*)
+ basic_os=${basic_os:-elf}
+ ;;
+ neo-tandem)
+ cpu=neo
+ vendor=tandem
+ ;;
+ nse-tandem)
+ cpu=nse
+ vendor=tandem
+ ;;
+ nsr-tandem)
+ cpu=nsr
+ vendor=tandem
+ ;;
+ nsv-tandem)
+ cpu=nsv
+ vendor=tandem
+ ;;
+ nsx-tandem)
+ cpu=nsx
+ vendor=tandem
+ ;;
+ mipsallegrexel-sony)
+ cpu=mipsallegrexel
+ vendor=sony
+ ;;
+ tile*-*)
+ basic_os=${basic_os:-linux-gnu}
+ ;;
+
+ *)
+ # Recognize the canonical CPU types that are allowed with any
+ # company name.
+ case $cpu in
+ 1750a | 580 \
+ | a29k \
+ | aarch64 | aarch64_be \
+ | abacus \
+ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] \
+ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] \
+ | alphapca5[67] | alpha64pca5[67] \
+ | am33_2.0 \
+ | amdgcn \
+ | arc | arceb \
+ | arm | arm[lb]e | arme[lb] | armv* \
+ | avr | avr32 \
+ | asmjs \
+ | ba \
+ | be32 | be64 \
+ | bfin | bpf | bs2000 \
+ | c[123]* | c30 | [cjt]90 | c4x \
+ | c8051 | clipper | craynv | csky | cydra \
+ | d10v | d30v | dlx | dsp16xx \
+ | e2k | elxsi | epiphany \
+ | f30[01] | f700 | fido | fr30 | frv | ft32 | fx80 \
+ | h8300 | h8500 \
+ | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+ | hexagon \
+ | i370 | i*86 | i860 | i960 | ia16 | ia64 \
+ | ip2k | iq2000 \
+ | k1om \
+ | le32 | le64 \
+ | lm32 \
+ | loongarch32 | loongarch64 | loongarchx32 \
+ | m32c | m32r | m32rle \
+ | m5200 | m68000 | m680[012346]0 | m68360 | m683?2 | m68k \
+ | m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x \
+ | m88110 | m88k | maxq | mb | mcore | mep | metag \
+ | microblaze | microblazeel \
+ | mips | mipsbe | mipseb | mipsel | mipsle \
+ | mips16 \
+ | mips64 | mips64eb | mips64el \
+ | mips64octeon | mips64octeonel \
+ | mips64orion | mips64orionel \
+ | mips64r5900 | mips64r5900el \
+ | mips64vr | mips64vrel \
+ | mips64vr4100 | mips64vr4100el \
+ | mips64vr4300 | mips64vr4300el \
+ | mips64vr5000 | mips64vr5000el \
+ | mips64vr5900 | mips64vr5900el \
+ | mipsisa32 | mipsisa32el \
+ | mipsisa32r2 | mipsisa32r2el \
+ | mipsisa32r6 | mipsisa32r6el \
+ | mipsisa64 | mipsisa64el \
+ | mipsisa64r2 | mipsisa64r2el \
+ | mipsisa64r6 | mipsisa64r6el \
+ | mipsisa64sb1 | mipsisa64sb1el \
+ | mipsisa64sr71k | mipsisa64sr71kel \
+ | mipsr5900 | mipsr5900el \
+ | mipstx39 | mipstx39el \
+ | mmix \
+ | mn10200 | mn10300 \
+ | moxie \
+ | mt \
+ | msp430 \
+ | nds32 | nds32le | nds32be \
+ | nfp \
+ | nios | nios2 | nios2eb | nios2el \
+ | none | np1 | ns16k | ns32k | nvptx \
+ | open8 \
+ | or1k* \
+ | or32 \
+ | orion \
+ | picochip \
+ | pdp10 | pdp11 | pj | pjl | pn | power \
+ | powerpc | powerpc64 | powerpc64le | powerpcle | powerpcspe \
+ | pru \
+ | pyramid \
+ | riscv | riscv32 | riscv32be | riscv64 | riscv64be \
+ | rl78 | romp | rs6000 | rx \
+ | s390 | s390x \
+ | score \
+ | sh | shl \
+ | sh[1234] | sh[24]a | sh[24]ae[lb] | sh[23]e | she[lb] | sh[lb]e \
+ | sh[1234]e[lb] | sh[12345][lb]e | sh[23]ele | sh64 | sh64le \
+ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet \
+ | sparclite \
+ | sparcv8 | sparcv9 | sparcv9b | sparcv9v | sv1 | sx* \
+ | spu \
+ | tahoe \
+ | thumbv7* \
+ | tic30 | tic4x | tic54x | tic55x | tic6x | tic80 \
+ | tron \
+ | ubicom32 \
+ | v70 | v850 | v850e | v850e1 | v850es | v850e2 | v850e2v3 \
+ | vax \
+ | visium \
+ | w65 \
+ | wasm32 | wasm64 \
+ | we32k \
+ | x86 | x86_64 | xc16x | xgate | xps100 \
+ | xstormy16 | xtensa* \
+ | ymp \
+ | z8k | z80)
+ ;;
+
+ *)
+ echo Invalid configuration \`"$1"\': machine \`"$cpu-$vendor"\' not recognized 1>&2
+ exit 1
+ ;;
+ esac
+ ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $vendor in
+ digital*)
+ vendor=dec
+ ;;
+ commodore*)
+ vendor=cbm
+ ;;
+ *)
+ ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if test x$basic_os != x
+then
+
+# First recognize some ad-hoc caes, or perhaps split kernel-os, or else just
+# set os.
+case $basic_os in
+ gnu/linux*)
+ kernel=linux
+ os=$(echo $basic_os | sed -e 's|gnu/linux|gnu|')
+ ;;
+ os2-emx)
+ kernel=os2
+ os=$(echo $basic_os | sed -e 's|os2-emx|emx|')
+ ;;
+ nto-qnx*)
+ kernel=nto
+ os=$(echo $basic_os | sed -e 's|nto-qnx|qnx|')
+ ;;
+ *-*)
+ # shellcheck disable=SC2162
+ IFS="-" read kernel os <<EOF
+$basic_os
+EOF
+ ;;
+ # Default OS when just kernel was specified
+ nto*)
+ kernel=nto
+ os=$(echo $basic_os | sed -e 's|nto|qnx|')
+ ;;
+ linux*)
+ kernel=linux
+ os=$(echo $basic_os | sed -e 's|linux|gnu|')
+ ;;
+ *)
+ kernel=
+ os=$basic_os
+ ;;
+esac
+
+# Now, normalize the OS (knowing we just have one component, it's not a kernel,
+# etc.)
+case $os in
+ # First match some system type aliases that might get confused
+ # with valid system types.
+ # solaris* is a basic system type, with this one exception.
+ auroraux)
+ os=auroraux
+ ;;
+ bluegene*)
+ os=cnk
+ ;;
+ solaris1 | solaris1.*)
+ os=$(echo $os | sed -e 's|solaris1|sunos4|')
+ ;;
+ solaris)
+ os=solaris2
+ ;;
+ unixware*)
+ os=sysv4.2uw
+ ;;
+ # es1800 is here to avoid being matched by es* (a different OS)
+ es1800*)
+ os=ose
+ ;;
+ # Some version numbers need modification
+ chorusos*)
+ os=chorusos
+ ;;
+ isc)
+ os=isc2.2
+ ;;
+ sco6)
+ os=sco5v6
+ ;;
+ sco5)
+ os=sco3.2v5
+ ;;
+ sco4)
+ os=sco3.2v4
+ ;;
+ sco3.2.[4-9]*)
+ os=$(echo $os | sed -e 's/sco3.2./sco3.2v/')
+ ;;
+ sco*v* | scout)
+ # Don't match below
+ ;;
+ sco*)
+ os=sco3.2v2
+ ;;
+ psos*)
+ os=psos
+ ;;
+ qnx*)
+ os=qnx
+ ;;
+ hiux*)
+ os=hiuxwe2
+ ;;
+ lynx*178)
+ os=lynxos178
+ ;;
+ lynx*5)
+ os=lynxos5
+ ;;
+ lynxos*)
+ # don't get caught up in next wildcard
+ ;;
+ lynx*)
+ os=lynxos
+ ;;
+ mac[0-9]*)
+ os=$(echo "$os" | sed -e 's|mac|macos|')
+ ;;
+ opened*)
+ os=openedition
+ ;;
+ os400*)
+ os=os400
+ ;;
+ sunos5*)
+ os=$(echo "$os" | sed -e 's|sunos5|solaris2|')
+ ;;
+ sunos6*)
+ os=$(echo "$os" | sed -e 's|sunos6|solaris3|')
+ ;;
+ wince*)
+ os=wince
+ ;;
+ utek*)
+ os=bsd
+ ;;
+ dynix*)
+ os=bsd
+ ;;
+ acis*)
+ os=aos
+ ;;
+ atheos*)
+ os=atheos
+ ;;
+ syllable*)
+ os=syllable
+ ;;
+ 386bsd)
+ os=bsd
+ ;;
+ ctix* | uts*)
+ os=sysv
+ ;;
+ nova*)
+ os=rtmk-nova
+ ;;
+ ns2)
+ os=nextstep2
+ ;;
+ # Preserve the version number of sinix5.
+ sinix5.*)
+ os=$(echo $os | sed -e 's|sinix|sysv|')
+ ;;
+ sinix*)
+ os=sysv4
+ ;;
+ tpf*)
+ os=tpf
+ ;;
+ triton*)
+ os=sysv3
+ ;;
+ oss*)
+ os=sysv3
+ ;;
+ svr4*)
+ os=sysv4
+ ;;
+ svr3)
+ os=sysv3
+ ;;
+ sysvr4)
+ os=sysv4
+ ;;
+ ose*)
+ os=ose
+ ;;
+ *mint | mint[0-9]* | *MiNT | MiNT[0-9]*)
+ os=mint
+ ;;
+ dicos*)
+ os=dicos
+ ;;
+ pikeos*)
+ # Until real need of OS specific support for
+ # particular features comes up, bare metal
+ # configurations are quite functional.
+ case $cpu in
+ arm*)
+ os=eabi
+ ;;
+ *)
+ os=elf
+ ;;
+ esac
+ ;;
+ *)
+ # No normalization, but not necessarily accepted, that comes below.
+ ;;
+esac
+
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system. Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+kernel=
+case $cpu-$vendor in
+ score-*)
+ os=elf
+ ;;
+ spu-*)
+ os=elf
+ ;;
+ *-acorn)
+ os=riscix1.2
+ ;;
+ arm*-rebel)
+ kernel=linux
+ os=gnu
+ ;;
+ arm*-semi)
+ os=aout
+ ;;
+ c4x-* | tic4x-*)
+ os=coff
+ ;;
+ c8051-*)
+ os=elf
+ ;;
+ clipper-intergraph)
+ os=clix
+ ;;
+ hexagon-*)
+ os=elf
+ ;;
+ tic54x-*)
+ os=coff
+ ;;
+ tic55x-*)
+ os=coff
+ ;;
+ tic6x-*)
+ os=coff
+ ;;
+ # This must come before the *-dec entry.
+ pdp10-*)
+ os=tops20
+ ;;
+ pdp11-*)
+ os=none
+ ;;
+ *-dec | vax-*)
+ os=ultrix4.2
+ ;;
+ m68*-apollo)
+ os=domain
+ ;;
+ i386-sun)
+ os=sunos4.0.2
+ ;;
+ m68000-sun)
+ os=sunos3
+ ;;
+ m68*-cisco)
+ os=aout
+ ;;
+ mep-*)
+ os=elf
+ ;;
+ mips*-cisco)
+ os=elf
+ ;;
+ mips*-*)
+ os=elf
+ ;;
+ or32-*)
+ os=coff
+ ;;
+ *-tti) # must be before sparc entry or we get the wrong os.
+ os=sysv3
+ ;;
+ sparc-* | *-sun)
+ os=sunos4.1.1
+ ;;
+ pru-*)
+ os=elf
+ ;;
+ *-be)
+ os=beos
+ ;;
+ *-ibm)
+ os=aix
+ ;;
+ *-knuth)
+ os=mmixware
+ ;;
+ *-wec)
+ os=proelf
+ ;;
+ *-winbond)
+ os=proelf
+ ;;
+ *-oki)
+ os=proelf
+ ;;
+ *-hp)
+ os=hpux
+ ;;
+ *-hitachi)
+ os=hiux
+ ;;
+ i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+ os=sysv
+ ;;
+ *-cbm)
+ os=amigaos
+ ;;
+ *-dg)
+ os=dgux
+ ;;
+ *-dolphin)
+ os=sysv3
+ ;;
+ m68k-ccur)
+ os=rtu
+ ;;
+ m88k-omron*)
+ os=luna
+ ;;
+ *-next)
+ os=nextstep
+ ;;
+ *-sequent)
+ os=ptx
+ ;;
+ *-crds)
+ os=unos
+ ;;
+ *-ns)
+ os=genix
+ ;;
+ i370-*)
+ os=mvs
+ ;;
+ *-gould)
+ os=sysv
+ ;;
+ *-highlevel)
+ os=bsd
+ ;;
+ *-encore)
+ os=bsd
+ ;;
+ *-sgi)
+ os=irix
+ ;;
+ *-siemens)
+ os=sysv4
+ ;;
+ *-masscomp)
+ os=rtu
+ ;;
+ f30[01]-fujitsu | f700-fujitsu)
+ os=uxpv
+ ;;
+ *-rom68k)
+ os=coff
+ ;;
+ *-*bug)
+ os=coff
+ ;;
+ *-apple)
+ os=macos
+ ;;
+ *-atari*)
+ os=mint
+ ;;
+ *-wrs)
+ os=vxworks
+ ;;
+ *)
+ os=none
+ ;;
+esac
+
+fi
+
+# Now, validate our (potentially fixed-up) OS.
+case $os in
+ # Sometimes we do "kernel-abi", so those need to count as OSes.
+ musl* | newlib* | uclibc*)
+ ;;
+ # Likewise for "kernel-libc"
+ eabi | eabihf | gnueabi | gnueabihf)
+ ;;
+ # Now accept the basic system types.
+ # The portable systems comes first.
+ # Each alternative MUST end in a * to match a version number.
+ gnu* | android* | bsd* | mach* | minix* | genix* | ultrix* | irix* \
+ | *vms* | esix* | aix* | cnk* | sunos | sunos[34]* \
+ | hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \
+ | sym* | plan9* | psp* | sim* | xray* | os68k* | v88r* \
+ | hiux* | abug | nacl* | netware* | windows* \
+ | os9* | macos* | osx* | ios* \
+ | mpw* | magic* | mmixware* | mon960* | lnews* \
+ | amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \
+ | aos* | aros* | cloudabi* | sortix* | twizzler* \
+ | nindy* | vxsim* | vxworks* | ebmon* | hms* | mvs* \
+ | clix* | riscos* | uniplus* | iris* | isc* | rtu* | xenix* \
+ | mirbsd* | netbsd* | dicos* | openedition* | ose* \
+ | bitrig* | openbsd* | solidbsd* | libertybsd* | os108* \
+ | ekkobsd* | freebsd* | riscix* | lynxos* | os400* \
+ | bosx* | nextstep* | cxux* | aout* | elf* | oabi* \
+ | ptx* | coff* | ecoff* | winnt* | domain* | vsta* \
+ | udi* | lites* | ieee* | go32* | aux* | hcos* \
+ | chorusrdb* | cegcc* | glidix* \
+ | cygwin* | msys* | pe* | moss* | proelf* | rtems* \
+ | midipix* | mingw32* | mingw64* | mint* \
+ | uxpv* | beos* | mpeix* | udk* | moxiebox* \
+ | interix* | uwin* | mks* | rhapsody* | darwin* \
+ | openstep* | oskit* | conix* | pw32* | nonstopux* \
+ | storm-chaos* | tops10* | tenex* | tops20* | its* \
+ | os2* | vos* | palmos* | uclinux* | nucleus* | morphos* \
+ | scout* | superux* | sysv* | rtmk* | tpf* | windiss* \
+ | powermax* | dnix* | nx6 | nx7 | sei* | dragonfly* \
+ | skyos* | haiku* | rdos* | toppers* | drops* | es* \
+ | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \
+ | midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \
+ | nsk* | powerunix* | genode* | zvmoe* | qnx* | emx*)
+ ;;
+ # This one is extra strict with allowed versions
+ sco3.2v2 | sco3.2v[4-9]* | sco5v6*)
+ # Don't forget version if it is 3.2v4 or newer.
+ ;;
+ none)
+ ;;
+ *)
+ echo Invalid configuration \`"$1"\': OS \`"$os"\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+
+# As a final step for OS-related things, validate the OS-kernel combination
+# (given a valid OS), if there is a kernel.
+case $kernel-$os in
+ linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* | linux-musl* | linux-uclibc* )
+ ;;
+ uclinux-uclibc* )
+ ;;
+ -dietlibc* | -newlib* | -musl* | -uclibc* )
+ # These are just libc implementations, not actual OSes, and thus
+ # require a kernel.
+ echo "Invalid configuration \`$1': libc \`$os' needs explicit kernel." 1>&2
+ exit 1
+ ;;
+ kfreebsd*-gnu* | kopensolaris*-gnu*)
+ ;;
+ nto-qnx*)
+ ;;
+ os2-emx)
+ ;;
+ *-eabi* | *-gnueabi*)
+ ;;
+ -*)
+ # Blank kernel with real OS is always fine.
+ ;;
+ *-*)
+ echo "Invalid configuration \`$1': Kernel \`$kernel' not known to work with OS \`$os'." 1>&2
+ exit 1
+ ;;
+esac
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer. We pick the logical manufacturer.
+case $vendor in
+ unknown)
+ case $cpu-$os in
+ *-riscix*)
+ vendor=acorn
+ ;;
+ *-sunos*)
+ vendor=sun
+ ;;
+ *-cnk* | *-aix*)
+ vendor=ibm
+ ;;
+ *-beos*)
+ vendor=be
+ ;;
+ *-hpux*)
+ vendor=hp
+ ;;
+ *-mpeix*)
+ vendor=hp
+ ;;
+ *-hiux*)
+ vendor=hitachi
+ ;;
+ *-unos*)
+ vendor=crds
+ ;;
+ *-dgux*)
+ vendor=dg
+ ;;
+ *-luna*)
+ vendor=omron
+ ;;
+ *-genix*)
+ vendor=ns
+ ;;
+ *-clix*)
+ vendor=intergraph
+ ;;
+ *-mvs* | *-opened*)
+ vendor=ibm
+ ;;
+ *-os400*)
+ vendor=ibm
+ ;;
+ s390-* | s390x-*)
+ vendor=ibm
+ ;;
+ *-ptx*)
+ vendor=sequent
+ ;;
+ *-tpf*)
+ vendor=ibm
+ ;;
+ *-vxsim* | *-vxworks* | *-windiss*)
+ vendor=wrs
+ ;;
+ *-aux*)
+ vendor=apple
+ ;;
+ *-hms*)
+ vendor=hitachi
+ ;;
+ *-mpw* | *-macos*)
+ vendor=apple
+ ;;
+ *-*mint | *-mint[0-9]* | *-*MiNT | *-MiNT[0-9]*)
+ vendor=atari
+ ;;
+ *-vos*)
+ vendor=stratus
+ ;;
+ esac
+ ;;
+esac
+
+echo "$cpu-$vendor-${kernel:+$kernel-}$os"
+exit
+
+# Local variables:
+# eval: (add-hook 'before-save-hook 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/configure b/configure
new file mode 100755
index 0000000..5041ca2
--- /dev/null
+++ b/configure
@@ -0,0 +1,16139 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.71 for freeradius $Id$.
+#
+# Report bugs to <http://bugs.freeradius.org>.
+#
+#
+# Copyright (C) 1992-1996, 1998-2017, 2020-2021 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
+as_nop=:
+if test ${ZSH_VERSION+y} && (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 $as_nop
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+
+# Reset variables that may have inherited troublesome values from
+# the environment.
+
+# IFS needs to be set, to space, tab, and newline, in precisely that order.
+# (If _AS_PATH_WALK were called with IFS unset, it would have the
+# side effect of setting IFS to empty, thus disabling word splitting.)
+# Quoting is to prevent editors from complaining about space-tab.
+as_nl='
+'
+export as_nl
+IFS=" "" $as_nl"
+
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# Ensure predictable behavior from utilities with locale-dependent output.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# We cannot yet rely on "unset" to work, but we need these variables
+# to be unset--not just set to an empty or harmless value--now, to
+# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct
+# also avoids known problems related to "unset" and subshell syntax
+# in other old shells (e.g. bash 2.01 and pdksh 5.2.14).
+for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH
+do eval test \${$as_var+y} \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+
+# Ensure that fds 0, 1, and 2 are open.
+if (exec 3>&0) 2>/dev/null; then :; else exec 0</dev/null; fi
+if (exec 3>&1) 2>/dev/null; then :; else exec 1>/dev/null; fi
+if (exec 3>&2) ; then :; else exec 2>/dev/null; fi
+
+# The user is always right.
+if ${PATH_SEPARATOR+false} :; 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
+
+
+# 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
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ 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
+ printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+
+# 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'.
+printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2
+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="as_nop=:
+if test \${ZSH_VERSION+y} && (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 \$as_nop
+ 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 \$as_nop
+ exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1
+blah=\$(echo \$(echo blah))
+test x\"\$blah\" = xblah || 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_nop
+ as_have_required=no
+fi
+ if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null
+then :
+
+else $as_nop
+ 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
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ 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_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null
+then :
+ CONFIG_SHELL=$as_shell as_have_required=yes
+ if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null
+then :
+ break 2
+fi
+fi
+ done;;
+ esac
+ as_found=false
+done
+IFS=$as_save_IFS
+if $as_found
+then :
+
+else $as_nop
+ if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+ as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null
+then :
+ CONFIG_SHELL=$SHELL as_have_required=yes
+fi
+fi
+
+
+ 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'.
+printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
+fi
+
+ if test x$as_have_required = xno
+then :
+ printf "%s\n" "$0: This script requires a shell more modern than all"
+ printf "%s\n" "$0: the shells that I found on your system."
+ if test ${ZSH_VERSION+y} ; then
+ printf "%s\n" "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+ printf "%s\n" "$0: be upgraded to zsh 4.3.4 or later."
+ else
+ printf "%s\n" "$0: Please tell bug-autoconf@gnu.org and
+$0: http://bugs.freeradius.org about your system, including
+$0: any error possibly output before this message. Then
+$0: install a modern shell, or manually run the script
+$0: 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_nop
+# ---------
+# Do nothing but, unlike ":", preserve the value of $?.
+as_fn_nop ()
+{
+ return $?
+}
+as_nop=as_fn_nop
+
+# 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=`printf "%s\n" "$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 ||
+printf "%s\n" 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_nop
+ 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_nop
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+# as_fn_nop
+# ---------
+# Do nothing but, unlike ":", preserve the value of $?.
+as_fn_nop ()
+{
+ return $?
+}
+as_nop=as_fn_nop
+
+# 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
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ printf "%s\n" "$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 ||
+printf "%s\n" 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" ||
+ { printf "%s\n" "$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
+}
+
+
+# Determine whether it's possible to make 'echo' print without a newline.
+# These variables are no longer used directly by Autoconf, but are AC_SUBSTed
+# for compatibility with existing Makefiles.
+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
+
+# For backward compatibility with old third-party macros, we provide
+# the shell variables $as_echo and $as_echo_n. New code should use
+# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively.
+as_echo='printf %s\n'
+as_echo_n='printf %s'
+
+
+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='freeradius'
+PACKAGE_TARNAME='freeradius'
+PACKAGE_VERSION='$Id$'
+PACKAGE_STRING='freeradius $Id$'
+PACKAGE_BUGREPORT='http://bugs.freeradius.org'
+PACKAGE_URL='http://www.freeradius.org'
+
+ac_unique_file="src/main/radiusd.c"
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stddef.h>
+#ifdef HAVE_STDIO_H
+# include <stdio.h>
+#endif
+#ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_header_c_list=
+enable_option_checking=no
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+STATIC_MODULES
+USE_STATIC_LIBS
+USE_SHARED_LIBS
+INSTALLSTRIP
+MODULES
+subdirs
+HOSTINFO
+CRYPTLIB
+LIBPREFIX
+COLLECTDC_LDFLAGS
+COLLECTDC_LIBS
+PCAP_LDFLAGS
+PCAP_LIBS
+OPENSSL_CPPFLAGS
+OPENSSL_LDFLAGS
+OPENSSL_LIBS
+SYSTEMD_LDFLAGS
+SYSTEMD_LIBS
+LIBREADLINE
+TALLOC_LDFLAGS
+TALLOC_LIBS
+DIRNAME
+AUTOHEADER
+AUTOCONF
+ACLOCAL
+RUSERS
+SNMPWALK
+SNMPGET
+openssl_version_check_config
+WITH_DHCP
+modconfdir
+dictdir
+raddbdir
+radacctdir
+logdir
+GIT
+FR_MAKEFLAGS
+MAKE
+GMAKE
+clang_path
+RANLIB
+EGREP
+GREP
+CPP
+ac_ct_CXX
+CXXFLAGS
+CXX
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+target_os
+target_vendor
+target_cpu
+target
+host_os
+host_vendor
+host_cpu
+host
+build_os
+build_vendor
+build_cpu
+build
+ANTORA
+GRAPHVIZ_DOT
+DOXYGEN
+PERL
+PANDOC_ENGINE
+PANDOC
+ASCIIDOCTOR
+RADIUSD_VERSION_STRING
+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
+enable_developer
+enable_verify_ptr
+enable_fips_workaround
+enable_largefile
+enable_strict_dependencies
+enable_werror
+with_docdir
+with_logdir
+with_radacctdir
+with_raddbdir
+with_dictdir
+with_ascend_binary
+with_radiusv11
+with_threads
+with_tcp
+with_vmps
+with_dhcp
+with_static_modules
+with_shared_libs
+with_modules
+with_experimental_modules
+with_udpfromto
+with_rlm_FOO_lib_dir
+with_rlm_FOO_include_dir
+with_openssl
+with_openssl_lib_dir
+with_openssl_include_dir
+enable_openssl_version_check
+enable_reproducible_builds
+enable_fuzzer
+enable_address_sanitizer
+enable_leak_sanitizer
+enable_thread_sanitizer
+enable_undefined_behaviour_sanitizer
+with_talloc_lib_dir
+with_talloc_include_dir
+with_pcap_lib_dir
+with_pcap_include_dir
+with_collectdclient_lib_dir
+with_collectdclient_include_dir
+with_cap_lib_dir
+with_cap_include_dir
+with_systemd
+with_systemd_lib_dir
+with_systemd_include_dir
+with_execinfo_lib_dir
+with_execinfo_include_dir
+with_pcre
+with_pcre_lib_dir
+with_pcre_include_dir
+with_regex
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CXX
+CXXFLAGS
+CCC
+CPP'
+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_TARNAME}'
+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
+
+ 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=`printf "%s\n" "$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=`printf "%s\n" "$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=`printf "%s\n" "$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=`printf "%s\n" "$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.
+ printf "%s\n" "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ printf "%s\n" "$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" ;;
+ *) printf "%s\n" "$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 ||
+printf "%s\n" 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 freeradius $Id$ 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/freeradius]
+ --htmldir=DIR html documentation [DOCDIR]
+ --dvidir=DIR dvi documentation [DOCDIR]
+ --pdfdir=DIR pdf documentation [DOCDIR]
+ --psdir=DIR ps documentation [DOCDIR]
+_ACEOF
+
+ cat <<\_ACEOF
+
+System types:
+ --build=BUILD configure for building on BUILD [guessed]
+ --host=HOST cross-compile to build programs to run on HOST [BUILD]
+ --target=TARGET configure for building compilers for TARGET [HOST]
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+ case $ac_init_help in
+ short | recursive ) echo "Configuration of freeradius $Id$:";;
+ esac
+ cat <<\_ACEOF
+
+Optional Features:
+ --disable-option-checking ignore unrecognized --enable/--with options
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --enable-developer enables features of interest to developers.
+ --disable-verify-ptr disables WITH_VERIFY_PTR developer build option.
+ --enable-fips-workaround enables local MD4, MD5, etc. functionality to avoid OpenSSL FIPS issues.
+ --disable-largefile omit support for large files
+ --enable-strict-dependencies fail configure on lack of module dependancy.
+ --enable-werror causes the build to fail if any warnings are generated.
+ --disable-openssl-version-check
+ disable vulnerable OpenSSL version check
+
+ --enable-reproducible-builds
+ ensure the build does not change each time
+ --enable-fuzzer build with support for a fuzzer
+ --enable-address-sanitizer
+ build with support for address sanitizer.
+ --enable-leak-sanitizer build with support for leak sanitizer.
+ --enable-thread-sanitizer
+ build with support for thread sanitizer.
+ --enable-undefined-behaviour-sanitizer
+ build with support for undefined behaviour
+ sanitizer.
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --with-docdir=DIR directory for documentation DATADIR/doc/freeradius
+ --with-logdir=DIR directory for logfiles LOCALSTATEDIR/log/radius
+ --with-radacctdir=DIR directory for detail files LOGDIR/radacct
+ --with-raddbdir=DIR directory for config files SYSCONFDIR/raddb
+ --with-dictdir=DIR directory for dictionary files DATAROOTDIR/freeradius
+ --with-ascend-binary include support for Ascend binary filter attributes (default=yes)
+ --with-radiusv11 compile in RADIUSv11 support. (default=no)
+ --with-threads use threads, if available. (default=yes)
+ --with-tcp compile in TCP support. (default=yes)
+ --with-vmps compile in VMPS support. (default=yes)
+ --with-dhcp compile in DHCP support. (default=yes)
+ --with-static-modules=QUOTED-MODULE-LIST
+ --with-shared-libs build dynamic libraries and link against them.
+ (default=yes)
+ --with-modules=QUOTED-MODULE-LIST
+ --with-experimental-modules
+ use experimental and unstable modules. (default=no,
+ unless --enable-developer=yes)
+ --with-udpfromto compile in UDPFROMTO support. (default=yes)
+ --with-rlm-FOO-lib-dir=DIR
+ directory in which to look for library files used by
+ module FOO
+ --with-rlm-FOO-include-dir=DIR
+ directory in which to look for include files used by
+ module FOO
+ --with-openssl use OpenSSL. (default=yes)
+ --with-openssl-lib-dir=DIR
+ directory to look for OpenSSL library files
+ --with-openssl-include-dir=DIR
+ directory to look for OpenSSL include files
+ --with-talloc-lib-dir=DIR
+ directory in which to look for talloc library files
+ --with-talloc-include-dir=DIR
+ directory in which to look for talloc include files
+ --with-pcap-lib-dir=DIR directory in which to look for pcap library files
+ --with-pcap-include-dir=DIR
+ directory in which to look for pcap include files
+ --with-collectdclient-lib-dir=DIR
+ directory in which to look for collectdclient
+ library files
+ --with-collectdclient-include-dir=DIR
+ directory in which to look for collectdclient
+ include files
+ --with-cap-lib-dir=DIR directory in which to look for cap library files
+ --with-cap-include-dir=DIR
+ directory in which to look for cap include files
+ --with-systemd add systemd support, if available (default=no)
+ --with-systemd-lib-dir=DIR
+ directory to look for systemd library files
+ --with-systemd-include-dir=DIR
+ directory to look for systemd include files
+ --with-execinfo-lib-dir=DIR
+ directory in which to look for execinfo library
+ files
+ --with-execinfo-include-dir=DIR
+ directory in which to look for execinfo include
+ files
+ --with-pcre use libpcre (if available). (default=yes)
+ --with-pcre-lib-dir=DIR directory in which to look for pcre library files
+ --with-pcre-include-dir=DIR
+ directory in which to look for pcre include files
+ --with-regex Whether to build with regular expressions
+ (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>
+ CXX C++ compiler command
+ CXXFLAGS C++ compiler flags
+ 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 <http://bugs.freeradius.org>.
+freeradius home page: <http://www.freeradius.org>.
+_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=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`printf "%s\n" "$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 configure.gnu first; this name is used for a wrapper for
+ # Metaconfig's "Configure" on case-insensitive file systems.
+ 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
+ printf "%s\n" "$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
+freeradius configure $Id$
+generated by GNU Autoconf 2.71
+
+Copyright (C) 2021 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest.beam
+ 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\""
+printf "%s\n" "$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
+ printf "%s\n" "$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_nop
+ printf "%s\n" "$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_cxx_try_compile LINENO
+# ----------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_cxx_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest.beam
+ 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\""
+printf "%s\n" "$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
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext
+then :
+ ac_retval=0
+else $as_nop
+ printf "%s\n" "$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_cxx_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
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+printf %s "checking for $2... " >&6; }
+if eval test \${$3+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ 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 $as_nop
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+printf "%s\n" "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_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\""
+printf "%s\n" "$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
+ printf "%s\n" "$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_nop
+ printf "%s\n" "$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_run LINENO
+# ----------------------
+# Try to run 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\""
+printf "%s\n" "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ printf "%s\n" "$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\""
+printf "%s\n" "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }
+then :
+ ac_retval=0
+else $as_nop
+ printf "%s\n" "$as_me: program exited with status $ac_status" >&5
+ printf "%s\n" "$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_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.beam 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\""
+printf "%s\n" "$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
+ printf "%s\n" "$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_nop
+ printf "%s\n" "$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
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+printf %s "checking for $2... " >&6; }
+if eval test \${$3+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ 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. */
+
+#include <limits.h>
+#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 (void)
+{
+return $2 ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+ eval "$3=yes"
+else $as_nop
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+printf "%s\n" "$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
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+printf %s "checking for $2... " >&6; }
+if eval test \${$3+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ eval "$3=no"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main (void)
+{
+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 (void)
+{
+if (sizeof (($2)))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+
+else $as_nop
+ eval "$3=yes"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+printf "%s\n" "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_type
+
+# ac_fn_check_decl LINENO SYMBOL VAR INCLUDES EXTRA-OPTIONS FLAG-VAR
+# ------------------------------------------------------------------
+# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR
+# accordingly. Pass EXTRA-OPTIONS to the compiler, using FLAG-VAR.
+ac_fn_check_decl ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ as_decl_name=`echo $2|sed 's/ *(.*//'`
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5
+printf %s "checking whether $as_decl_name is declared... " >&6; }
+if eval test \${$3+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'`
+ eval ac_save_FLAGS=\$$6
+ as_fn_append $6 " $5"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main (void)
+{
+#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 $as_nop
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ eval $6=\$ac_save_FLAGS
+
+fi
+eval ac_res=\$$3
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+printf "%s\n" "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_check_decl
+ac_configure_args_raw=
+for ac_arg
+do
+ case $ac_arg in
+ *\'*)
+ ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ as_fn_append ac_configure_args_raw " '$ac_arg'"
+done
+
+case $ac_configure_args_raw in
+ *$as_nl*)
+ ac_safe_unquote= ;;
+ *)
+ ac_unsafe_z='|&;<>()$`\\"*?[ '' ' # This string ends in space, tab.
+ ac_unsafe_a="$ac_unsafe_z#~"
+ ac_safe_unquote="s/ '\\([^$ac_unsafe_a][^$ac_unsafe_z]*\\)'/ \\1/g"
+ ac_configure_args_raw=` printf "%s\n" "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;;
+esac
+
+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 freeradius $as_me $Id$, which was
+generated by GNU Autoconf 2.71. Invocation command line was
+
+ $ $0$ac_configure_args_raw
+
+_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
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ printf "%s\n" "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=`printf "%s\n" "$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=$?
+ # Sanitize IFS.
+ IFS=" "" $as_nl"
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ printf "%s\n" "## ---------------- ##
+## 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_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+printf "%s\n" "$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
+
+ printf "%s\n" "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ printf "%s\n" "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ printf "%s\n" "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ printf "%s\n" "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ printf "%s\n" "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ printf "%s\n" "$as_me: caught signal $ac_signal"
+ printf "%s\n" "$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
+
+printf "%s\n" "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+printf "%s\n" "#define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h
+
+printf "%s\n" "#define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h
+
+printf "%s\n" "#define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h
+
+printf "%s\n" "#define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h
+
+printf "%s\n" "#define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h
+
+printf "%s\n" "#define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+if test -n "$CONFIG_SITE"; then
+ ac_site_files="$CONFIG_SITE"
+elif test "x$prefix" != xNONE; then
+ ac_site_files="$prefix/share/config.site $prefix/etc/config.site"
+else
+ ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+fi
+
+for ac_site_file in $ac_site_files
+do
+ case $ac_site_file in #(
+ */*) :
+ ;; #(
+ *) :
+ ac_site_file=./$ac_site_file ;;
+esac
+ if test -f "$ac_site_file" && test -r "$ac_site_file"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+printf "%s\n" "$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
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+printf "%s\n" "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+printf "%s\n" "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Test code for whether the C compiler supports C89 (global declarations)
+ac_c_conftest_c89_globals='
+/* Does the compiler advertise C89 conformance?
+ Do not test the value of __STDC__, because some compilers set it to 0
+ while being otherwise adequately conformant. */
+#if !defined __STDC__
+# error "Compiler does not advertise C89 conformance"
+#endif
+
+#include <stddef.h>
+#include <stdarg.h>
+struct stat;
+/* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */
+struct buf { int x; };
+struct buf * (*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 do not provoke an error unfortunately, instead are silently treated
+ as an "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 is necessary to write \x00 == 0 to get something
+ that is 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 **, int *(*)(struct buf *, struct stat *, int),
+ int, int);'
+
+# Test code for whether the C compiler supports C89 (body of main).
+ac_c_conftest_c89_main='
+ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]);
+'
+
+# Test code for whether the C compiler supports C99 (global declarations)
+ac_c_conftest_c99_globals='
+// Does the compiler advertise C99 conformance?
+#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L
+# error "Compiler does not advertise C99 conformance"
+#endif
+
+#include <stdbool.h>
+extern int puts (const char *);
+extern int printf (const char *, ...);
+extern int dprintf (int, const char *, ...);
+extern void *malloc (size_t);
+
+// Check varargs macros. These examples are taken from C99 6.10.3.5.
+// dprintf is used instead of fprintf to avoid needing to declare
+// FILE and stderr.
+#define debug(...) dprintf (2, __VA_ARGS__)
+#define showlist(...) puts (#__VA_ARGS__)
+#define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__))
+static void
+test_varargs_macros (void)
+{
+ int x = 1234;
+ int y = 5678;
+ debug ("Flag");
+ debug ("X = %d\n", x);
+ showlist (The first, second, and third items.);
+ report (x>y, "x is %d but y is %d", x, y);
+}
+
+// Check long long types.
+#define BIG64 18446744073709551615ull
+#define BIG32 4294967295ul
+#define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0)
+#if !BIG_OK
+ #error "your preprocessor is broken"
+#endif
+#if BIG_OK
+#else
+ #error "your preprocessor is broken"
+#endif
+static long long int bignum = -9223372036854775807LL;
+static unsigned long long int ubignum = BIG64;
+
+struct incomplete_array
+{
+ int datasize;
+ double data[];
+};
+
+struct named_init {
+ int number;
+ const wchar_t *name;
+ double average;
+};
+
+typedef const char *ccp;
+
+static inline int
+test_restrict (ccp restrict text)
+{
+ // See if C++-style comments work.
+ // Iterate through items via the restricted pointer.
+ // Also check for declarations in for loops.
+ for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i)
+ continue;
+ return 0;
+}
+
+// Check varargs and va_copy.
+static bool
+test_varargs (const char *format, ...)
+{
+ va_list args;
+ va_start (args, format);
+ va_list args_copy;
+ va_copy (args_copy, args);
+
+ const char *str = "";
+ int number = 0;
+ float fnumber = 0;
+
+ while (*format)
+ {
+ switch (*format++)
+ {
+ case '\''s'\'': // string
+ str = va_arg (args_copy, const char *);
+ break;
+ case '\''d'\'': // int
+ number = va_arg (args_copy, int);
+ break;
+ case '\''f'\'': // float
+ fnumber = va_arg (args_copy, double);
+ break;
+ default:
+ break;
+ }
+ }
+ va_end (args_copy);
+ va_end (args);
+
+ return *str && number && fnumber;
+}
+'
+
+# Test code for whether the C compiler supports C99 (body of main).
+ac_c_conftest_c99_main='
+ // Check bool.
+ _Bool success = false;
+ success |= (argc != 0);
+
+ // Check restrict.
+ if (test_restrict ("String literal") == 0)
+ success = true;
+ char *restrict newvar = "Another string";
+
+ // Check varargs.
+ success &= test_varargs ("s, d'\'' f .", "string", 65, 34.234);
+ test_varargs_macros ();
+
+ // Check flexible array members.
+ struct incomplete_array *ia =
+ malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10));
+ ia->datasize = 10;
+ for (int i = 0; i < ia->datasize; ++i)
+ ia->data[i] = i * 1.234;
+
+ // Check named initializers.
+ struct named_init ni = {
+ .number = 34,
+ .name = L"Test wide string",
+ .average = 543.34343,
+ };
+
+ ni.number = 58;
+
+ int dynamic_array[ni.number];
+ dynamic_array[0] = argv[0][0];
+ dynamic_array[ni.number - 1] = 543;
+
+ // work around unused variable warnings
+ ok |= (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == '\''x'\''
+ || dynamic_array[ni.number - 1] != 543);
+'
+
+# Test code for whether the C compiler supports C11 (global declarations)
+ac_c_conftest_c11_globals='
+// Does the compiler advertise C11 conformance?
+#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L
+# error "Compiler does not advertise C11 conformance"
+#endif
+
+// Check _Alignas.
+char _Alignas (double) aligned_as_double;
+char _Alignas (0) no_special_alignment;
+extern char aligned_as_int;
+char _Alignas (0) _Alignas (int) aligned_as_int;
+
+// Check _Alignof.
+enum
+{
+ int_alignment = _Alignof (int),
+ int_array_alignment = _Alignof (int[100]),
+ char_alignment = _Alignof (char)
+};
+_Static_assert (0 < -_Alignof (int), "_Alignof is signed");
+
+// Check _Noreturn.
+int _Noreturn does_not_return (void) { for (;;) continue; }
+
+// Check _Static_assert.
+struct test_static_assert
+{
+ int x;
+ _Static_assert (sizeof (int) <= sizeof (long int),
+ "_Static_assert does not work in struct");
+ long int y;
+};
+
+// Check UTF-8 literals.
+#define u8 syntax error!
+char const utf8_literal[] = u8"happens to be ASCII" "another string";
+
+// Check duplicate typedefs.
+typedef long *long_ptr;
+typedef long int *long_ptr;
+typedef long_ptr long_ptr;
+
+// Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1.
+struct anonymous
+{
+ union {
+ struct { int i; int j; };
+ struct { int k; long int l; } w;
+ };
+ int m;
+} v1;
+'
+
+# Test code for whether the C compiler supports C11 (body of main).
+ac_c_conftest_c11_main='
+ _Static_assert ((offsetof (struct anonymous, i)
+ == offsetof (struct anonymous, w.k)),
+ "Anonymous union alignment botch");
+ v1.i = 2;
+ v1.w.k = 5;
+ ok |= v1.i != 5;
+'
+
+# Test code for whether the C compiler supports C11 (complete).
+ac_c_conftest_c11_program="${ac_c_conftest_c89_globals}
+${ac_c_conftest_c99_globals}
+${ac_c_conftest_c11_globals}
+
+int
+main (int argc, char **argv)
+{
+ int ok = 0;
+ ${ac_c_conftest_c89_main}
+ ${ac_c_conftest_c99_main}
+ ${ac_c_conftest_c11_main}
+ return ok;
+}
+"
+
+# Test code for whether the C compiler supports C99 (complete).
+ac_c_conftest_c99_program="${ac_c_conftest_c89_globals}
+${ac_c_conftest_c99_globals}
+
+int
+main (int argc, char **argv)
+{
+ int ok = 0;
+ ${ac_c_conftest_c89_main}
+ ${ac_c_conftest_c99_main}
+ return ok;
+}
+"
+
+# Test code for whether the C compiler supports C89 (complete).
+ac_c_conftest_c89_program="${ac_c_conftest_c89_globals}
+
+int
+main (int argc, char **argv)
+{
+ int ok = 0;
+ ${ac_c_conftest_c89_main}
+ return ok;
+}
+"
+
+# Test code for whether the C++ compiler supports C++98 (global declarations)
+ac_cxx_conftest_cxx98_globals='
+// Does the compiler advertise C++98 conformance?
+#if !defined __cplusplus || __cplusplus < 199711L
+# error "Compiler does not advertise C++98 conformance"
+#endif
+
+// These inclusions are to reject old compilers that
+// lack the unsuffixed header files.
+#include <cstdlib>
+#include <exception>
+
+// <cassert> and <cstring> are *not* freestanding headers in C++98.
+extern void assert (int);
+namespace std {
+ extern int strcmp (const char *, const char *);
+}
+
+// Namespaces, exceptions, and templates were all added after "C++ 2.0".
+using std::exception;
+using std::strcmp;
+
+namespace {
+
+void test_exception_syntax()
+{
+ try {
+ throw "test";
+ } catch (const char *s) {
+ // Extra parentheses suppress a warning when building autoconf itself,
+ // due to lint rules shared with more typical C programs.
+ assert (!(strcmp) (s, "test"));
+ }
+}
+
+template <typename T> struct test_template
+{
+ T const val;
+ explicit test_template(T t) : val(t) {}
+ template <typename U> T add(U u) { return static_cast<T>(u) + val; }
+};
+
+} // anonymous namespace
+'
+
+# Test code for whether the C++ compiler supports C++98 (body of main)
+ac_cxx_conftest_cxx98_main='
+ assert (argc);
+ assert (! argv[0]);
+{
+ test_exception_syntax ();
+ test_template<double> tt (2.0);
+ assert (tt.add (4) == 6.0);
+ assert (true && !false);
+}
+'
+
+# Test code for whether the C++ compiler supports C++11 (global declarations)
+ac_cxx_conftest_cxx11_globals='
+// Does the compiler advertise C++ 2011 conformance?
+#if !defined __cplusplus || __cplusplus < 201103L
+# error "Compiler does not advertise C++11 conformance"
+#endif
+
+namespace cxx11test
+{
+ constexpr int get_val() { return 20; }
+
+ struct testinit
+ {
+ int i;
+ double d;
+ };
+
+ class delegate
+ {
+ public:
+ delegate(int n) : n(n) {}
+ delegate(): delegate(2354) {}
+
+ virtual int getval() { return this->n; };
+ protected:
+ int n;
+ };
+
+ class overridden : public delegate
+ {
+ public:
+ overridden(int n): delegate(n) {}
+ virtual int getval() override final { return this->n * 2; }
+ };
+
+ class nocopy
+ {
+ public:
+ nocopy(int i): i(i) {}
+ nocopy() = default;
+ nocopy(const nocopy&) = delete;
+ nocopy & operator=(const nocopy&) = delete;
+ private:
+ int i;
+ };
+
+ // for testing lambda expressions
+ template <typename Ret, typename Fn> Ret eval(Fn f, Ret v)
+ {
+ return f(v);
+ }
+
+ // for testing variadic templates and trailing return types
+ template <typename V> auto sum(V first) -> V
+ {
+ return first;
+ }
+ template <typename V, typename... Args> auto sum(V first, Args... rest) -> V
+ {
+ return first + sum(rest...);
+ }
+}
+'
+
+# Test code for whether the C++ compiler supports C++11 (body of main)
+ac_cxx_conftest_cxx11_main='
+{
+ // Test auto and decltype
+ auto a1 = 6538;
+ auto a2 = 48573953.4;
+ auto a3 = "String literal";
+
+ int total = 0;
+ for (auto i = a3; *i; ++i) { total += *i; }
+
+ decltype(a2) a4 = 34895.034;
+}
+{
+ // Test constexpr
+ short sa[cxx11test::get_val()] = { 0 };
+}
+{
+ // Test initializer lists
+ cxx11test::testinit il = { 4323, 435234.23544 };
+}
+{
+ // Test range-based for
+ int array[] = {9, 7, 13, 15, 4, 18, 12, 10, 5, 3,
+ 14, 19, 17, 8, 6, 20, 16, 2, 11, 1};
+ for (auto &x : array) { x += 23; }
+}
+{
+ // Test lambda expressions
+ using cxx11test::eval;
+ assert (eval ([](int x) { return x*2; }, 21) == 42);
+ double d = 2.0;
+ assert (eval ([&](double x) { return d += x; }, 3.0) == 5.0);
+ assert (d == 5.0);
+ assert (eval ([=](double x) mutable { return d += x; }, 4.0) == 9.0);
+ assert (d == 5.0);
+}
+{
+ // Test use of variadic templates
+ using cxx11test::sum;
+ auto a = sum(1);
+ auto b = sum(1, 2);
+ auto c = sum(1.0, 2.0, 3.0);
+}
+{
+ // Test constructor delegation
+ cxx11test::delegate d1;
+ cxx11test::delegate d2();
+ cxx11test::delegate d3(45);
+}
+{
+ // Test override and final
+ cxx11test::overridden o1(55464);
+}
+{
+ // Test nullptr
+ char *c = nullptr;
+}
+{
+ // Test template brackets
+ test_template<::test_template<int>> v(test_template<int>(12));
+}
+{
+ // Unicode literals
+ char const *utf8 = u8"UTF-8 string \u2500";
+ char16_t const *utf16 = u"UTF-8 string \u2500";
+ char32_t const *utf32 = U"UTF-32 string \u2500";
+}
+'
+
+# Test code for whether the C compiler supports C++11 (complete).
+ac_cxx_conftest_cxx11_program="${ac_cxx_conftest_cxx98_globals}
+${ac_cxx_conftest_cxx11_globals}
+
+int
+main (int argc, char **argv)
+{
+ int ok = 0;
+ ${ac_cxx_conftest_cxx98_main}
+ ${ac_cxx_conftest_cxx11_main}
+ return ok;
+}
+"
+
+# Test code for whether the C compiler supports C++98 (complete).
+ac_cxx_conftest_cxx98_program="${ac_cxx_conftest_cxx98_globals}
+int
+main (int argc, char **argv)
+{
+ int ok = 0;
+ ${ac_cxx_conftest_cxx98_main}
+ return ok;
+}
+"
+
+as_fn_append ac_header_c_list " stdio.h stdio_h HAVE_STDIO_H"
+as_fn_append ac_header_c_list " stdlib.h stdlib_h HAVE_STDLIB_H"
+as_fn_append ac_header_c_list " string.h string_h HAVE_STRING_H"
+as_fn_append ac_header_c_list " inttypes.h inttypes_h HAVE_INTTYPES_H"
+as_fn_append ac_header_c_list " stdint.h stdint_h HAVE_STDINT_H"
+as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H"
+as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H"
+as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H"
+as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H"
+as_fn_append ac_header_c_list " wchar.h wchar_h HAVE_WCHAR_H"
+as_fn_append ac_header_c_list " minix/config.h minix_config_h HAVE_MINIX_CONFIG_H"
+as_fn_append ac_header_c_list " sys/time.h sys_time_h HAVE_SYS_TIME_H"
+
+# Auxiliary files required by this configure script.
+ac_aux_files="missing config.guess config.sub"
+
+# Locations in which to look for auxiliary files.
+ac_aux_dir_candidates="${srcdir}${PATH_SEPARATOR}${srcdir}/..${PATH_SEPARATOR}${srcdir}/../.."
+
+# Search for a directory containing all of the required auxiliary files,
+# $ac_aux_files, from the $PATH-style list $ac_aux_dir_candidates.
+# If we don't find one directory that contains all the files we need,
+# we report the set of missing files from the *first* directory in
+# $ac_aux_dir_candidates and give up.
+ac_missing_aux_files=""
+ac_first_candidate=:
+printf "%s\n" "$as_me:${as_lineno-$LINENO}: looking for aux files: $ac_aux_files" >&5
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in $ac_aux_dir_candidates
+do
+ IFS=$as_save_IFS
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ as_found=:
+
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: trying $as_dir" >&5
+ ac_aux_dir_found=yes
+ ac_install_sh=
+ for ac_aux in $ac_aux_files
+ do
+ # As a special case, if "install-sh" is required, that requirement
+ # can be satisfied by any of "install-sh", "install.sh", or "shtool",
+ # and $ac_install_sh is set appropriately for whichever one is found.
+ if test x"$ac_aux" = x"install-sh"
+ then
+ if test -f "${as_dir}install-sh"; then
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install-sh found" >&5
+ ac_install_sh="${as_dir}install-sh -c"
+ elif test -f "${as_dir}install.sh"; then
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install.sh found" >&5
+ ac_install_sh="${as_dir}install.sh -c"
+ elif test -f "${as_dir}shtool"; then
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}shtool found" >&5
+ ac_install_sh="${as_dir}shtool install -c"
+ else
+ ac_aux_dir_found=no
+ if $ac_first_candidate; then
+ ac_missing_aux_files="${ac_missing_aux_files} install-sh"
+ else
+ break
+ fi
+ fi
+ else
+ if test -f "${as_dir}${ac_aux}"; then
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}${ac_aux} found" >&5
+ else
+ ac_aux_dir_found=no
+ if $ac_first_candidate; then
+ ac_missing_aux_files="${ac_missing_aux_files} ${ac_aux}"
+ else
+ break
+ fi
+ fi
+ fi
+ done
+ if test "$ac_aux_dir_found" = yes; then
+ ac_aux_dir="$as_dir"
+ break
+ fi
+ ac_first_candidate=false
+
+ as_found=false
+done
+IFS=$as_save_IFS
+if $as_found
+then :
+
+else $as_nop
+ as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$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.
+if test -f "${ac_aux_dir}config.guess"; then
+ ac_config_guess="$SHELL ${ac_aux_dir}config.guess"
+fi
+if test -f "${ac_aux_dir}config.sub"; then
+ ac_config_sub="$SHELL ${ac_aux_dir}config.sub"
+fi
+if test -f "$ac_aux_dir/configure"; then
+ ac_configure="$SHELL ${ac_aux_dir}configure"
+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,)
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+printf "%s\n" "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+printf "%s\n" "$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
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+printf "%s\n" "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+printf "%s\n" "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+printf "%s\n" "$as_me: former value: \`$ac_old_val'" >&2;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+printf "%s\n" "$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=`printf "%s\n" "$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
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`${MAKE-make} distclean' and/or \`rm $cache_file'
+ and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+ac_config_headers="$ac_config_headers src/include/autoconf.h"
+
+
+RADIUSD_MAJOR_VERSION=`cat VERSION | cut -f1 -d.`
+RADIUSD_MINOR_VERSION=`cat VERSION | cut -f2 -d.`
+RADIUSD_INCRM_VERSION=`cat VERSION | cut -f3 -d. | sed 's/[\.-].*$//'`
+
+RADIUSD_VERSION=`printf "%02i%02i%02i" $RADIUSD_MAJOR_VERSION $RADIUSD_MINOR_VERSION $RADIUSD_INCRM_VERSION`
+
+RADIUSD_VERSION_STRING=`cat VERSION`
+
+
+
+
+printf "%s\n" "#define RADIUSD_VERSION ${RADIUSD_VERSION}" >>confdefs.h
+
+
+printf "%s\n" "#define RADIUSD_VERSION_STRING \"${RADIUSD_VERSION_STRING}\"" >>confdefs.h
+
+
+
+unset ASAN_OPTIONS
+unset LSAN_OPTIONS
+
+# Extract the first word of "asciidoctor", so it can be a program name with args.
+set dummy asciidoctor; ac_word=$2
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_path_ASCIIDOCTOR+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ case $ASCIIDOCTOR in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_ASCIIDOCTOR="$ASCIIDOCTOR" # 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
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ 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_ASCIIDOCTOR="$as_dir$ac_word$ac_exec_ext"
+ printf "%s\n" "$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
+ASCIIDOCTOR=$ac_cv_path_ASCIIDOCTOR
+if test -n "$ASCIIDOCTOR"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ASCIIDOCTOR" >&5
+printf "%s\n" "$ASCIIDOCTOR" >&6; }
+else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+
+
+if test "x$ac_cv_path_ASCIIDOCTOR" = "x"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: asciidoctor not found - Please install if you want build the docs" >&5
+printf "%s\n" "$as_me: WARNING: asciidoctor not found - Please install if you want build the docs" >&2;}
+fi
+
+# Extract the first word of "pandoc", so it can be a program name with args.
+set dummy pandoc; ac_word=$2
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_path_PANDOC+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ case $PANDOC in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_PANDOC="$PANDOC" # 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
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ 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_PANDOC="$as_dir$ac_word$ac_exec_ext"
+ printf "%s\n" "$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
+PANDOC=$ac_cv_path_PANDOC
+if test -n "$PANDOC"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PANDOC" >&5
+printf "%s\n" "$PANDOC" >&6; }
+else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+
+
+if test "x$ac_cv_path_PANDOC" = "x"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: pandoc not found - Please install if you want build the docs" >&5
+printf "%s\n" "$as_me: WARNING: pandoc not found - Please install if you want build the docs" >&2;}
+else
+ #
+ # Pandoc v2 onwards renamed --latex-engine to --pdf-engine
+ #
+ if pandoc --help 2>&1 | grep -q "latex-engine"; then
+ PANDOC_ENGINE=latex
+ else
+ PANDOC_ENGINE=pdf
+ fi
+
+fi
+
+# pandoc and asciidoctor is defined? then check it.
+if test "x$ac_cv_path_PANDOC" != "x" && test "x$ac_cv_path_ASCIIDOCTOR" != "x"; then
+
+
+
+
+
+
+# Make sure we have perl
+if test -z "$PERL"; then
+# Extract the first word of "perl", so it can be a program name with args.
+set dummy perl; ac_word=$2
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_PERL+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ if test -n "$PERL"; then
+ ac_cv_prog_PERL="$PERL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ ac_cv_prog_PERL="perl"
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+PERL=$ac_cv_prog_PERL
+if test -n "$PERL"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PERL" >&5
+printf "%s\n" "$PERL" >&6; }
+else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+
+
+fi
+
+if test "x$PERL" != x; then
+ ax_perl_modules_failed=0
+ for ax_perl_module in 'JSON' ; do
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for perl module $ax_perl_module" >&5
+printf %s "checking for perl module $ax_perl_module... " >&6; }
+
+ # Would be nice to log result here, but can't rely on autoconf internals
+ $PERL -e "use $ax_perl_module; exit" > /dev/null 2>&1
+ if test $? -ne 0; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; };
+ ax_perl_modules_failed=1
+ else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ok" >&5
+printf "%s\n" "ok" >&6; };
+ fi
+ done
+
+ # Run optional shell commands
+ if test "$ax_perl_modules_failed" = 0; then
+ :
+
+ else
+ :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Perl JSON module not found - Please install if you want build the docs" >&5
+printf "%s\n" "$as_me: WARNING: Perl JSON module not found - Please install if you want build the docs" >&2;}
+ fi
+else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: could not find perl" >&5
+printf "%s\n" "$as_me: WARNING: could not find perl" >&2;}
+fi
+fi
+
+# Extract the first word of "doxygen", so it can be a program name with args.
+set dummy doxygen; ac_word=$2
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_path_DOXYGEN+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ case $DOXYGEN in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_DOXYGEN="$DOXYGEN" # 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
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ 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_DOXYGEN="$as_dir$ac_word$ac_exec_ext"
+ printf "%s\n" "$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
+DOXYGEN=$ac_cv_path_DOXYGEN
+if test -n "$DOXYGEN"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DOXYGEN" >&5
+printf "%s\n" "$DOXYGEN" >&6; }
+else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+
+
+if test "x$ac_cv_path_DOXYGEN" != "x"; then
+ # Extract the first word of "dot", so it can be a program name with args.
+set dummy dot; ac_word=$2
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_path_GRAPHVIZ_DOT+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ case $GRAPHVIZ_DOT in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_GRAPHVIZ_DOT="$GRAPHVIZ_DOT" # 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
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ 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_GRAPHVIZ_DOT="$as_dir$ac_word$ac_exec_ext"
+ printf "%s\n" "$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
+GRAPHVIZ_DOT=$ac_cv_path_GRAPHVIZ_DOT
+if test -n "$GRAPHVIZ_DOT"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $GRAPHVIZ_DOT" >&5
+printf "%s\n" "$GRAPHVIZ_DOT" >&6; }
+else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+
+
+ if test "x$ac_cv_path_GRAPHVIZ_DOT" = "x"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: dot not found - Please install the graphviz if you want to build the docs/source" >&5
+printf "%s\n" "$as_me: WARNING: dot not found - Please install the graphviz if you want to build the docs/source" >&2;}
+ fi
+else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: doxygen not found - Please install if you want build the docs/source" >&5
+printf "%s\n" "$as_me: WARNING: doxygen not found - Please install if you want build the docs/source" >&2;}
+fi
+
+# Extract the first word of "antora", so it can be a program name with args.
+set dummy antora; ac_word=$2
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_path_ANTORA+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ case $ANTORA in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_ANTORA="$ANTORA" # 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
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ 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_ANTORA="$as_dir$ac_word$ac_exec_ext"
+ printf "%s\n" "$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
+ANTORA=$ac_cv_path_ANTORA
+if test -n "$ANTORA"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ANTORA" >&5
+printf "%s\n" "$ANTORA" >&6; }
+else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+
+
+if test "x$ac_cv_path_ANTORA" = "x"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: antora not found - Please install if you want build the site" >&5
+printf "%s\n" "$as_me: WARNING: antora not found - Please install if you want build the site" >&2;}
+fi
+
+# Check whether --enable-developer was given.
+if test ${enable_developer+y}
+then :
+ enableval=$enable_developer; case "$enableval" in
+ no)
+ developer=no
+ ;;
+ *)
+ developer=yes
+ esac
+
+fi
+
+
+if test -d $srcdir/.git; then
+ if test "x$developer" != "xno"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: found .git directory, enabling developer build implicitly, disable with --disable-developer" >&5
+printf "%s\n" "$as_me: found .git directory, enabling developer build implicitly, disable with --disable-developer" >&6;}
+ developer="yes"
+ fi
+fi
+
+if test "x$developer" = "xyes"; then
+ : ${CFLAGS=-g3}
+fi
+
+# Check whether --enable-verify-ptr was given.
+if test ${enable_verify_ptr+y}
+then :
+ enableval=$enable_verify_ptr; case "$enableval" in
+ no)
+ verify_ptr=""
+ ;;
+ *)
+ verify_ptr="-DWITH_VERIFY_PTR=1"
+ esac
+else $as_nop
+ verify_ptr="-DWITH_VERIFY_PTR=1"
+fi
+
+
+# Check whether --enable-fips-workaround was given.
+if test ${enable_fips_workaround+y}
+then :
+ enableval=$enable_fips_workaround; case "$enableval" in
+ no)
+ fips=""
+ ;;
+ *)
+ fips="-DWITH_FIPS=1"
+ esac
+else $as_nop
+ fips=""
+fi
+
+
+
+
+
+
+ # Make sure we can run config.sub.
+$SHELL "${ac_aux_dir}config.sub" sun4 >/dev/null 2>&1 ||
+ as_fn_error $? "cannot run $SHELL ${ac_aux_dir}config.sub" "$LINENO" 5
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
+printf %s "checking build system type... " >&6; }
+if test ${ac_cv_build+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_build_alias=$build_alias
+test "x$ac_build_alias" = x &&
+ ac_build_alias=`$SHELL "${ac_aux_dir}config.guess"`
+test "x$ac_build_alias" = x &&
+ as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5
+ac_cv_build=`$SHELL "${ac_aux_dir}config.sub" $ac_build_alias` ||
+ as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $ac_build_alias failed" "$LINENO" 5
+
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
+printf "%s\n" "$ac_cv_build" >&6; }
+case $ac_cv_build in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;;
+esac
+build=$ac_cv_build
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_build
+shift
+build_cpu=$1
+build_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+build_os=$*
+IFS=$ac_save_IFS
+case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
+
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
+printf %s "checking host system type... " >&6; }
+if test ${ac_cv_host+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ if test "x$host_alias" = x; then
+ ac_cv_host=$ac_cv_build
+else
+ ac_cv_host=`$SHELL "${ac_aux_dir}config.sub" $host_alias` ||
+ as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $host_alias failed" "$LINENO" 5
+fi
+
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
+printf "%s\n" "$ac_cv_host" >&6; }
+case $ac_cv_host in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;;
+esac
+host=$ac_cv_host
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_host
+shift
+host_cpu=$1
+host_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+host_os=$*
+IFS=$ac_save_IFS
+case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
+
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking target system type" >&5
+printf %s "checking target system type... " >&6; }
+if test ${ac_cv_target+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ if test "x$target_alias" = x; then
+ ac_cv_target=$ac_cv_host
+else
+ ac_cv_target=`$SHELL "${ac_aux_dir}config.sub" $target_alias` ||
+ as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $target_alias failed" "$LINENO" 5
+fi
+
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5
+printf "%s\n" "$ac_cv_target" >&6; }
+case $ac_cv_target in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical target" "$LINENO" 5;;
+esac
+target=$ac_cv_target
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_target
+shift
+target_cpu=$1
+target_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+target_os=$*
+IFS=$ac_save_IFS
+case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac
+
+
+# The aliases save the names the user supplied, while $host etc.
+# will get canonicalized.
+test -n "$target_alias" &&
+ test "$program_prefix$program_suffix$program_transform_name" = \
+ NONENONEs,x,x, &&
+ program_prefix=${target_alias}-
+
+case "$host" in
+ *-darwin*)
+ CFLAGS="$CFLAGS -DDARWIN"
+ LDFLAGS="-L/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib $LDFLAGS"
+ LIBS="-F /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/ -framework DirectoryService $LIBS"
+ ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+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
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_CC+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ 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
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ for 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"
+ printf "%s\n" "$as_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
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+printf "%s\n" "$CC" >&6; }
+else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "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
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_ac_ct_CC+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ 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
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ for 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"
+ printf "%s\n" "$as_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
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+printf "%s\n" "$ac_ct_CC" >&6; }
+else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+printf "%s\n" "$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
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_CC+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ 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
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ for 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"
+ printf "%s\n" "$as_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
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+printf "%s\n" "$CC" >&6; }
+else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "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
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_CC+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ 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
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ 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"
+ printf "%s\n" "$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
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+printf "%s\n" "$CC" >&6; }
+else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "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
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_CC+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ 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
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ for 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"
+ printf "%s\n" "$as_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
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+printf "%s\n" "$CC" >&6; }
+else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "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
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_ac_ct_CC+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ 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
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ for 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"
+ printf "%s\n" "$as_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
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+printf "%s\n" "$ac_ct_CC" >&6; }
+else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "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:)
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+fi
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args.
+set dummy ${ac_tool_prefix}clang; ac_word=$2
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_CC+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ 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
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ for 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}clang"
+ printf "%s\n" "$as_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
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+printf "%s\n" "$CC" >&6; }
+else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "clang", so it can be a program name with args.
+set dummy clang; ac_word=$2
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_ac_ct_CC+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ 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
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ for 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="clang"
+ printf "%s\n" "$as_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
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+printf "%s\n" "$ac_ct_CC" >&6; }
+else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+printf "%s\n" "$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
+
+fi
+
+
+test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+printf "%s\n" "$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.
+printf "%s\n" "$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 -version; 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\""
+printf "%s\n" "$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
+ printf "%s\n" "$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 (void)
+{
+
+ ;
+ 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.
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+printf %s "checking whether the C compiler works... " >&6; }
+ac_link_default=`printf "%s\n" "$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\""
+printf "%s\n" "$ac_try_echo"; } >&5
+ (eval "$ac_link_default") 2>&5
+ ac_status=$?
+ printf "%s\n" "$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+y} && 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 $as_nop
+ ac_file=''
+fi
+if test -z "$ac_file"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+printf "%s\n" "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+printf "%s\n" "$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_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+printf %s "checking for C compiler default output file name... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+printf "%s\n" "$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
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+printf %s "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\""
+printf "%s\n" "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ printf "%s\n" "$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_nop
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+printf "%s\n" "$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
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+printf "%s\n" "$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 (void)
+{
+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.
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+printf %s "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\""
+printf "%s\n" "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ printf "%s\n" "$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\""
+printf "%s\n" "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ printf "%s\n" "$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
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+ fi
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+printf "%s\n" "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+printf %s "checking for suffix of object files... " >&6; }
+if test ${ac_cv_objext+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main (void)
+{
+
+ ;
+ 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\""
+printf "%s\n" "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>&5
+ ac_status=$?
+ printf "%s\n" "$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_nop
+ printf "%s\n" "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+printf "%s\n" "$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
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+printf "%s\n" "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5
+printf %s "checking whether the compiler supports GNU C... " >&6; }
+if test ${ac_cv_c_compiler_gnu+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main (void)
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+ ac_compiler_gnu=yes
+else $as_nop
+ ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; }
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+if test $ac_compiler_gnu = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+y}
+ac_save_CFLAGS=$CFLAGS
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+printf %s "checking whether $CC accepts -g... " >&6; }
+if test ${ac_cv_prog_cc_g+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ 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 (void)
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+ ac_cv_prog_cc_g=yes
+else $as_nop
+ CFLAGS=""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main (void)
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+
+else $as_nop
+ ac_c_werror_flag=$ac_save_c_werror_flag
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main (void)
+{
+
+ ;
+ 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.beam conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+printf "%s\n" "$ac_cv_prog_cc_g" >&6; }
+if test $ac_test_CFLAGS; 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
+ac_prog_cc_stdc=no
+if test x$ac_prog_cc_stdc = xno
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5
+printf %s "checking for $CC option to enable C11 features... " >&6; }
+if test ${ac_cv_prog_cc_c11+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_cv_prog_cc_c11=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$ac_c_conftest_c11_program
+_ACEOF
+for ac_arg in '' -std=gnu11
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"
+then :
+ ac_cv_prog_cc_c11=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam
+ test "x$ac_cv_prog_cc_c11" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+fi
+
+if test "x$ac_cv_prog_cc_c11" = xno
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+printf "%s\n" "unsupported" >&6; }
+else $as_nop
+ if test "x$ac_cv_prog_cc_c11" = x
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+printf "%s\n" "none needed" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5
+printf "%s\n" "$ac_cv_prog_cc_c11" >&6; }
+ CC="$CC $ac_cv_prog_cc_c11"
+fi
+ ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11
+ ac_prog_cc_stdc=c11
+fi
+fi
+if test x$ac_prog_cc_stdc = xno
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5
+printf %s "checking for $CC option to enable C99 features... " >&6; }
+if test ${ac_cv_prog_cc_c99+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_cv_prog_cc_c99=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$ac_c_conftest_c99_program
+_ACEOF
+for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99=
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"
+then :
+ ac_cv_prog_cc_c99=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam
+ test "x$ac_cv_prog_cc_c99" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+fi
+
+if test "x$ac_cv_prog_cc_c99" = xno
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+printf "%s\n" "unsupported" >&6; }
+else $as_nop
+ if test "x$ac_cv_prog_cc_c99" = x
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+printf "%s\n" "none needed" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5
+printf "%s\n" "$ac_cv_prog_cc_c99" >&6; }
+ CC="$CC $ac_cv_prog_cc_c99"
+fi
+ ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99
+ ac_prog_cc_stdc=c99
+fi
+fi
+if test x$ac_prog_cc_stdc = xno
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5
+printf %s "checking for $CC option to enable C89 features... " >&6; }
+if test ${ac_cv_prog_cc_c89+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$ac_c_conftest_c89_program
+_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 conftest.beam
+ test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+fi
+
+if test "x$ac_cv_prog_cc_c89" = xno
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+printf "%s\n" "unsupported" >&6; }
+else $as_nop
+ if test "x$ac_cv_prog_cc_c89" = x
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+printf "%s\n" "none needed" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+printf "%s\n" "$ac_cv_prog_cc_c89" >&6; }
+ CC="$CC $ac_cv_prog_cc_c89"
+fi
+ ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89
+ ac_prog_cc_stdc=c89
+fi
+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=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+if test -z "$CXX"; then
+ if test -n "$CCC"; then
+ CXX=$CCC
+ else
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC clang++
+ 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
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_CXX+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ if test -n "$CXX"; then
+ ac_cv_prog_CXX="$CXX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CXX="$ac_tool_prefix$ac_prog"
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CXX=$ac_cv_prog_CXX
+if test -n "$CXX"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5
+printf "%s\n" "$CXX" >&6; }
+else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+
+
+ test -n "$CXX" && break
+ done
+fi
+if test -z "$CXX"; then
+ ac_ct_CXX=$CXX
+ for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC clang++
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_ac_ct_CXX+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ if test -n "$ac_ct_CXX"; then
+ ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ for 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_CXX="$ac_prog"
+ printf "%s\n" "$as_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_CXX=$ac_cv_prog_ac_ct_CXX
+if test -n "$ac_ct_CXX"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5
+printf "%s\n" "$ac_ct_CXX" >&6; }
+else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_CXX" && break
+done
+
+ if test "x$ac_ct_CXX" = x; then
+ CXX="g++"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CXX=$ac_ct_CXX
+ fi
+fi
+
+ fi
+fi
+# Provide some information about the compiler.
+printf "%s\n" "$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\""
+printf "%s\n" "$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
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+done
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C++" >&5
+printf %s "checking whether the compiler supports GNU C++... " >&6; }
+if test ${ac_cv_cxx_compiler_gnu+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main (void)
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"
+then :
+ ac_compiler_gnu=yes
+else $as_nop
+ ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ac_cv_cxx_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5
+printf "%s\n" "$ac_cv_cxx_compiler_gnu" >&6; }
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+if test $ac_compiler_gnu = yes; then
+ GXX=yes
+else
+ GXX=
+fi
+ac_test_CXXFLAGS=${CXXFLAGS+y}
+ac_save_CXXFLAGS=$CXXFLAGS
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5
+printf %s "checking whether $CXX accepts -g... " >&6; }
+if test ${ac_cv_prog_cxx_g+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_save_cxx_werror_flag=$ac_cxx_werror_flag
+ ac_cxx_werror_flag=yes
+ ac_cv_prog_cxx_g=no
+ CXXFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main (void)
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"
+then :
+ ac_cv_prog_cxx_g=yes
+else $as_nop
+ CXXFLAGS=""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main (void)
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"
+then :
+
+else $as_nop
+ ac_cxx_werror_flag=$ac_save_cxx_werror_flag
+ CXXFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main (void)
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"
+then :
+ ac_cv_prog_cxx_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ ac_cxx_werror_flag=$ac_save_cxx_werror_flag
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5
+printf "%s\n" "$ac_cv_prog_cxx_g" >&6; }
+if test $ac_test_CXXFLAGS; then
+ CXXFLAGS=$ac_save_CXXFLAGS
+elif test $ac_cv_prog_cxx_g = yes; then
+ if test "$GXX" = yes; then
+ CXXFLAGS="-g -O2"
+ else
+ CXXFLAGS="-g"
+ fi
+else
+ if test "$GXX" = yes; then
+ CXXFLAGS="-O2"
+ else
+ CXXFLAGS=
+ fi
+fi
+ac_prog_cxx_stdcxx=no
+if test x$ac_prog_cxx_stdcxx = xno
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CXX option to enable C++11 features" >&5
+printf %s "checking for $CXX option to enable C++11 features... " >&6; }
+if test ${ac_cv_prog_cxx_11+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_cv_prog_cxx_11=no
+ac_save_CXX=$CXX
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$ac_cxx_conftest_cxx11_program
+_ACEOF
+for ac_arg in '' -std=gnu++11 -std=gnu++0x -std=c++11 -std=c++0x -qlanglvl=extended0x -AA
+do
+ CXX="$ac_save_CXX $ac_arg"
+ if ac_fn_cxx_try_compile "$LINENO"
+then :
+ ac_cv_prog_cxx_cxx11=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam
+ test "x$ac_cv_prog_cxx_cxx11" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CXX=$ac_save_CXX
+fi
+
+if test "x$ac_cv_prog_cxx_cxx11" = xno
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+printf "%s\n" "unsupported" >&6; }
+else $as_nop
+ if test "x$ac_cv_prog_cxx_cxx11" = x
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+printf "%s\n" "none needed" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_cxx11" >&5
+printf "%s\n" "$ac_cv_prog_cxx_cxx11" >&6; }
+ CXX="$CXX $ac_cv_prog_cxx_cxx11"
+fi
+ ac_cv_prog_cxx_stdcxx=$ac_cv_prog_cxx_cxx11
+ ac_prog_cxx_stdcxx=cxx11
+fi
+fi
+if test x$ac_prog_cxx_stdcxx = xno
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CXX option to enable C++98 features" >&5
+printf %s "checking for $CXX option to enable C++98 features... " >&6; }
+if test ${ac_cv_prog_cxx_98+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_cv_prog_cxx_98=no
+ac_save_CXX=$CXX
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$ac_cxx_conftest_cxx98_program
+_ACEOF
+for ac_arg in '' -std=gnu++98 -std=c++98 -qlanglvl=extended -AA
+do
+ CXX="$ac_save_CXX $ac_arg"
+ if ac_fn_cxx_try_compile "$LINENO"
+then :
+ ac_cv_prog_cxx_cxx98=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam
+ test "x$ac_cv_prog_cxx_cxx98" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CXX=$ac_save_CXX
+fi
+
+if test "x$ac_cv_prog_cxx_cxx98" = xno
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+printf "%s\n" "unsupported" >&6; }
+else $as_nop
+ if test "x$ac_cv_prog_cxx_cxx98" = x
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+printf "%s\n" "none needed" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_cxx98" >&5
+printf "%s\n" "$ac_cv_prog_cxx_cxx98" >&6; }
+ CXX="$CXX $ac_cv_prog_cxx_cxx98"
+fi
+ ac_cv_prog_cxx_stdcxx=$ac_cv_prog_cxx_cxx98
+ ac_prog_cxx_stdcxx=cxx98
+fi
+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_header= ac_cache=
+for ac_item in $ac_header_c_list
+do
+ if test $ac_cache; then
+ ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default"
+ if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then
+ printf "%s\n" "#define $ac_item 1" >> confdefs.h
+ fi
+ ac_header= ac_cache=
+ elif test $ac_header; then
+ ac_cache=$ac_item
+ else
+ ac_header=$ac_item
+ fi
+done
+
+
+
+
+
+
+
+
+if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes
+then :
+
+printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h
+
+fi
+
+
+
+
+
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5
+printf %s "checking whether it is safe to define __EXTENSIONS__... " >&6; }
+if test ${ac_cv_safe_to_define___extensions__+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+# define __EXTENSIONS__ 1
+ $ac_includes_default
+int
+main (void)
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+ ac_cv_safe_to_define___extensions__=yes
+else $as_nop
+ ac_cv_safe_to_define___extensions__=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_safe_to_define___extensions__" >&5
+printf "%s\n" "$ac_cv_safe_to_define___extensions__" >&6; }
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether _XOPEN_SOURCE should be defined" >&5
+printf %s "checking whether _XOPEN_SOURCE should be defined... " >&6; }
+if test ${ac_cv_should_define__xopen_source+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_cv_should_define__xopen_source=no
+ if test $ac_cv_header_wchar_h = yes
+then :
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <wchar.h>
+ mbstate_t x;
+int
+main (void)
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+
+else $as_nop
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #define _XOPEN_SOURCE 500
+ #include <wchar.h>
+ mbstate_t x;
+int
+main (void)
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+ ac_cv_should_define__xopen_source=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_should_define__xopen_source" >&5
+printf "%s\n" "$ac_cv_should_define__xopen_source" >&6; }
+
+ printf "%s\n" "#define _ALL_SOURCE 1" >>confdefs.h
+
+ printf "%s\n" "#define _DARWIN_C_SOURCE 1" >>confdefs.h
+
+ printf "%s\n" "#define _GNU_SOURCE 1" >>confdefs.h
+
+ printf "%s\n" "#define _HPUX_ALT_XOPEN_SOCKET_API 1" >>confdefs.h
+
+ printf "%s\n" "#define _NETBSD_SOURCE 1" >>confdefs.h
+
+ printf "%s\n" "#define _OPENBSD_SOURCE 1" >>confdefs.h
+
+ printf "%s\n" "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h
+
+ printf "%s\n" "#define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1" >>confdefs.h
+
+ printf "%s\n" "#define __STDC_WANT_IEC_60559_BFP_EXT__ 1" >>confdefs.h
+
+ printf "%s\n" "#define __STDC_WANT_IEC_60559_DFP_EXT__ 1" >>confdefs.h
+
+ printf "%s\n" "#define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1" >>confdefs.h
+
+ printf "%s\n" "#define __STDC_WANT_IEC_60559_TYPES_EXT__ 1" >>confdefs.h
+
+ printf "%s\n" "#define __STDC_WANT_LIB_EXT2__ 1" >>confdefs.h
+
+ printf "%s\n" "#define __STDC_WANT_MATH_SPEC_FUNCS__ 1" >>confdefs.h
+
+ printf "%s\n" "#define _TANDEM_SOURCE 1" >>confdefs.h
+
+ if test $ac_cv_header_minix_config_h = yes
+then :
+ MINIX=yes
+ printf "%s\n" "#define _MINIX 1" >>confdefs.h
+
+ printf "%s\n" "#define _POSIX_SOURCE 1" >>confdefs.h
+
+ printf "%s\n" "#define _POSIX_1_SOURCE 2" >>confdefs.h
+
+else $as_nop
+ MINIX=
+fi
+ if test $ac_cv_safe_to_define___extensions__ = yes
+then :
+ printf "%s\n" "#define __EXTENSIONS__ 1" >>confdefs.h
+
+fi
+ if test $ac_cv_should_define__xopen_source = yes
+then :
+ printf "%s\n" "#define _XOPEN_SOURCE 500" >>confdefs.h
+
+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
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
+printf %s "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 test ${ac_cv_prog_CPP+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ # Double quotes because $CC needs to be expanded
+ for CPP in "$CC -E" "$CC -E -traditional-cpp" 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.
+ # 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. */
+#include <limits.h>
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"
+then :
+
+else $as_nop
+ # 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 $as_nop
+ # 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
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
+printf "%s\n" "$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.
+ # 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. */
+#include <limits.h>
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"
+then :
+
+else $as_nop
+ # 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 $as_nop
+ # 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_nop
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+printf "%s\n" "$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
+
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+printf %s "checking for grep that handles long lines and -e... " >&6; }
+if test ${ac_cv_path_GREP+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ 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
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ 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
+ printf %s 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ printf "%s\n" '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
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+printf "%s\n" "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+printf %s "checking for egrep... " >&6; }
+if test ${ac_cv_path_EGREP+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ 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
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ 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
+ printf %s 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ printf "%s\n" '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
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+printf "%s\n" "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+if test $ac_cv_c_compiler_gnu = yes; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC needs -traditional" >&5
+printf %s "checking whether $CC needs -traditional... " >&6; }
+if test ${ac_cv_prog_gcc_traditional+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_pattern="Autoconf.*'x'"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sgtty.h>
+Autoconf TIOCGETP
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "$ac_pattern" >/dev/null 2>&1
+then :
+ ac_cv_prog_gcc_traditional=yes
+else $as_nop
+ ac_cv_prog_gcc_traditional=no
+fi
+rm -rf conftest*
+
+
+ if test $ac_cv_prog_gcc_traditional = no; then
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <termio.h>
+Autoconf TCGETA
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "$ac_pattern" >/dev/null 2>&1
+then :
+ ac_cv_prog_gcc_traditional=yes
+fi
+rm -rf conftest*
+
+ fi
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_gcc_traditional" >&5
+printf "%s\n" "$ac_cv_prog_gcc_traditional" >&6; }
+ if test $ac_cv_prog_gcc_traditional = yes; then
+ CC="$CC -traditional"
+ fi
+fi
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are using SUNPro C" >&5
+printf %s "checking whether we are using SUNPro C... " >&6; }
+if test ${ac_cv_prog_suncc+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ cat > conftest.c <<EOF
+#ifdef __SUNPRO_C
+ yes;
+#endif
+EOF
+if { ac_try='${CC-cc} -E conftest.c'
+ { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; } | egrep yes >/dev/null 2>&1; then
+ ac_cv_prog_suncc=yes
+else
+ ac_cv_prog_suncc=no
+fi
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_suncc" >&5
+printf "%s\n" "$ac_cv_prog_suncc" >&6; }
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_RANLIB+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ if test -n "$RANLIB"; then
+ ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
+printf "%s\n" "$RANLIB" >&6; }
+else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+ ac_ct_RANLIB=$RANLIB
+ # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_ac_ct_RANLIB+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ if test -n "$ac_ct_RANLIB"; then
+ ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ for 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_RANLIB="ranlib"
+ printf "%s\n" "$as_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_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
+printf "%s\n" "$ac_ct_RANLIB" >&6; }
+else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+
+ if test "x$ac_ct_RANLIB" = x; then
+ RANLIB=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ RANLIB=$ac_ct_RANLIB
+ fi
+else
+ RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if compiler is clang" >&5
+printf %s "checking if compiler is clang... " >&6; }
+if test ${ax_cv_cc_clang+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main (void)
+{
+
+ #ifndef __clang__
+ not clang
+ #endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+ ax_cv_cc_clang=yes
+else $as_nop
+ ax_cv_cc_clang=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_cc_clang" >&5
+printf "%s\n" "$ax_cv_cc_clang" >&6; }
+
+if test "x$ax_cv_cc_clang" = "xyes"; then
+ clang_path="$CC"
+
+else
+ clang_path=""
+
+fi
+
+
+if test "x$GCC" = "xyes"; then
+ CFLAGS="$CFLAGS -Wall -std=c99 -D_GNU_SOURCE"
+fi
+
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for the compiler flag \"-Wno-unknown-warning-option\"" >&5
+printf %s "checking for the compiler flag \"-Wno-unknown-warning-option\"... " >&6; }
+if test ${ax_cv_cc_no_unknown_warning_option_flag+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+
+
+ CFLAGS_SAVED=$CFLAGS
+ CFLAGS="-Werror -Wno-unknown-warning-option"
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main (void)
+{
+
+ /*
+ * gcc will happily accept -Wno-unknown-warning-option
+ * only emitting an error about it, if an error ocurrs in the source file.
+ */
+ #if defined(__GNUC__) && !defined(__clang__)
+ gcc sucks
+ #endif
+
+ return 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+ ax_cv_cc_no_unknown_warning_option_flag=yes
+else $as_nop
+ ax_cv_cc_no_unknown_warning_option_flag=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+
+ CFLAGS="$CFLAGS_SAVED"
+
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_cc_no_unknown_warning_option_flag" >&5
+printf "%s\n" "$ax_cv_cc_no_unknown_warning_option_flag" >&6; }
+
+if test "x$ax_cv_cc_no_unknown_warning_option_flag" = "xyes"; then
+ CFLAGS="$CFLAGS -Wno-unknown-warning-option"
+fi
+
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for the compiler flag \"-Qunused-arguments\"" >&5
+printf %s "checking for the compiler flag \"-Qunused-arguments\"... " >&6; }
+if test ${ax_cv_cc_qunused_arguments_flag+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+
+
+ CFLAGS_SAVED=$CFLAGS
+ CFLAGS="$CFLAGS -Werror -Qunused-arguments -foobar"
+
+ 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
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main (void)
+{
+return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+ ax_cv_cc_qunused_arguments_flag="yes"
+else $as_nop
+ ax_cv_cc_qunused_arguments_flag="no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ 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
+
+
+ CFLAGS="$CFLAGS_SAVED"
+
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_cc_qunused_arguments_flag" >&5
+printf "%s\n" "$ax_cv_cc_qunused_arguments_flag" >&6; }
+
+if test "x$ax_cv_cc_qunused_arguments_flag" = "xyes"; then
+ CFLAGS="$CFLAGS -Qunused-arguments"
+ LDFLAGS="$LDFLAGS -Qunused-arguments"
+fi
+
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for the compiler flag \"-Wno-date-time\"" >&5
+printf %s "checking for the compiler flag \"-Wno-date-time\"... " >&6; }
+if test ${ax_cv_cc_no_date_time_flag+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+
+
+ CFLAGS_SAVED=$CFLAGS
+ CFLAGS="$CFLAGS -Werror -Wno-date-time"
+
+ 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
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main (void)
+{
+return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+ ax_cv_cc_no_date_time_flag="yes"
+else $as_nop
+ ax_cv_cc_no_date_time_flag="no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ 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
+
+
+ CFLAGS="$CFLAGS_SAVED"
+
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_cc_no_date_time_flag" >&5
+printf "%s\n" "$ax_cv_cc_no_date_time_flag" >&6; }
+
+
+# Check whether --enable-largefile was given.
+if test ${enable_largefile+y}
+then :
+ enableval=$enable_largefile;
+fi
+
+if test "$enable_largefile" != no; then
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5
+printf %s "checking for special C compiler options needed for large files... " >&6; }
+if test ${ac_cv_sys_largefile_CC+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_cv_sys_largefile_CC=no
+ if test "$GCC" != yes; then
+ ac_save_CC=$CC
+ while :; do
+ # IRIX 6.2 and later do not support large files by default,
+ # so use the C compiler's -n32 option if that helps.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+ We can't simply define LARGE_OFF_T to be 9223372036854775807,
+ since some C++ compilers masquerading as C compilers
+ incorrectly reject 9223372036854775807. */
+#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31))
+ int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+ && LARGE_OFF_T % 2147483647 == 1)
+ ? 1 : -1];
+int
+main (void)
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ if ac_fn_c_try_compile "$LINENO"
+then :
+ break
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam
+ CC="$CC -n32"
+ if ac_fn_c_try_compile "$LINENO"
+then :
+ ac_cv_sys_largefile_CC=' -n32'; break
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam
+ break
+ done
+ CC=$ac_save_CC
+ rm -f conftest.$ac_ext
+ fi
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5
+printf "%s\n" "$ac_cv_sys_largefile_CC" >&6; }
+ if test "$ac_cv_sys_largefile_CC" != no; then
+ CC=$CC$ac_cv_sys_largefile_CC
+ fi
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5
+printf %s "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; }
+if test ${ac_cv_sys_file_offset_bits+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ while :; do
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+ We can't simply define LARGE_OFF_T to be 9223372036854775807,
+ since some C++ compilers masquerading as C compilers
+ incorrectly reject 9223372036854775807. */
+#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31))
+ int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+ && LARGE_OFF_T % 2147483647 == 1)
+ ? 1 : -1];
+int
+main (void)
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+ ac_cv_sys_file_offset_bits=no; break
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#define _FILE_OFFSET_BITS 64
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+ We can't simply define LARGE_OFF_T to be 9223372036854775807,
+ since some C++ compilers masquerading as C compilers
+ incorrectly reject 9223372036854775807. */
+#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31))
+ int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+ && LARGE_OFF_T % 2147483647 == 1)
+ ? 1 : -1];
+int
+main (void)
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+ ac_cv_sys_file_offset_bits=64; break
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ ac_cv_sys_file_offset_bits=unknown
+ break
+done
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5
+printf "%s\n" "$ac_cv_sys_file_offset_bits" >&6; }
+case $ac_cv_sys_file_offset_bits in #(
+ no | unknown) ;;
+ *)
+printf "%s\n" "#define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits" >>confdefs.h
+;;
+esac
+rm -rf conftest*
+ if test $ac_cv_sys_file_offset_bits = unknown; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5
+printf %s "checking for _LARGE_FILES value needed for large files... " >&6; }
+if test ${ac_cv_sys_large_files+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ while :; do
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+ We can't simply define LARGE_OFF_T to be 9223372036854775807,
+ since some C++ compilers masquerading as C compilers
+ incorrectly reject 9223372036854775807. */
+#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31))
+ int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+ && LARGE_OFF_T % 2147483647 == 1)
+ ? 1 : -1];
+int
+main (void)
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+ ac_cv_sys_large_files=no; break
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#define _LARGE_FILES 1
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+ We can't simply define LARGE_OFF_T to be 9223372036854775807,
+ since some C++ compilers masquerading as C compilers
+ incorrectly reject 9223372036854775807. */
+#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31))
+ int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+ && LARGE_OFF_T % 2147483647 == 1)
+ ? 1 : -1];
+int
+main (void)
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+ ac_cv_sys_large_files=1; break
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ ac_cv_sys_large_files=unknown
+ break
+done
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5
+printf "%s\n" "$ac_cv_sys_large_files" >&6; }
+case $ac_cv_sys_large_files in #(
+ no | unknown) ;;
+ *)
+printf "%s\n" "#define _LARGE_FILES $ac_cv_sys_large_files" >>confdefs.h
+;;
+esac
+rm -rf conftest*
+ fi
+fi
+
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5
+printf %s "checking whether byte ordering is bigendian... " >&6; }
+if test ${ac_cv_c_bigendian+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_cv_c_bigendian=unknown
+ # See if we're dealing with a universal compiler.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifndef __APPLE_CC__
+ not a universal capable compiler
+ #endif
+ typedef int dummy;
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+
+ # Check for potential -arch flags. It is not universal unless
+ # there are at least two -arch flags with different values.
+ ac_arch=
+ ac_prev=
+ for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do
+ if test -n "$ac_prev"; then
+ case $ac_word in
+ i?86 | x86_64 | ppc | ppc64)
+ if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then
+ ac_arch=$ac_word
+ else
+ ac_cv_c_bigendian=universal
+ break
+ fi
+ ;;
+ esac
+ ac_prev=
+ elif test "x$ac_word" = "x-arch"; then
+ ac_prev=arch
+ fi
+ done
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ if test $ac_cv_c_bigendian = unknown; then
+ # See if sys/param.h defines the BYTE_ORDER macro.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+ #include <sys/param.h>
+
+int
+main (void)
+{
+#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \
+ && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \
+ && LITTLE_ENDIAN)
+ bogus endian macros
+ #endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+ # It does; now see whether it defined to BIG_ENDIAN or not.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+ #include <sys/param.h>
+
+int
+main (void)
+{
+#if BYTE_ORDER != BIG_ENDIAN
+ not big endian
+ #endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+ ac_cv_c_bigendian=yes
+else $as_nop
+ ac_cv_c_bigendian=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ fi
+ if test $ac_cv_c_bigendian = unknown; then
+ # See if <limits.h> defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris).
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <limits.h>
+
+int
+main (void)
+{
+#if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN)
+ bogus endian macros
+ #endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+ # It does; now see whether it defined to _BIG_ENDIAN or not.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <limits.h>
+
+int
+main (void)
+{
+#ifndef _BIG_ENDIAN
+ not big endian
+ #endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+ ac_cv_c_bigendian=yes
+else $as_nop
+ ac_cv_c_bigendian=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ fi
+ if test $ac_cv_c_bigendian = unknown; then
+ # Compile a test program.
+ if test "$cross_compiling" = yes
+then :
+ # Try to guess by grepping values from an object file.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+unsigned short int ascii_mm[] =
+ { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 };
+ unsigned short int ascii_ii[] =
+ { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 };
+ int use_ascii (int i) {
+ return ascii_mm[i] + ascii_ii[i];
+ }
+ unsigned short int ebcdic_ii[] =
+ { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 };
+ unsigned short int ebcdic_mm[] =
+ { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 };
+ int use_ebcdic (int i) {
+ return ebcdic_mm[i] + ebcdic_ii[i];
+ }
+ extern int foo;
+
+int
+main (void)
+{
+return use_ascii (foo) == use_ebcdic (foo);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+ if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then
+ ac_cv_c_bigendian=yes
+ fi
+ if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then
+ if test "$ac_cv_c_bigendian" = unknown; then
+ ac_cv_c_bigendian=no
+ else
+ # finding both strings is unlikely to happen, but who knows?
+ ac_cv_c_bigendian=unknown
+ fi
+ fi
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+else $as_nop
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$ac_includes_default
+int
+main (void)
+{
+
+ /* Are we little or big endian? From Harbison&Steele. */
+ union
+ {
+ long int l;
+ char c[sizeof (long int)];
+ } u;
+ u.l = 1;
+ return u.c[sizeof (long int) - 1] == 1;
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"
+then :
+ ac_cv_c_bigendian=no
+else $as_nop
+ ac_cv_c_bigendian=yes
+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
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5
+printf "%s\n" "$ac_cv_c_bigendian" >&6; }
+ case $ac_cv_c_bigendian in #(
+ yes)
+
+printf "%s\n" "#define FR_BIG_ENDIAN 1" >>confdefs.h
+;; #(
+ no)
+
+printf "%s\n" "#define FR_LITTLE_ENDIAN 1" >>confdefs.h
+
+ ;; #(
+ universal)
+
+printf "%s\n" "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h
+
+ ;; #(
+ *)
+ as_fn_error $? "unknown endianness
+ presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;;
+ esac
+
+
+# Extract the first word of "gmake", so it can be a program name with args.
+set dummy gmake; ac_word=$2
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_GMAKE+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ if test -n "$GMAKE"; then
+ ac_cv_prog_GMAKE="$GMAKE" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ ac_cv_prog_GMAKE="yes"
+ printf "%s\n" "$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_GMAKE" && ac_cv_prog_GMAKE="no"
+fi
+fi
+GMAKE=$ac_cv_prog_GMAKE
+if test -n "$GMAKE"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $GMAKE" >&5
+printf "%s\n" "$GMAKE" >&6; }
+else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+
+
+if test $GMAKE = no; then
+ # Extract the first word of "make", so it can be a program name with args.
+set dummy make; ac_word=$2
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_path_MAKE+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ case $MAKE in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_MAKE="$MAKE" # 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
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ 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_MAKE="$as_dir$ac_word$ac_exec_ext"
+ printf "%s\n" "$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_MAKE" && ac_cv_path_MAKE="/usr/local/bin/make"
+ ;;
+esac
+fi
+MAKE=$ac_cv_path_MAKE
+if test -n "$MAKE"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MAKE" >&5
+printf "%s\n" "$MAKE" >&6; }
+else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+
+
+else
+ # Extract the first word of "gmake", so it can be a program name with args.
+set dummy gmake; ac_word=$2
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_path_MAKE+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ case $MAKE in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_MAKE="$MAKE" # 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
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ 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_MAKE="$as_dir$ac_word$ac_exec_ext"
+ printf "%s\n" "$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_MAKE" && ac_cv_path_MAKE="/usr/local/gnu/bin/make"
+ ;;
+esac
+fi
+MAKE=$ac_cv_path_MAKE
+if test -n "$MAKE"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MAKE" >&5
+printf "%s\n" "$MAKE" >&6; }
+else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+
+
+fi
+makever=`$ac_cv_path_MAKE --version 2>&1 | grep "GNU Make"`
+if test -z "$makever"; then
+ as_fn_error $? "GNU Make is not installed. Please download and install it from ftp://prep.ai.mit.edu/pub/gnu/make/ before continuing." "$LINENO" 5
+fi
+
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking number of system cores" >&5
+printf %s "checking number of system cores... " >&6; }
+if test ${ax_cv_system_cores+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+
+ 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 "$cross_compiling" = yes
+then :
+ ax_cv_system_cores=
+
+else $as_nop
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <stdio.h>
+ #include <stdint.h>
+ #ifdef _WIN32
+ # include <windows.h>
+ #elif MACOS
+ # include <sys/param.h>
+ # include <sys/sysctl.h>
+ #else
+ # include <unistd.h>
+ #endif
+
+ int main (int argc, char *argv[])
+ {
+ uint32_t count;
+
+ #ifdef WIN32
+ SYSTEM_INFO sysinfo;
+ GetSystemInfo(&sysinfo);
+
+ count = sysinfo.dwNumberOfProcessors;
+
+ #elif MACOS
+ int nm[2];
+ size_t len = 4;
+
+ nm[0] = CTL_HW;
+ nm[1] = HW_AVAILCPU;
+ sysctl(nm, 2, &count, &len, NULL, 0);
+
+ if(count < 1) {
+ nm[1] = HW_NCPU;
+ sysctl(nm, 2, &count, &len, NULL, 0);
+ if(count < 1) {
+ count = 1;
+ }
+ }
+
+ #else
+ count = sysconf(_SC_NPROCESSORS_ONLN);
+ #endif
+
+ return count;
+ }
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"
+then :
+ ax_cv_system_cores=$?
+else $as_nop
+ ax_cv_system_cores=$?
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+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
+
+
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_system_cores" >&5
+printf "%s\n" "$ax_cv_system_cores" >&6; }
+
+
+
+
+# Extract the first word of "git", so it can be a program name with args.
+set dummy git; ac_word=$2
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_GIT+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ if test -n "$GIT"; then
+ ac_cv_prog_GIT="$GIT" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ ac_cv_prog_GIT="yes"
+ printf "%s\n" "$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_GIT" && ac_cv_prog_GIT="no"
+fi
+fi
+GIT=$ac_cv_prog_GIT
+if test -n "$GIT"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $GIT" >&5
+printf "%s\n" "$GIT" >&6; }
+else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+
+
+
+
+# Check whether --enable-strict-dependencies was given.
+if test ${enable_strict_dependencies+y}
+then :
+ enableval=$enable_strict_dependencies;
+fi
+
+
+# Check whether --enable-werror was given.
+if test ${enable_werror+y}
+then :
+ enableval=$enable_werror; case "$enableval" in
+ no)
+ werror=no
+ ;;
+ *)
+ werror=yes
+ esac
+
+fi
+
+
+docdir='${datadir}/doc/freeradius'
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking docdir" >&5
+printf %s "checking docdir... " >&6; }
+
+# Check whether --with-docdir was given.
+if test ${with_docdir+y}
+then :
+ withval=$with_docdir; case "$withval" in
+ no)
+ docdir=no
+ ;;
+ yes)
+ ;;
+ [\\/$]* | ?:[\\/]* )
+ docdir="$withval"
+ ;;
+ *)
+ as_fn_error $? "expected an absolute directory name for --with-docdir: $withval" "$LINENO" 5
+ ;;
+ esac
+
+fi
+
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $docdir" >&5
+printf "%s\n" "$docdir" >&6; }
+if test "x$docdir" = xno; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Documentation files will NOT be installed." >&5
+printf "%s\n" "$as_me: WARNING: Documentation files will NOT be installed." >&2;}
+fi
+
+logdir='${localstatedir}/log/radius'
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking logdir" >&5
+printf %s "checking logdir... " >&6; }
+
+# Check whether --with-logdir was given.
+if test ${with_logdir+y}
+then :
+ withval=$with_logdir; case "$withval" in
+ no)
+ as_fn_error $? "Need logdir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ [\\/$]* | ?:[\\/]* )
+ logdir="$withval"
+ ;;
+ *)
+ as_fn_error $? "expected an absolute directory name for --with-logdir: $withval" "$LINENO" 5
+ ;;
+ esac
+
+fi
+
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $logdir" >&5
+printf "%s\n" "$logdir" >&6; }
+
+radacctdir='${logdir}/radacct'
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking radacctdir" >&5
+printf %s "checking radacctdir... " >&6; }
+
+# Check whether --with-radacctdir was given.
+if test ${with_radacctdir+y}
+then :
+ withval=$with_radacctdir; case "$withval" in
+ no)
+ as_fn_error $? "Need radacctdir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ [\\/$]* | ?:[\\/]* )
+ radacctdir="$withval"
+ ;;
+ *)
+ as_fn_error $? "expected an absolute directory name for --with-radacctdir: $withval" "$LINENO" 5
+ ;;
+ esac
+
+fi
+
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $radacctdir" >&5
+printf "%s\n" "$radacctdir" >&6; }
+
+raddbdir='${sysconfdir}/raddb'
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking raddbdir" >&5
+printf %s "checking raddbdir... " >&6; }
+
+# Check whether --with-raddbdir was given.
+if test ${with_raddbdir+y}
+then :
+ withval=$with_raddbdir; case "$withval" in
+ no)
+ as_fn_error $? "Need raddbdir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ [\\/$]* | ?:[\\/]* )
+ raddbdir="$withval"
+ ;;
+ *)
+ as_fn_error $? "expected an absolute directory name for --with-raddbdir: $withval" "$LINENO" 5
+ ;;
+ esac
+
+fi
+
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $raddbdir" >&5
+printf "%s\n" "$raddbdir" >&6; }
+
+dictdir='${datarootdir}/freeradius'
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dictdir" >&5
+printf %s "checking dictdir... " >&6; }
+
+# Check whether --with-dictdir was given.
+if test ${with_dictdir+y}
+then :
+ withval=$with_dictdir; case "$withval" in
+ no)
+ as_fn_error $? "Need dictdir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ [\\/$]* | ?:[\\/]* )
+ dictdir="$withval"
+ ;;
+ *)
+ as_fn_error $? "expected an absolute directory name for --with-dictdir: $withval" "$LINENO" 5
+ ;;
+ esac
+
+fi
+
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $dictdir" >&5
+printf "%s\n" "$dictdir" >&6; }
+
+modconfdir='${raddbdir}/mods-config'
+
+
+WITH_ASCEND_BINARY=yes
+
+# Check whether --with-ascend-binary was given.
+if test ${with_ascend_binary+y}
+then :
+ withval=$with_ascend_binary; case "$withval" in
+ yes)
+ ;;
+ *)
+ WITH_ASCEND_BINARY=no
+ esac
+
+fi
+
+if test "x$WITH_ASCEND_BINARY" = "xyes"; then
+
+printf "%s\n" "#define WITH_ASCEND_BINARY 1" >>confdefs.h
+
+fi
+
+WITH_RADIUSV11=
+
+# Check whether --with-radiusv11 was given.
+if test ${with_radiusv11+y}
+then :
+ withval=$with_radiusv11; case "$withval" in
+ yes)
+ WITH_RADIUSV11=yes
+ ;;
+ *)
+ ;;
+ esac
+
+fi
+
+if test "x$WITH_RADIUSCV11" = "xyes"; then
+
+printf "%s\n" "#define WITH_RADIUSV11 1" >>confdefs.h
+
+fi
+
+WITH_THREADS=yes
+
+# Check whether --with-threads was given.
+if test ${with_threads+y}
+then :
+ withval=$with_threads; case "$withval" in
+ yes)
+ ;;
+ *)
+ WITH_THREADS=no
+ esac
+
+fi
+
+
+WITH_TCP=yes
+
+# Check whether --with-tcp was given.
+if test ${with_tcp+y}
+then :
+ withval=$with_tcp; case "$withval" in
+ yes)
+ ;;
+ *)
+ WITH_TCP=no
+ esac
+
+fi
+
+if test "x$WITH_TCP" = "xyes"; then
+
+printf "%s\n" "#define WITH_TCP 1" >>confdefs.h
+
+fi
+
+WITH_VMPS=yes
+
+# Check whether --with-vmps was given.
+if test ${with_vmps+y}
+then :
+ withval=$with_vmps; case "$withval" in
+ yes)
+ ;;
+ *)
+ WITH_VMPS=no
+ esac
+
+fi
+
+if test "x$WITH_VMPS" = "xyes"; then
+
+printf "%s\n" "#define WITH_VMPS 1" >>confdefs.h
+
+fi
+
+WITH_DHCP=yes
+
+# Check whether --with-dhcp was given.
+if test ${with_dhcp+y}
+then :
+ withval=$with_dhcp; case "$withval" in
+ yes)
+ ;;
+ *)
+ WITH_DHCP=no
+ esac
+
+fi
+
+if test "x$WITH_DHCP" = "xyes"; then
+
+printf "%s\n" "#define WITH_DHCP 1" >>confdefs.h
+
+fi
+
+
+STATIC_MODULES=
+
+# Check whether --with-static_modules was given.
+if test ${with_static_modules+y}
+then :
+ withval=$with_static_modules;
+ for i in $withval; do
+ STATIC_MODULES="$STATIC_MODULES -dlpreopen ../modules/rlm_$i/rlm_$i.la"
+ done
+
+fi
+
+
+USE_SHARED_LIBS=yes
+
+# Check whether --with-shared-libs was given.
+if test ${with_shared_libs+y}
+then :
+ withval=$with_shared_libs; case "$withval" in
+ no)
+ USE_SHARED_LIBS=no
+ ;;
+ *)
+ esac
+
+fi
+
+
+MODULES=
+
+# Check whether --with-modules was given.
+if test ${with_modules+y}
+then :
+ withval=$with_modules;
+ for i in $withval; do
+ MODULES="$MODULES $i"
+ done
+
+fi
+
+
+EXPERIMENTAL=
+
+# Check whether --with-experimental-modules was given.
+if test ${with_experimental_modules+y}
+then :
+ withval=$with_experimental_modules; case "$withval" in
+ yes)
+ EXPERIMENTAL=yes
+ ;;
+ no)
+ EXPERIMENTAL=no
+ ;;
+ *)
+ esac
+
+fi
+
+
+WITH_UDPFROMTO=yes
+
+# Check whether --with-udpfromto was given.
+if test ${with_udpfromto+y}
+then :
+ withval=$with_udpfromto; case "$withval" in
+ yes)
+ WITH_UDPFROMTO=yes
+ ;;
+ *)
+ WITH_UDPFROMTO=no
+ esac
+
+fi
+
+
+if test "x$WITH_UDPFROMTO" = "xyes"; then
+
+printf "%s\n" "#define WITH_UDPFROMTO /**/" >>confdefs.h
+
+fi
+
+
+
+# Check whether --with-rlm-FOO-lib-dir was given.
+if test ${with_rlm_FOO_lib_dir+y}
+then :
+ withval=$with_rlm_FOO_lib_dir; case "$withval" in
+ *)
+ ;;
+ esac
+
+fi
+
+
+
+# Check whether --with-rlm-FOO-include-dir was given.
+if test ${with_rlm_FOO_include_dir+y}
+then :
+ withval=$with_rlm_FOO_include_dir; case "$withval" in
+ *)
+ ;;
+ esac
+
+fi
+
+
+WITH_OPENSSL=yes
+
+# Check whether --with-openssl was given.
+if test ${with_openssl+y}
+then :
+ withval=$with_openssl; case "$withval" in
+ no)
+ WITH_OPENSSL=no
+ ;;
+ *)
+ WITH_OPENSSL=yes
+ ;;
+ esac
+
+fi
+
+if test "x$WITH_THREADS" = "xno"; then
+ if test "x$WITH_OPENSSL" = "xyes"; then
+ as_fn_error $? "Threads are required when using OpenSSL, use --with-threads=yes" "$LINENO" 5
+ fi
+fi
+
+openssl_lib_dir=
+
+# Check whether --with-openssl-lib-dir was given.
+if test ${with_openssl_lib_dir+y}
+then :
+ withval=$with_openssl_lib_dir; case "$withval" in
+ *) openssl_lib_dir="$withval"
+ ;;
+ esac
+
+fi
+
+
+openssl_include_dir=
+
+# Check whether --with-openssl-include-dir was given.
+if test ${with_openssl_include_dir+y}
+then :
+ withval=$with_openssl_include_dir; case "$withval" in
+ *) openssl_include_dir="$withval"
+ ;;
+ esac
+
+fi
+
+
+# Check whether --enable-openssl-version-check was given.
+if test ${enable_openssl_version_check+y}
+then :
+ enableval=$enable_openssl_version_check;
+fi
+
+if test "x$enable_openssl_version_check" != "xno"; then
+
+printf "%s\n" "#define ENABLE_OPENSSL_VERSION_CHECK 1" >>confdefs.h
+
+ openssl_version_check_config="\
+ #
+ # allow_vulnerable_openssl: Allow the server to start with
+ # versions of OpenSSL known to have critical vulnerabilities.
+ #
+ # This check is based on the version number reported by libssl
+ # and may not reflect patches applied to libssl by
+ # distribution maintainers.
+ #
+ allow_vulnerable_openssl = no"
+else
+ openssl_version_check_config=
+fi
+
+
+# Check whether --enable-reproducible-builds was given.
+if test ${enable_reproducible_builds+y}
+then :
+ enableval=$enable_reproducible_builds; case "$enableval" in
+ yes)
+
+printf "%s\n" "#define ENABLE_REPRODUCIBLE_BUILDS 1" >>confdefs.h
+
+ reproducible_builds=yes
+ ;;
+ *)
+ reproducible_builds=no
+ esac
+
+fi
+
+
+# Check whether --enable-fuzzer was given.
+if test ${enable_fuzzer+y}
+then :
+ enableval=$enable_fuzzer; case "$enableval" in
+ no)
+ fuzzer=no
+ ;;
+ *)
+ fuzzer=yes
+ esac
+
+fi
+
+
+# Check whether --enable-address-sanitizer was given.
+if test ${enable_address_sanitizer+y}
+then :
+ enableval=$enable_address_sanitizer; case "$enableval" in
+ no)
+ address_sanitizer=no
+ ;;
+ *)
+ address_sanitizer=yes
+ esac
+
+fi
+
+
+# Check whether --enable-leak-sanitizer was given.
+if test ${enable_leak_sanitizer+y}
+then :
+ enableval=$enable_leak_sanitizer; case "$enableval" in
+ no)
+ leak_sanitizer=no
+ ;;
+ *)
+ leak_sanitizer=yes
+ esac
+
+fi
+
+
+# Check whether --enable-thread-sanitizer was given.
+if test ${enable_thread_sanitizer+y}
+then :
+ enableval=$enable_thread_sanitizer; case "$enableval" in
+ no)
+ thread_sanitizer=no
+ ;;
+ *)
+ thread_sanitizer=yes
+ esac
+
+fi
+
+
+# Check whether --enable-undefined-behaviour-sanitizer was given.
+if test ${enable_undefined_behaviour_sanitizer+y}
+then :
+ enableval=$enable_undefined_behaviour_sanitizer; case "$enableval" in
+ no)
+ undefined_behaviour_sanitizer=no
+ ;;
+ *)
+ undefined_behaviour_sanitizer=yes
+ esac
+
+fi
+
+
+
+CHECKRAD=checkrad
+# Extract the first word of "perl", so it can be a program name with args.
+set dummy perl; ac_word=$2
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_path_PERL+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ case $PERL in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_PERL="$PERL" # 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
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ 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"
+ printf "%s\n" "$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="/usr/local/bin/perl"
+ ;;
+esac
+fi
+PERL=$ac_cv_path_PERL
+if test -n "$PERL"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PERL" >&5
+printf "%s\n" "$PERL" >&6; }
+else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+
+
+if test "x$ac_cv_path_PERL" = "x"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: perl not found - Simultaneous-Use and checkrad may not work" >&5
+printf "%s\n" "$as_me: WARNING: perl not found - Simultaneous-Use and checkrad may not work" >&2;}
+fi
+# Extract the first word of "snmpget", so it can be a program name with args.
+set dummy snmpget; ac_word=$2
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_path_SNMPGET+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ case $SNMPGET in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_SNMPGET="$SNMPGET" # 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
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ 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_SNMPGET="$as_dir$ac_word$ac_exec_ext"
+ printf "%s\n" "$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
+SNMPGET=$ac_cv_path_SNMPGET
+if test -n "$SNMPGET"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $SNMPGET" >&5
+printf "%s\n" "$SNMPGET" >&6; }
+else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+
+
+if test "x$ac_cv_path_SNMPGET" = "x"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: snmpget not found - Simultaneous-Use and checkrad may not work" >&5
+printf "%s\n" "$as_me: WARNING: snmpget not found - Simultaneous-Use and checkrad may not work" >&2;}
+fi
+
+# Extract the first word of "snmpwalk", so it can be a program name with args.
+set dummy snmpwalk; ac_word=$2
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_path_SNMPWALK+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ case $SNMPWALK in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_SNMPWALK="$SNMPWALK" # 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
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ 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_SNMPWALK="$as_dir$ac_word$ac_exec_ext"
+ printf "%s\n" "$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
+SNMPWALK=$ac_cv_path_SNMPWALK
+if test -n "$SNMPWALK"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $SNMPWALK" >&5
+printf "%s\n" "$SNMPWALK" >&6; }
+else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+
+
+if test "x$ac_cv_path_SNMPWALK" = "x"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: snmpwalk not found - Simultaneous-Use and checkrad may not work" >&5
+printf "%s\n" "$as_me: WARNING: snmpwalk not found - Simultaneous-Use and checkrad may not work" >&2;}
+fi
+
+# Extract the first word of "rusers", so it can be a program name with args.
+set dummy rusers; ac_word=$2
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_path_RUSERS+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ case $RUSERS in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_RUSERS="$RUSERS" # 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
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ 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_RUSERS="$as_dir$ac_word$ac_exec_ext"
+ printf "%s\n" "$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_RUSERS" && ac_cv_path_RUSERS="/usr/bin/rusers"
+ ;;
+esac
+fi
+RUSERS=$ac_cv_path_RUSERS
+if test -n "$RUSERS"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $RUSERS" >&5
+printf "%s\n" "$RUSERS" >&6; }
+else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+
+
+
+missing_dir=`cd $ac_aux_dir && pwd`
+
+# Expand $ac_aux_dir to an absolute path.
+am_aux_dir=`cd "$ac_aux_dir" && pwd`
+
+
+ if test x"${MISSING+set}" != xset; then
+ MISSING="\${SHELL} '$am_aux_dir/missing'"
+fi
+# Use eval to expand $SHELL
+if eval "$MISSING --is-lightweight"; then
+ am_missing_run="$MISSING "
+else
+ am_missing_run=
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5
+printf "%s\n" "$as_me: WARNING: 'missing' script is too old or missing" >&2;}
+fi
+
+
+ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal"}
+
+
+AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"}
+
+
+AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"}
+
+
+# Extract the first word of "dirname", so it can be a program name with args.
+set dummy dirname; ac_word=$2
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_path_DIRNAME+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ case $DIRNAME in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_DIRNAME="$DIRNAME" # 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
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ 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_DIRNAME="$as_dir$ac_word$ac_exec_ext"
+ printf "%s\n" "$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
+DIRNAME=$ac_cv_path_DIRNAME
+if test -n "$DIRNAME"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DIRNAME" >&5
+printf "%s\n" "$DIRNAME" >&6; }
+else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+
+
+# Extract the first word of "grep", so it can be a program name with args.
+set dummy grep; ac_word=$2
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_path_GREP+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ case $GREP in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_GREP="$GREP" # 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
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ 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_GREP="$as_dir$ac_word$ac_exec_ext"
+ printf "%s\n" "$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
+GREP=$ac_cv_path_GREP
+if test -n "$GREP"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $GREP" >&5
+printf "%s\n" "$GREP" >&6; }
+else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+
+
+
+
+talloc_lib_dir=
+
+# Check whether --with-talloc-lib-dir was given.
+if test ${with_talloc_lib_dir+y}
+then :
+ withval=$with_talloc_lib_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need talloc-lib-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ talloc_lib_dir="$withval"
+ ;;
+ esac
+fi
+
+
+talloc_include_dir=
+
+# Check whether --with-talloc-include-dir was given.
+if test ${with_talloc_include_dir+y}
+then :
+ withval=$with_talloc_include_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need talloc-include-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ talloc_include_dir="$withval"
+ ;;
+ esac
+fi
+
+
+smart_try_dir="$talloc_lib_dir"
+
+
+sm_lib_safe=`echo "talloc" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "_talloc" | sed 'y%./+-%__p_%'`
+
+old_LIBS="$LIBS"
+old_CPPFLAGS="$CPPFLAGS"
+smart_lib=
+smart_ldflags=
+smart_lib_dir=
+
+if test "x$smart_try_dir" != "x"; then
+ for try in $smart_try_dir; do
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for _talloc in -ltalloc in $try" >&5
+printf %s "checking for _talloc in -ltalloc in $try... " >&6; }
+ LIBS="-ltalloc $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char _talloc();
+int
+main (void)
+{
+_talloc()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+
+ smart_lib="-ltalloc"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+ LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_lib" = "x"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for _talloc in -ltalloc" >&5
+printf %s "checking for _talloc in -ltalloc... " >&6; }
+ LIBS="-ltalloc $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char _talloc();
+int
+main (void)
+{
+_talloc()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+
+ smart_lib="-ltalloc"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ 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
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for _talloc in -ltalloc in $try" >&5
+printf %s "checking for _talloc in -ltalloc in $try... " >&6; }
+ LIBS="-ltalloc $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char _talloc();
+int
+main (void)
+{
+_talloc()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+
+ smart_lib="-ltalloc"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+ LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_lib" != "x"; then
+ eval "ac_cv_lib_${sm_lib_safe}_${sm_func_safe}=yes"
+ LIBS="$smart_ldflags $smart_lib $old_LIBS"
+ SMART_LIBS="$smart_ldflags $smart_lib $SMART_LIBS"
+fi
+
+if test "x$ac_cv_lib_talloc__talloc" != "xyes"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: talloc library not found. Use --with-talloc-lib-dir=<path>." >&5
+printf "%s\n" "$as_me: WARNING: talloc library not found. Use --with-talloc-lib-dir=<path>." >&2;}
+ as_fn_error $? "FreeRADIUS requires libtalloc" "$LINENO" 5
+fi
+
+TALLOC_LIBS="${smart_lib}"
+TALLOC_LDFLAGS="${smart_ldflags}"
+
+
+LIBS="$old_LIBS"
+
+old_CFLAGS=$CFLAGS
+if test "x$WITH_THREADS" = "xyes"; then
+ if test $ac_cv_prog_suncc = "yes"; then
+ CFLAGS="$CFLAGS -mt"
+ fi
+
+ for ac_header in pthread.h
+do :
+ ac_fn_c_check_header_compile "$LINENO" "pthread.h" "ac_cv_header_pthread_h" "$ac_includes_default"
+if test "x$ac_cv_header_pthread_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_PTHREAD_H 1" >>confdefs.h
+
+else $as_nop
+
+ WITH_THREADS="no"
+ fail=pthread.h
+
+fi
+
+done
+
+ if test "x$WITH_THREADS" != "xno"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5
+printf %s "checking for pthread_create in -lpthread... " >&6; }
+if test ${ac_cv_lib_pthread_pthread_create+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpthread $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. */
+char pthread_create ();
+int
+main (void)
+{
+return pthread_create ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+ ac_cv_lib_pthread_pthread_create=yes
+else $as_nop
+ ac_cv_lib_pthread_pthread_create=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create" >&5
+printf "%s\n" "$ac_cv_lib_pthread_pthread_create" >&6; }
+if test "x$ac_cv_lib_pthread_pthread_create" = xyes
+then :
+
+ HAVE_LPTHREAD='yes'
+ CFLAGS="$CFLAGS -D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS"
+ LIBS="-lpthread $LIBS"
+
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for the compiler flag \"-pthread\"" >&5
+printf %s "checking for the compiler flag \"-pthread\"... " >&6; }
+if test ${ax_cv_cc_pthread_flag+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+
+
+ CFLAGS_SAVED=$CFLAGS
+ CFLAGS="$CFLAGS -Werror -pthread"
+
+ 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
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main (void)
+{
+return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+ ax_cv_cc_pthread_flag="yes"
+else $as_nop
+ ax_cv_cc_pthread_flag="no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ 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
+
+
+ CFLAGS="$CFLAGS_SAVED"
+
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_cc_pthread_flag" >&5
+printf "%s\n" "$ax_cv_cc_pthread_flag" >&6; }
+
+ if test "x$ax_cv_cc_pthread_flag" != 'xyes'; then
+ CFLAGS="$CFLAGS -pthread"
+ fi
+
+
+fi
+
+
+ if test "x$HAVE_LPTHREAD" != "xyes"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lc_r" >&5
+printf %s "checking for pthread_create in -lc_r... " >&6; }
+if test ${ac_cv_lib_c_r_pthread_create+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lc_r $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. */
+char pthread_create ();
+int
+main (void)
+{
+return pthread_create ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+ ac_cv_lib_c_r_pthread_create=yes
+else $as_nop
+ ac_cv_lib_c_r_pthread_create=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_r_pthread_create" >&5
+printf "%s\n" "$ac_cv_lib_c_r_pthread_create" >&6; }
+if test "x$ac_cv_lib_c_r_pthread_create" = xyes
+then :
+
+ CFLAGS="$CFLAGS -D_THREAD_SAFE"
+
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for the compiler flag \"-pthread\"" >&5
+printf %s "checking for the compiler flag \"-pthread\"... " >&6; }
+if test ${ax_cv_cc_pthread_flag+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+
+
+ CFLAGS_SAVED=$CFLAGS
+ CFLAGS="$CFLAGS -Werror -pthread"
+
+ 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
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main (void)
+{
+return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+ ax_cv_cc_pthread_flag="yes"
+else $as_nop
+ ax_cv_cc_pthread_flag="no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ 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
+
+
+ CFLAGS="$CFLAGS_SAVED"
+
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_cc_pthread_flag" >&5
+printf "%s\n" "$ax_cv_cc_pthread_flag" >&6; }
+
+ if test "x$ax_cv_cc_pthread_flag" != 'xyes'; then
+ LIBS="-lc_r $LIBS"
+ else
+ CFLAGS="$CFLAGS -pthread"
+ fi
+
+else $as_nop
+ fail=-lc_r or -lpthread
+
+fi
+
+ fi
+ fi
+
+ if test "x$WITH_THREADS" != "xyes"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: silently not building with thread support." >&5
+printf "%s\n" "$as_me: WARNING: silently not building with thread support." >&2;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: thread support requires: $fail." >&5
+printf "%s\n" "$as_me: WARNING: FAILURE: thread support requires: $fail." >&2;}
+ else
+
+printf "%s\n" "#define WITH_THREADS 1" >>confdefs.h
+
+ fi
+fi
+
+if test "x$WITH_THREADS" != "xyes"; then
+ CFLAGS=$old_CFLAGS
+ ac_cv_header_pthread_h="no"
+ WITH_THREADS=no
+else
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing sem_init" >&5
+printf %s "checking for library containing sem_init... " >&6; }
+if test ${ac_cv_search_sem_init+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_func_search_save_LIBS=$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. */
+char sem_init ();
+int
+main (void)
+{
+return sem_init ();
+ ;
+ return 0;
+}
+_ACEOF
+for ac_lib in '' pthread sem posix4 rt semaphore
+do
+ if test -z "$ac_lib"; then
+ ac_res="none required"
+ else
+ ac_res=-l$ac_lib
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ fi
+ if ac_fn_c_try_link "$LINENO"
+then :
+ ac_cv_search_sem_init=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext
+ if test ${ac_cv_search_sem_init+y}
+then :
+ break
+fi
+done
+if test ${ac_cv_search_sem_init+y}
+then :
+
+else $as_nop
+ ac_cv_search_sem_init=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_sem_init" >&5
+printf "%s\n" "$ac_cv_search_sem_init" >&6; }
+ac_res=$ac_cv_search_sem_init
+if test "$ac_res" != no
+then :
+ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+else $as_nop
+ as_fn_error $? "-lsem not found. You may want to download it from ftp://ftp.to.gd-es.com/pub/BSDI/libsem.tar.bz2 or ftp://ftp.freeradius.org/pub/radius/contrib/libsem.tar.gz" "$LINENO" 5
+
+fi
+
+fi
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
+printf %s "checking for dlopen in -ldl... " >&6; }
+if test ${ac_cv_lib_dl_dlopen+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ 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. */
+char dlopen ();
+int
+main (void)
+{
+return dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+ ac_cv_lib_dl_dlopen=yes
+else $as_nop
+ ac_cv_lib_dl_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
+printf "%s\n" "$ac_cv_lib_dl_dlopen" >&6; }
+if test "x$ac_cv_lib_dl_dlopen" = xyes
+then :
+ printf "%s\n" "#define HAVE_LIBDL 1" >>confdefs.h
+
+ LIBS="-ldl $LIBS"
+
+fi
+
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for getsockname in -lsocket" >&5
+printf %s "checking for getsockname in -lsocket... " >&6; }
+if test ${ac_cv_lib_socket_getsockname+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsocket $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. */
+char getsockname ();
+int
+main (void)
+{
+return getsockname ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+ ac_cv_lib_socket_getsockname=yes
+else $as_nop
+ ac_cv_lib_socket_getsockname=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_getsockname" >&5
+printf "%s\n" "$ac_cv_lib_socket_getsockname" >&6; }
+if test "x$ac_cv_lib_socket_getsockname" = xyes
+then :
+ printf "%s\n" "#define HAVE_LIBSOCKET 1" >>confdefs.h
+
+ LIBS="-lsocket $LIBS"
+
+fi
+
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for inet_aton in -lresolv" >&5
+printf %s "checking for inet_aton in -lresolv... " >&6; }
+if test ${ac_cv_lib_resolv_inet_aton+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lresolv $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. */
+char inet_aton ();
+int
+main (void)
+{
+return inet_aton ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+ ac_cv_lib_resolv_inet_aton=yes
+else $as_nop
+ ac_cv_lib_resolv_inet_aton=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_resolv_inet_aton" >&5
+printf "%s\n" "$ac_cv_lib_resolv_inet_aton" >&6; }
+if test "x$ac_cv_lib_resolv_inet_aton" = xyes
+then :
+ printf "%s\n" "#define HAVE_LIBRESOLV 1" >>confdefs.h
+
+ LIBS="-lresolv $LIBS"
+
+fi
+
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for inet_ntoa in -lnsl" >&5
+printf %s "checking for inet_ntoa in -lnsl... " >&6; }
+if test ${ac_cv_lib_nsl_inet_ntoa+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lnsl $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. */
+char inet_ntoa ();
+int
+main (void)
+{
+return inet_ntoa ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+ ac_cv_lib_nsl_inet_ntoa=yes
+else $as_nop
+ ac_cv_lib_nsl_inet_ntoa=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_inet_ntoa" >&5
+printf "%s\n" "$ac_cv_lib_nsl_inet_ntoa" >&6; }
+if test "x$ac_cv_lib_nsl_inet_ntoa" = xyes
+then :
+ printf "%s\n" "#define HAVE_LIBNSL 1" >>confdefs.h
+
+ LIBS="-lnsl $LIBS"
+
+fi
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for htonl in -lws2_32" >&5
+printf %s "checking for htonl in -lws2_32... " >&6; }
+if test ${ac_cv_lib_ws2_32_htonl+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lws2_32 $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. */
+char htonl ();
+int
+main (void)
+{
+return htonl ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+ ac_cv_lib_ws2_32_htonl=yes
+else $as_nop
+ ac_cv_lib_ws2_32_htonl=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ws2_32_htonl" >&5
+printf "%s\n" "$ac_cv_lib_ws2_32_htonl" >&6; }
+if test "x$ac_cv_lib_ws2_32_htonl" = xyes
+then :
+ printf "%s\n" "#define HAVE_LIBWS2_32 1" >>confdefs.h
+
+ LIBS="-lws2_32 $LIBS"
+
+fi
+
+
+pcap_lib_dir=
+
+# Check whether --with-pcap-lib-dir was given.
+if test ${with_pcap_lib_dir+y}
+then :
+ withval=$with_pcap_lib_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need pcap-lib-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ pcap_lib_dir="$withval"
+ ;;
+ esac
+fi
+
+
+pcap_include_dir=
+
+# Check whether --with-pcap-include-dir was given.
+if test ${with_pcap_include_dir+y}
+then :
+ withval=$with_pcap_include_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need pcap-include-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ pcap_include_dir="$withval"
+ ;;
+ esac
+fi
+
+
+smart_try_dir="$pcap_lib_dir"
+
+
+sm_lib_safe=`echo "pcap" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "pcap_open_live" | sed 'y%./+-%__p_%'`
+
+old_LIBS="$LIBS"
+old_CPPFLAGS="$CPPFLAGS"
+smart_lib=
+smart_ldflags=
+smart_lib_dir=
+
+if test "x$smart_try_dir" != "x"; then
+ for try in $smart_try_dir; do
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pcap_open_live in -lpcap in $try" >&5
+printf %s "checking for pcap_open_live in -lpcap in $try... " >&6; }
+ LIBS="-lpcap $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char pcap_open_live();
+int
+main (void)
+{
+pcap_open_live()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+
+ smart_lib="-lpcap"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+ LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_lib" = "x"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pcap_open_live in -lpcap" >&5
+printf %s "checking for pcap_open_live in -lpcap... " >&6; }
+ LIBS="-lpcap $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char pcap_open_live();
+int
+main (void)
+{
+pcap_open_live()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+
+ smart_lib="-lpcap"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ 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
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pcap_open_live in -lpcap in $try" >&5
+printf %s "checking for pcap_open_live in -lpcap in $try... " >&6; }
+ LIBS="-lpcap $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char pcap_open_live();
+int
+main (void)
+{
+pcap_open_live()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+
+ smart_lib="-lpcap"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ 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_pcap_pcap_open_live" != "xyes"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: pcap library not found, silently disabling the RADIUS sniffer, and ARP listener. Use --with-pcap-lib-dir=<path>." >&5
+printf "%s\n" "$as_me: WARNING: pcap library not found, silently disabling the RADIUS sniffer, and ARP listener. Use --with-pcap-lib-dir=<path>." >&2;}
+else
+ ac_fn_c_check_func "$LINENO" "pcap_fopen_offline" "ac_cv_func_pcap_fopen_offline"
+if test "x$ac_cv_func_pcap_fopen_offline" = xyes
+then :
+ printf "%s\n" "#define HAVE_PCAP_FOPEN_OFFLINE 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "pcap_dump_fopen" "ac_cv_func_pcap_dump_fopen"
+if test "x$ac_cv_func_pcap_dump_fopen" = xyes
+then :
+ printf "%s\n" "#define HAVE_PCAP_DUMP_FOPEN 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "pcap_create" "ac_cv_func_pcap_create"
+if test "x$ac_cv_func_pcap_create" = xyes
+then :
+ printf "%s\n" "#define HAVE_PCAP_CREATE 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "pcap_activate" "ac_cv_func_pcap_activate"
+if test "x$ac_cv_func_pcap_activate" = xyes
+then :
+ printf "%s\n" "#define HAVE_PCAP_ACTIVATE 1" >>confdefs.h
+
+fi
+
+
+ PCAP_LIBS="${smart_lib}"
+ PCAP_LDFLAGS="${smart_ldflags}"
+fi
+LIBS="${old_LIBS}"
+
+collectdclient_lib_dir=
+
+# Check whether --with-collectdclient-lib-dir was given.
+if test ${with_collectdclient_lib_dir+y}
+then :
+ withval=$with_collectdclient_lib_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need collectdclient-lib-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ collectdclient_lib_dir="$withval"
+ ;;
+ esac
+fi
+
+
+collectdclient_include_dir=
+
+# Check whether --with-collectdclient-include-dir was given.
+if test ${with_collectdclient_include_dir+y}
+then :
+ withval=$with_collectdclient_include_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need collectdclient-include-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ collectdclient_include_dir="$withval"
+ ;;
+ esac
+fi
+
+
+smart_try_dir="$collectdclient_lib_dir"
+
+
+sm_lib_safe=`echo "collectdclient" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "lcc_connect" | sed 'y%./+-%__p_%'`
+
+old_LIBS="$LIBS"
+old_CPPFLAGS="$CPPFLAGS"
+smart_lib=
+smart_ldflags=
+smart_lib_dir=
+
+if test "x$smart_try_dir" != "x"; then
+ for try in $smart_try_dir; do
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for lcc_connect in -lcollectdclient in $try" >&5
+printf %s "checking for lcc_connect in -lcollectdclient in $try... " >&6; }
+ LIBS="-lcollectdclient $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char lcc_connect();
+int
+main (void)
+{
+lcc_connect()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+
+ smart_lib="-lcollectdclient"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+ LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_lib" = "x"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for lcc_connect in -lcollectdclient" >&5
+printf %s "checking for lcc_connect in -lcollectdclient... " >&6; }
+ LIBS="-lcollectdclient $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char lcc_connect();
+int
+main (void)
+{
+lcc_connect()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+
+ smart_lib="-lcollectdclient"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ 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
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for lcc_connect in -lcollectdclient in $try" >&5
+printf %s "checking for lcc_connect in -lcollectdclient in $try... " >&6; }
+ LIBS="-lcollectdclient $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char lcc_connect();
+int
+main (void)
+{
+lcc_connect()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+
+ smart_lib="-lcollectdclient"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+ LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_lib" != "x"; then
+ eval "ac_cv_lib_${sm_lib_safe}_${sm_func_safe}=yes"
+ LIBS="$smart_ldflags $smart_lib $old_LIBS"
+ SMART_LIBS="$smart_ldflags $smart_lib $SMART_LIBS"
+fi
+
+if test "x$ac_cv_lib_collectdclient_lcc_connect" != "xyes"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: collectdclient library not found. Use --with-collectdclient-lib-dir=<path>." >&5
+printf "%s\n" "$as_me: WARNING: collectdclient library not found. Use --with-collectdclient-lib-dir=<path>." >&2;}
+else
+ COLLECTDC_LIBS="${smart_lib}"
+ COLLECTDC_LDFLAGS="${smart_ldflags}"
+fi
+LIBS="${old_LIBS}"
+
+cap_lib_dir=
+
+# Check whether --with-cap-lib-dir was given.
+if test ${with_cap_lib_dir+y}
+then :
+ withval=$with_cap_lib_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need cap-lib-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ cap_lib_dir="$withval"
+ ;;
+ esac
+fi
+
+
+cap_include_dir=
+
+# Check whether --with-cap-include-dir was given.
+if test ${with_cap_include_dir+y}
+then :
+ withval=$with_cap_include_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need cap-include-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ cap_include_dir="$withval"
+ ;;
+ esac
+fi
+
+
+smart_try_dir="$cap_lib_dir"
+
+
+sm_lib_safe=`echo "cap" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "cap_get_proc" | 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
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for cap_get_proc in -lcap in $try" >&5
+printf %s "checking for cap_get_proc in -lcap in $try... " >&6; }
+ LIBS="-lcap $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char cap_get_proc();
+int
+main (void)
+{
+cap_get_proc()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+
+ smart_lib="-lcap"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+ LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_lib" = "x"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for cap_get_proc in -lcap" >&5
+printf %s "checking for cap_get_proc in -lcap... " >&6; }
+ LIBS="-lcap $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char cap_get_proc();
+int
+main (void)
+{
+cap_get_proc()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+
+ smart_lib="-lcap"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ 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
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for cap_get_proc in -lcap in $try" >&5
+printf %s "checking for cap_get_proc in -lcap in $try... " >&6; }
+ LIBS="-lcap $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char cap_get_proc();
+int
+main (void)
+{
+cap_get_proc()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+
+ smart_lib="-lcap"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ 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_cap_cap_get_proc" != "xyes"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cap library not found, debugger checks will not be enabled. Use --with-cap-lib-dir=<path>." >&5
+printf "%s\n" "$as_me: WARNING: cap library not found, debugger checks will not be enabled. Use --with-cap-lib-dir=<path>." >&2;}
+else
+
+printf "%s\n" "#define HAVE_LIBCAP 1" >>confdefs.h
+
+ HAVE_LIBCAP=1
+fi
+
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a readline compatible library" >&5
+printf %s "checking for a readline compatible library... " >&6; }
+if test ${vl_cv_lib_readline+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+
+ ORIG_LIBS="$LIBS"
+ for readline_lib in readline edit editline; do
+ for termcap_lib in "" termcap curses ncurses; do
+ if test -z "$termcap_lib"; then
+ TRY_LIB="-l$readline_lib"
+ else
+ TRY_LIB="-l$readline_lib -l$termcap_lib"
+ fi
+ LIBS="$ORIG_LIBS $TRY_LIB"
+ 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. */
+char readline ();
+int
+main (void)
+{
+return readline ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+ vl_cv_lib_readline="$TRY_LIB"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+ if test -n "$vl_cv_lib_readline"; then
+ break
+ fi
+ done
+ if test -n "$vl_cv_lib_readline"; then
+ break
+ fi
+ done
+ if test -z "$vl_cv_lib_readline"; then
+ vl_cv_lib_readline="no"
+ LIBS="$ORIG_LIBS"
+ fi
+
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $vl_cv_lib_readline" >&5
+printf "%s\n" "$vl_cv_lib_readline" >&6; }
+
+ if test "$vl_cv_lib_readline" != "no"; then
+ LIBREADLINE="$vl_cv_lib_readline"
+
+printf "%s\n" "#define HAVE_LIBREADLINE 1" >>confdefs.h
+
+ ac_fn_c_check_header_compile "$LINENO" "readline.h" "ac_cv_header_readline_h" "$ac_includes_default"
+if test "x$ac_cv_header_readline_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_READLINE_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "readline/readline.h" "ac_cv_header_readline_readline_h" "$ac_includes_default"
+if test "x$ac_cv_header_readline_readline_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_READLINE_READLINE_H 1" >>confdefs.h
+
+fi
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether readline supports history" >&5
+printf %s "checking whether readline supports history... " >&6; }
+if test ${vl_cv_lib_readline_history+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+
+ vl_cv_lib_readline_history="no"
+ 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. */
+char add_history ();
+int
+main (void)
+{
+return add_history ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+ vl_cv_lib_readline_history="yes"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $vl_cv_lib_readline_history" >&5
+printf "%s\n" "$vl_cv_lib_readline_history" >&6; }
+ if test "$vl_cv_lib_readline_history" = "yes"; then
+
+printf "%s\n" "#define HAVE_READLINE_HISTORY 1" >>confdefs.h
+
+ ac_fn_c_check_header_compile "$LINENO" "history.h" "ac_cv_header_history_h" "$ac_includes_default"
+if test "x$ac_cv_header_history_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_HISTORY_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "readline/history.h" "ac_cv_header_readline_history_h" "$ac_includes_default"
+if test "x$ac_cv_header_readline_history_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_READLINE_HISTORY_H 1" >>confdefs.h
+
+fi
+
+ fi
+ fi
+
+
+
+
+# Check whether --with-systemd was given.
+if test ${with_systemd+y}
+then :
+ withval=$with_systemd; case "$withval" in
+ no)
+ WITH_SYSTEMD=no
+ ;;
+ *)
+ WITH_SYSTEMD=yes
+ esac
+else $as_nop
+ WITH_SYSTEMD=no
+fi
+
+
+systemd_lib_dir=
+
+# Check whether --with-systemd-lib-dir was given.
+if test ${with_systemd_lib_dir+y}
+then :
+ withval=$with_systemd_lib_dir; case "$withval" in
+ *) systemd_lib_dir="$withval"
+ ;;
+ esac
+
+fi
+
+
+systemd_include_dir=
+
+# Check whether --with-systemd-include-dir was given.
+if test ${with_systemd_include_dir+y}
+then :
+ withval=$with_systemd_include_dir; case "$withval" in
+ *) systemd_include_dir="$withval"
+ ;;
+ esac
+
+fi
+
+
+if test "x$WITH_SYSTEMD" = xyes; then
+ smart_try_dir="$systemd_lib_dir"
+
+
+sm_lib_safe=`echo "systemd" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "sd_notify" | 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
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sd_notify in -lsystemd in $try" >&5
+printf %s "checking for sd_notify in -lsystemd in $try... " >&6; }
+ LIBS="-lsystemd $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char sd_notify();
+int
+main (void)
+{
+sd_notify()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+
+ smart_lib="-lsystemd"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+ LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_lib" = "x"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sd_notify in -lsystemd" >&5
+printf %s "checking for sd_notify in -lsystemd... " >&6; }
+ LIBS="-lsystemd $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char sd_notify();
+int
+main (void)
+{
+sd_notify()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+
+ smart_lib="-lsystemd"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ 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
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sd_notify in -lsystemd in $try" >&5
+printf %s "checking for sd_notify in -lsystemd in $try... " >&6; }
+ LIBS="-lsystemd $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char sd_notify();
+int
+main (void)
+{
+sd_notify()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+
+ smart_lib="-lsystemd"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ 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_systemd_sd_notify" != "xyes"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: systemd library not found. Use --with-systemd-lib-dir=<path>." >&5
+printf "%s\n" "$as_me: WARNING: systemd library not found. Use --with-systemd-lib-dir=<path>." >&2;}
+ else
+
+printf "%s\n" "#define HAVE_SYSTEMD 1" >>confdefs.h
+
+ HAVE_SYSTEMD=1
+ SYSTEMD_LIBS="${smart_lib}"
+ SYSTEMD_LDFLAGS="${smart_ldflags}"
+ fi
+ LIBS="${old_LIBS}"
+fi
+
+if test "x$HAVE_SYSTEMD" = x; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: skipping test for systemd watchdog" >&5
+printf "%s\n" "$as_me: skipping test for systemd watchdog" >&6;}
+else
+ smart_try_dir="$systemd_lib_dir"
+
+
+sm_lib_safe=`echo "systemd" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "sd_watchdog_enabled" | 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
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sd_watchdog_enabled in -lsystemd in $try" >&5
+printf %s "checking for sd_watchdog_enabled in -lsystemd in $try... " >&6; }
+ LIBS="-lsystemd $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char sd_watchdog_enabled();
+int
+main (void)
+{
+sd_watchdog_enabled()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+
+ smart_lib="-lsystemd"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+ LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_lib" = "x"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sd_watchdog_enabled in -lsystemd" >&5
+printf %s "checking for sd_watchdog_enabled in -lsystemd... " >&6; }
+ LIBS="-lsystemd $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char sd_watchdog_enabled();
+int
+main (void)
+{
+sd_watchdog_enabled()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+
+ smart_lib="-lsystemd"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ 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
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sd_watchdog_enabled in -lsystemd in $try" >&5
+printf %s "checking for sd_watchdog_enabled in -lsystemd in $try... " >&6; }
+ LIBS="-lsystemd $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char sd_watchdog_enabled();
+int
+main (void)
+{
+sd_watchdog_enabled()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+
+ smart_lib="-lsystemd"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ 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_systemd_sd_watchdog_enabled" != "xyes"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: systemd watchdog is only available from systemd 209." >&5
+printf "%s\n" "$as_me: WARNING: systemd watchdog is only available from systemd 209." >&2;}
+ else
+
+printf "%s\n" "#define HAVE_SYSTEMD_WATCHDOG 1" >>confdefs.h
+
+ fi
+ LIBS="${old_LIBS}"
+fi
+
+if test "x$WITH_SYSTEMD" != xyes || test "x$SYSTEMD_LIBS" = x; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: skipping test for systemd/sd-daemon.h." >&5
+printf "%s\n" "$as_me: skipping test for systemd/sd-daemon.h." >&6;}
+else
+ smart_try_dir="$systemd_include_dir"
+
+
+ac_safe=`echo "systemd/sd-daemon.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
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for systemd/sd-daemon.h in $try" >&5
+printf %s "checking for systemd/sd-daemon.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <systemd/sd-daemon.h>
+int
+main (void)
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+
+ smart_include="-isystem $try"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+
+ smart_include=
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ done
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_include" = "x"; then
+ for _prefix in $smart_prefix; do
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ${_prefix}/systemd/sd-daemon.h" >&5
+printf %s "checking for ${_prefix}/systemd/sd-daemon.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <systemd/sd-daemon.h>
+int
+main (void)
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+
+ smart_include="-isystem ${_prefix}/"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+
+ smart_include=
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ done
+fi
+
+if test "x$smart_include" = "x"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for systemd/sd-daemon.h" >&5
+printf %s "checking for systemd/sd-daemon.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <systemd/sd-daemon.h>
+int
+main (void)
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+
+ smart_include=" "
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+
+ smart_include=
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+if test "x$smart_include" = "x"; then
+
+ for try in $_smart_include_dir; do
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for systemd/sd-daemon.h in $try" >&5
+printf %s "checking for systemd/sd-daemon.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <systemd/sd-daemon.h>
+int
+main (void)
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+
+ smart_include="-isystem $try"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+
+ smart_include=
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam 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_systemd_sdmdaemon_h" = "xyes"; then
+
+printf "%s\n" "#define HAVE_SYSTEMD_SD_DAEMON_H 1" >>confdefs.h
+
+
+
+ else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: systemd headers not found. Use --with-systemd-include-dir=<path>." >&5
+printf "%s\n" "$as_me: WARNING: systemd headers not found. Use --with-systemd-include-dir=<path>." >&2;}
+ fi
+fi
+
+
+smart_try_dir="$talloc_include_dir"
+
+
+ac_safe=`echo "talloc.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
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for talloc.h in $try" >&5
+printf %s "checking for talloc.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <talloc.h>
+int
+main (void)
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+
+ smart_include="-isystem $try"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+
+ smart_include=
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ done
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_include" = "x"; then
+ for _prefix in $smart_prefix; do
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ${_prefix}/talloc.h" >&5
+printf %s "checking for ${_prefix}/talloc.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <talloc.h>
+int
+main (void)
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+
+ smart_include="-isystem ${_prefix}/"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+
+ smart_include=
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ done
+fi
+
+if test "x$smart_include" = "x"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for talloc.h" >&5
+printf %s "checking for talloc.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <talloc.h>
+int
+main (void)
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+
+ smart_include=" "
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+
+ smart_include=
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+if test "x$smart_include" = "x"; then
+
+ for try in $_smart_include_dir; do
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for talloc.h in $try" >&5
+printf %s "checking for talloc.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <talloc.h>
+int
+main (void)
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+
+ smart_include="-isystem $try"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+
+ smart_include=
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam 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_talloc_h" != "xyes"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: talloc headers not found. Use --with-talloc-include-dir=<path>." >&5
+printf "%s\n" "$as_me: WARNING: talloc headers not found. Use --with-talloc-include-dir=<path>." >&2;}
+ as_fn_error $? "FreeRADIUS requires libtalloc" "$LINENO" 5
+fi
+
+case "$host" in
+ *-interix*)
+ CFLAGS="$CFLAGS -D_ALL_SOURCE"
+ ;;
+ *-darwin*)
+
+printf "%s\n" "#define __APPLE_USE_RFC_3542 1" >>confdefs.h
+
+ ;;
+esac
+
+ac_header_dirent=no
+for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do
+ as_ac_Header=`printf "%s\n" "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh`
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_hdr that defines DIR" >&5
+printf %s "checking for $ac_hdr that defines DIR... " >&6; }
+if eval test \${$as_ac_Header+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <$ac_hdr>
+
+int
+main (void)
+{
+if ((DIR *) 0)
+return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+ eval "$as_ac_Header=yes"
+else $as_nop
+ eval "$as_ac_Header=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+eval ac_res=\$$as_ac_Header
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+printf "%s\n" "$ac_res" >&6; }
+if eval test \"x\$"$as_ac_Header"\" = x"yes"
+then :
+ cat >>confdefs.h <<_ACEOF
+#define `printf "%s\n" "HAVE_$ac_hdr" | $as_tr_cpp` 1
+_ACEOF
+
+ac_header_dirent=$ac_hdr; break
+fi
+
+done
+# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix.
+if test $ac_header_dirent = dirent.h; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5
+printf %s "checking for library containing opendir... " >&6; }
+if test ${ac_cv_search_opendir+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_func_search_save_LIBS=$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. */
+char opendir ();
+int
+main (void)
+{
+return opendir ();
+ ;
+ return 0;
+}
+_ACEOF
+for ac_lib in '' dir
+do
+ if test -z "$ac_lib"; then
+ ac_res="none required"
+ else
+ ac_res=-l$ac_lib
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ fi
+ if ac_fn_c_try_link "$LINENO"
+then :
+ ac_cv_search_opendir=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext
+ if test ${ac_cv_search_opendir+y}
+then :
+ break
+fi
+done
+if test ${ac_cv_search_opendir+y}
+then :
+
+else $as_nop
+ ac_cv_search_opendir=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5
+printf "%s\n" "$ac_cv_search_opendir" >&6; }
+ac_res=$ac_cv_search_opendir
+if test "$ac_res" != no
+then :
+ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+fi
+
+else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5
+printf %s "checking for library containing opendir... " >&6; }
+if test ${ac_cv_search_opendir+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_func_search_save_LIBS=$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. */
+char opendir ();
+int
+main (void)
+{
+return opendir ();
+ ;
+ return 0;
+}
+_ACEOF
+for ac_lib in '' x
+do
+ if test -z "$ac_lib"; then
+ ac_res="none required"
+ else
+ ac_res=-l$ac_lib
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ fi
+ if ac_fn_c_try_link "$LINENO"
+then :
+ ac_cv_search_opendir=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext
+ if test ${ac_cv_search_opendir+y}
+then :
+ break
+fi
+done
+if test ${ac_cv_search_opendir+y}
+then :
+
+else $as_nop
+ ac_cv_search_opendir=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5
+printf "%s\n" "$ac_cv_search_opendir" >&6; }
+ac_res=$ac_cv_search_opendir
+if test "$ac_res" != no
+then :
+ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+fi
+
+fi
+
+# Autoupdate added the next two lines to ensure that your configure
+# script's behavior did not change. They are probably safe to remove.
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+printf %s "checking for egrep... " >&6; }
+if test ${ac_cv_path_EGREP+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ 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
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ 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
+ printf %s 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ printf "%s\n" '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
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+printf "%s\n" "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+
+
+
+# Obsolete code to be removed.
+if test $ac_cv_header_sys_time_h = yes; then
+
+printf "%s\n" "#define TIME_WITH_SYS_TIME 1" >>confdefs.h
+
+fi
+# End of obsolete code.
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sys/wait.h that is POSIX.1 compatible" >&5
+printf %s "checking for sys/wait.h that is POSIX.1 compatible... " >&6; }
+if test ${ac_cv_header_sys_wait_h+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <sys/wait.h>
+#ifndef WEXITSTATUS
+# define WEXITSTATUS(stat_val) ((unsigned int) (stat_val) >> 8)
+#endif
+#ifndef WIFEXITED
+# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#endif
+
+int
+main (void)
+{
+ int s;
+ wait (&s);
+ s = WIFEXITED (s) ? WEXITSTATUS (s) : 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+ ac_cv_header_sys_wait_h=yes
+else $as_nop
+ ac_cv_header_sys_wait_h=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_sys_wait_h" >&5
+printf "%s\n" "$ac_cv_header_sys_wait_h" >&6; }
+if test $ac_cv_header_sys_wait_h = yes; then
+
+printf "%s\n" "#define HAVE_SYS_WAIT_H 1" >>confdefs.h
+
+fi
+
+
+ac_fn_c_check_header_compile "$LINENO" "arpa/inet.h" "ac_cv_header_arpa_inet_h" "$ac_includes_default"
+if test "x$ac_cv_header_arpa_inet_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_ARPA_INET_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "crypt.h" "ac_cv_header_crypt_h" "$ac_includes_default"
+if test "x$ac_cv_header_crypt_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_CRYPT_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default"
+if test "x$ac_cv_header_dlfcn_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_DLFCN_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "errno.h" "ac_cv_header_errno_h" "$ac_includes_default"
+if test "x$ac_cv_header_errno_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_ERRNO_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "fcntl.h" "ac_cv_header_fcntl_h" "$ac_includes_default"
+if test "x$ac_cv_header_fcntl_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_FCNTL_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "features.h" "ac_cv_header_features_h" "$ac_includes_default"
+if test "x$ac_cv_header_features_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_FEATURES_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "fnmatch.h" "ac_cv_header_fnmatch_h" "$ac_includes_default"
+if test "x$ac_cv_header_fnmatch_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_FNMATCH_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "getopt.h" "ac_cv_header_getopt_h" "$ac_includes_default"
+if test "x$ac_cv_header_getopt_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_GETOPT_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "glob.h" "ac_cv_header_glob_h" "$ac_includes_default"
+if test "x$ac_cv_header_glob_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_GLOB_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "grp.h" "ac_cv_header_grp_h" "$ac_includes_default"
+if test "x$ac_cv_header_grp_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_GRP_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "inttypes.h" "ac_cv_header_inttypes_h" "$ac_includes_default"
+if test "x$ac_cv_header_inttypes_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_INTTYPES_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "limits.h" "ac_cv_header_limits_h" "$ac_includes_default"
+if test "x$ac_cv_header_limits_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_LIMITS_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "linux/if_packet.h" "ac_cv_header_linux_if_packet_h" "$ac_includes_default"
+if test "x$ac_cv_header_linux_if_packet_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_LINUX_IF_PACKET_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "malloc.h" "ac_cv_header_malloc_h" "$ac_includes_default"
+if test "x$ac_cv_header_malloc_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_MALLOC_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "netdb.h" "ac_cv_header_netdb_h" "$ac_includes_default"
+if test "x$ac_cv_header_netdb_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_NETDB_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "netinet/in.h" "ac_cv_header_netinet_in_h" "$ac_includes_default"
+if test "x$ac_cv_header_netinet_in_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_NETINET_IN_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "prot.h" "ac_cv_header_prot_h" "$ac_includes_default"
+if test "x$ac_cv_header_prot_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_PROT_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "pwd.h" "ac_cv_header_pwd_h" "$ac_includes_default"
+if test "x$ac_cv_header_pwd_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_PWD_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "resource.h" "ac_cv_header_resource_h" "$ac_includes_default"
+if test "x$ac_cv_header_resource_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_RESOURCE_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "semaphore.h" "ac_cv_header_semaphore_h" "$ac_includes_default"
+if test "x$ac_cv_header_semaphore_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SEMAPHORE_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "sia.h" "ac_cv_header_sia_h" "$ac_includes_default"
+if test "x$ac_cv_header_sia_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SIA_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "siad.h" "ac_cv_header_siad_h" "$ac_includes_default"
+if test "x$ac_cv_header_siad_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SIAD_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "signal.h" "ac_cv_header_signal_h" "$ac_includes_default"
+if test "x$ac_cv_header_signal_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SIGNAL_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "stdatomic.h" "ac_cv_header_stdatomic_h" "$ac_includes_default"
+if test "x$ac_cv_header_stdatomic_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_STDATOMIC_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "stdalign.h" "ac_cv_header_stdalign_h" "$ac_includes_default"
+if test "x$ac_cv_header_stdalign_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_STDALIGN_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "stdbool.h" "ac_cv_header_stdbool_h" "$ac_includes_default"
+if test "x$ac_cv_header_stdbool_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_STDBOOL_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "stddef.h" "ac_cv_header_stddef_h" "$ac_includes_default"
+if test "x$ac_cv_header_stddef_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_STDDEF_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "stdint.h" "ac_cv_header_stdint_h" "$ac_includes_default"
+if test "x$ac_cv_header_stdint_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_STDINT_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "stdio.h" "ac_cv_header_stdio_h" "$ac_includes_default"
+if test "x$ac_cv_header_stdio_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_STDIO_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "sys/event.h" "ac_cv_header_sys_event_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_event_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SYS_EVENT_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "sys/fcntl.h" "ac_cv_header_sys_fcntl_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_fcntl_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SYS_FCNTL_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "sys/prctl.h" "ac_cv_header_sys_prctl_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_prctl_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SYS_PRCTL_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "sys/procctl.h" "ac_cv_header_sys_procctl_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_procctl_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SYS_PROCCTL_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "sys/ptrace.h" "ac_cv_header_sys_ptrace_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_ptrace_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SYS_PTRACE_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "sys/resource.h" "ac_cv_header_sys_resource_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_resource_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SYS_RESOURCE_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "sys/security.h" "ac_cv_header_sys_security_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_security_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SYS_SECURITY_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "sys/select.h" "ac_cv_header_sys_select_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_select_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SYS_SELECT_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "sys/socket.h" "ac_cv_header_sys_socket_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_socket_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SYS_SOCKET_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "sys/time.h" "ac_cv_header_sys_time_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_time_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SYS_TIME_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "sys/types.h" "ac_cv_header_sys_types_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_types_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SYS_TYPES_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "sys/un.h" "ac_cv_header_sys_un_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_un_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SYS_UN_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "sys/wait.h" "ac_cv_header_sys_wait_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_wait_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SYS_WAIT_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "syslog.h" "ac_cv_header_syslog_h" "$ac_includes_default"
+if test "x$ac_cv_header_syslog_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SYSLOG_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "unistd.h" "ac_cv_header_unistd_h" "$ac_includes_default"
+if test "x$ac_cv_header_unistd_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_UNISTD_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "utime.h" "ac_cv_header_utime_h" "$ac_includes_default"
+if test "x$ac_cv_header_utime_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_UTIME_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "utmp.h" "ac_cv_header_utmp_h" "$ac_includes_default"
+if test "x$ac_cv_header_utmp_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_UTMP_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "utmpx.h" "ac_cv_header_utmpx_h" "$ac_includes_default"
+if test "x$ac_cv_header_utmpx_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_UTMPX_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "winsock.h" "ac_cv_header_winsock_h" "$ac_includes_default"
+if test "x$ac_cv_header_winsock_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_WINSOCK_H 1" >>confdefs.h
+
+fi
+
+
+ac_fn_c_check_header_compile "$LINENO" "net/if.h" "ac_cv_header_net_if_h" "
+ #ifdef HAVE_SYS_SOCKET_H
+ # include <sys/socket.h>
+ #endif
+
+
+"
+if test "x$ac_cv_header_net_if_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_NET_IF_H 1" >>confdefs.h
+
+fi
+
+
+if test "x$ac_cv_header_sys_security_h" = "xyes" && test "x$ac_cv_header_prot_h" = "xyes"
+then
+
+printf "%s\n" "#define OSFC2 /**/" >>confdefs.h
+
+fi
+
+if test "x$ac_cv_header_sia_h" = "xyes" && test "x$ac_cv_header_siad_h" = "xyes"
+then
+
+printf "%s\n" "#define OSFSIA /**/" >>confdefs.h
+
+fi
+
+if test "x$WITH_OPENSSL" = xyes; then
+ OLD_LIBS="$LIBS"
+
+ CFLAGS="$CFLAGS -DOPENSSL_NO_KRB5"
+
+ smart_try_dir="$openssl_lib_dir"
+
+
+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
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for DH_new in -lcrypto in $try" >&5
+printf %s "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 (void)
+{
+DH_new()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+
+ smart_lib="-lcrypto"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+ LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_lib" = "x"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for DH_new in -lcrypto" >&5
+printf %s "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 (void)
+{
+DH_new()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+
+ smart_lib="-lcrypto"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ 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
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for DH_new in -lcrypto in $try" >&5
+printf %s "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 (void)
+{
+DH_new()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+
+ smart_lib="-lcrypto"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ 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
+
+printf "%s\n" "#define HAVE_LIBCRYPTO 1" >>confdefs.h
+
+ OPENSSL_LIBS="$smart_lib"
+ OPENSSL_LDFLAGS="$smart_ldflags"
+
+
+
+sm_lib_safe=`echo "ssl" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "SSL_new" | sed 'y%./+-%__p_%'`
+
+old_LIBS="$LIBS"
+old_CPPFLAGS="$CPPFLAGS"
+smart_lib=
+smart_ldflags=
+smart_lib_dir=
+
+if test "x$smart_try_dir" != "x"; then
+ for try in $smart_try_dir; do
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for SSL_new in -lssl in $try" >&5
+printf %s "checking for SSL_new in -lssl in $try... " >&6; }
+ LIBS="-lssl $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char SSL_new();
+int
+main (void)
+{
+SSL_new()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+
+ smart_lib="-lssl"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+ LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_lib" = "x"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for SSL_new in -lssl" >&5
+printf %s "checking for SSL_new in -lssl... " >&6; }
+ LIBS="-lssl $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char SSL_new();
+int
+main (void)
+{
+SSL_new()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+
+ smart_lib="-lssl"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ 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
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for SSL_new in -lssl in $try" >&5
+printf %s "checking for SSL_new in -lssl in $try... " >&6; }
+ LIBS="-lssl $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char SSL_new();
+int
+main (void)
+{
+SSL_new()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+
+ smart_lib="-lssl"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+ LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_lib" != "x"; then
+ eval "ac_cv_lib_${sm_lib_safe}_${sm_func_safe}=yes"
+ LIBS="$smart_ldflags $smart_lib $old_LIBS"
+ SMART_LIBS="$smart_ldflags $smart_lib $SMART_LIBS"
+fi
+
+ if test "x$ac_cv_lib_ssl_SSL_new" != "xyes"; then
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed linking to libssl. Use --with-openssl-lib-dir=<path>, or --with-openssl=no (builds without OpenSSL)
+See \`config.log' for more details" "$LINENO" 5; }
+ else
+
+printf "%s\n" "#define HAVE_LIBSSL 1" >>confdefs.h
+
+ OPENSSL_LIBS="$OPENSSL_LIBS $smart_lib"
+
+ if test "$OPENSSL_LDFLAGS" != "$smart_ldflags"; then
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "\"inconsistent LDFLAGS between -lssl '$smart_ldflags' and -lcrypto '$OPENSSL_LDFLAGS'\"
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+ fi
+ else
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed linking to libcrypto. Use --with-openssl-lib-dir=<path>, or --with-openssl=no (builds without OpenSSL)
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+
+ smart_try_dir="$openssl_include_dir"
+
+
+ac_safe=`echo "openssl/ssl.h" | sed 'y%./+-%__pm%'`
+old_CPPFLAGS="$CPPFLAGS"
+smart_include=
+smart_include_dir="/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
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for openssl/ssl.h in $try" >&5
+printf %s "checking for openssl/ssl.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <openssl/ssl.h>
+int
+main (void)
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+
+ smart_include="-isystem $try"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+
+ smart_include=
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ done
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_include" = "x"; then
+ for _prefix in $smart_prefix; do
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ${_prefix}/openssl/ssl.h" >&5
+printf %s "checking for ${_prefix}/openssl/ssl.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <openssl/ssl.h>
+int
+main (void)
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+
+ smart_include="-isystem ${_prefix}/"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+
+ smart_include=
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ done
+fi
+
+if test "x$smart_include" = "x"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for openssl/ssl.h" >&5
+printf %s "checking for openssl/ssl.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <openssl/ssl.h>
+int
+main (void)
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+
+ smart_include=" "
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+
+ smart_include=
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+if test "x$smart_include" = "x"; then
+
+ for try in $_smart_include_dir; do
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for openssl/ssl.h in $try" >&5
+printf %s "checking for openssl/ssl.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <openssl/ssl.h>
+int
+main (void)
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+
+ smart_include="-isystem $try"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+
+ smart_include=
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam 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_openssl_ssl_h" = "xyes"; then
+
+printf "%s\n" "#define HAVE_OPENSSL_SSL_H 1" >>confdefs.h
+
+
+ for ac_header in openssl/asn1.h openssl/conf.h openssl/crypto.h openssl/err.h openssl/evp.h openssl/hmac.h openssl/md5.h openssl/md4.h openssl/rand.h openssl/sha.h openssl/ssl.h openssl/ocsp.h openssl/engine.h
+do :
+ as_ac_Header=`printf "%s\n" "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 `printf "%s\n" "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+ OPENSSL_CPPFLAGS="$smart_include"
+else $as_nop
+
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed locating OpenSSL headers. Use --with-openssl-include-dir=<path>, or --with-openssl=no (builds without OpenSSL)
+See \`config.log' for more details" "$LINENO" 5; }
+
+
+fi
+
+done
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for OpenSSL version >= 1.0.2" >&5
+printf %s "checking for OpenSSL version >= 1.0.2... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <openssl/crypto.h>
+ #if (OPENSSL_VERSION_NUMBER >= 0x10002000L)
+ yes
+ #endif
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "yes" >/dev/null 2>&1
+then :
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+
+else $as_nop
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "OpenSSL version too old
+See \`config.log' for more details" "$LINENO" 5; }
+
+
+fi
+rm -rf conftest*
+
+
+ old_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="$OPENSSL_CPPFLAGS $CPPFLAGS"
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking OpenSSL library and header version consistency" >&5
+printf %s "checking OpenSSL library and header version consistency... " >&6; }
+ if test "$cross_compiling" = yes
+then :
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: cross-compiling (assuming yes)" >&5
+printf "%s\n" "cross-compiling (assuming yes)" >&6; }
+
+
+else $as_nop
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <stdio.h>
+ #include <openssl/opensslv.h>
+ #include <openssl/crypto.h>
+
+int
+main (void)
+{
+
+ printf("library: %lx header: %lx... ", (unsigned long) SSLeay(), (unsigned long) OPENSSL_VERSION_NUMBER);
+ if (SSLeay() == OPENSSL_VERSION_NUMBER) {
+ return 0;
+ } else {
+ return 1;
+ }
+
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"
+then :
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+
+else $as_nop
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "OpenSSL library version does not match header version
+See \`config.log' for more details" "$LINENO" 5; }
+
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+ ac_fn_c_check_func "$LINENO" "SSL_get_client_random" "ac_cv_func_SSL_get_client_random"
+if test "x$ac_cv_func_SSL_get_client_random" = xyes
+then :
+ printf "%s\n" "#define HAVE_SSL_GET_CLIENT_RANDOM 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "SSL_get_server_random" "ac_cv_func_SSL_get_server_random"
+if test "x$ac_cv_func_SSL_get_server_random" = xyes
+then :
+ printf "%s\n" "#define HAVE_SSL_GET_SERVER_RANDOM 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "SSL_SESSION_get_master_key" "ac_cv_func_SSL_SESSION_get_master_key"
+if test "x$ac_cv_func_SSL_SESSION_get_master_key" = xyes
+then :
+ printf "%s\n" "#define HAVE_SSL_SESSION_GET_MASTER_KEY 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "HMAC_CTX_new" "ac_cv_func_HMAC_CTX_new"
+if test "x$ac_cv_func_HMAC_CTX_new" = xyes
+then :
+ printf "%s\n" "#define HAVE_HMAC_CTX_NEW 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "HMAC_CTX_free" "ac_cv_func_HMAC_CTX_free"
+if test "x$ac_cv_func_HMAC_CTX_free" = xyes
+then :
+ printf "%s\n" "#define HAVE_HMAC_CTX_FREE 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "ASN1_STRING_get0_data" "ac_cv_func_ASN1_STRING_get0_data"
+if test "x$ac_cv_func_ASN1_STRING_get0_data" = xyes
+then :
+ printf "%s\n" "#define HAVE_ASN1_STRING_GET0_DATA 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "CONF_modules_load_file" "ac_cv_func_CONF_modules_load_file"
+if test "x$ac_cv_func_CONF_modules_load_file" = xyes
+then :
+ printf "%s\n" "#define HAVE_CONF_MODULES_LOAD_FILE 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "CRYPTO_set_id_callback" "ac_cv_func_CRYPTO_set_id_callback"
+if test "x$ac_cv_func_CRYPTO_set_id_callback" = xyes
+then :
+ printf "%s\n" "#define HAVE_CRYPTO_SET_ID_CALLBACK 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "CRYPTO_set_locking_callback" "ac_cv_func_CRYPTO_set_locking_callback"
+if test "x$ac_cv_func_CRYPTO_set_locking_callback" = xyes
+then :
+ printf "%s\n" "#define HAVE_CRYPTO_SET_LOCKING_CALLBACK 1" >>confdefs.h
+
+fi
+
+ CPPFLAGS="$old_CPPFLAGS"
+ fi
+
+ LIBS="$OLD_LIBS"
+
+
+
+ export OPENSSL_LIBS OPENSSL_LDFLAGS OPENSSL_CPPFLAGS
+fi
+
+if test "x$PCAP_LIBS" = x; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: skipping test for pcap.h." >&5
+printf "%s\n" "$as_me: skipping test for pcap.h." >&6;}
+else
+ smart_try_dir="$pcap_include_dir"
+
+
+ac_safe=`echo "pcap.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
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pcap.h in $try" >&5
+printf %s "checking for pcap.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <pcap.h>
+int
+main (void)
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+
+ smart_include="-isystem $try"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+
+ smart_include=
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ done
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_include" = "x"; then
+ for _prefix in $smart_prefix; do
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ${_prefix}/pcap.h" >&5
+printf %s "checking for ${_prefix}/pcap.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <pcap.h>
+int
+main (void)
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+
+ smart_include="-isystem ${_prefix}/"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+
+ smart_include=
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ done
+fi
+
+if test "x$smart_include" = "x"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pcap.h" >&5
+printf %s "checking for pcap.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <pcap.h>
+int
+main (void)
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+
+ smart_include=" "
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+
+ smart_include=
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+if test "x$smart_include" = "x"; then
+
+ for try in $_smart_include_dir; do
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pcap.h in $try" >&5
+printf %s "checking for pcap.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <pcap.h>
+int
+main (void)
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+
+ smart_include="-isystem $try"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+
+ smart_include=
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam 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_pcap_h" = "xyes" && test "x$ac_cv_lib_pcap_pcap_open_live" = "xyes"; then
+
+printf "%s\n" "#define HAVE_LIBPCAP 1" >>confdefs.h
+
+
+
+ else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: pcap headers not found, silently disabling the RADIUS sniffer, and ARP listener. Use --with-pcap-include-dir=<path>." >&5
+printf "%s\n" "$as_me: WARNING: pcap headers not found, silently disabling the RADIUS sniffer, and ARP listener. Use --with-pcap-include-dir=<path>." >&2;}
+ fi
+fi
+
+if test "x$COLLECTDC_LIBS" = x; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: skipping test for collectd/client.h." >&5
+printf "%s\n" "$as_me: skipping test for collectd/client.h." >&6;}
+else
+ smart_try_dir="$collectdclient_include_dir"
+
+
+ac_safe=`echo "collectd/client.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
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for collectd/client.h in $try" >&5
+printf %s "checking for collectd/client.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <collectd/client.h>
+int
+main (void)
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+
+ smart_include="-isystem $try"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+
+ smart_include=
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ done
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_include" = "x"; then
+ for _prefix in $smart_prefix; do
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ${_prefix}/collectd/client.h" >&5
+printf %s "checking for ${_prefix}/collectd/client.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <collectd/client.h>
+int
+main (void)
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+
+ smart_include="-isystem ${_prefix}/"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+
+ smart_include=
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ done
+fi
+
+if test "x$smart_include" = "x"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for collectd/client.h" >&5
+printf %s "checking for collectd/client.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <collectd/client.h>
+int
+main (void)
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+
+ smart_include=" "
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+
+ smart_include=
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+if test "x$smart_include" = "x"; then
+
+ for try in $_smart_include_dir; do
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for collectd/client.h in $try" >&5
+printf %s "checking for collectd/client.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <collectd/client.h>
+int
+main (void)
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+
+ smart_include="-isystem $try"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+
+ smart_include=
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam 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_collectd_client_h" = "xyes"; then
+
+printf "%s\n" "#define HAVE_COLLECTDC_H 1" >>confdefs.h
+
+
+
+ else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: collectdclient headers not found. Use --with-collectdclient-include-dir=<path>." >&5
+printf "%s\n" "$as_me: WARNING: collectdclient headers not found. Use --with-collectdclient-include-dir=<path>." >&2;}
+ fi
+fi
+
+if test "x$HAVE_LIBCAP" = x; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: skipping test for cap.h." >&5
+printf "%s\n" "$as_me: skipping test for cap.h." >&6;}
+else
+ smart_try_dir="$cap_include_dir"
+
+
+ac_safe=`echo "sys/capability.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
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sys/capability.h in $try" >&5
+printf %s "checking for sys/capability.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <sys/capability.h>
+int
+main (void)
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+
+ smart_include="-isystem $try"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+
+ smart_include=
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ done
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_include" = "x"; then
+ for _prefix in $smart_prefix; do
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ${_prefix}/sys/capability.h" >&5
+printf %s "checking for ${_prefix}/sys/capability.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <sys/capability.h>
+int
+main (void)
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+
+ smart_include="-isystem ${_prefix}/"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+
+ smart_include=
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ done
+fi
+
+if test "x$smart_include" = "x"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sys/capability.h" >&5
+printf %s "checking for sys/capability.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <sys/capability.h>
+int
+main (void)
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+
+ smart_include=" "
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+
+ smart_include=
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+if test "x$smart_include" = "x"; then
+
+ for try in $_smart_include_dir; do
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sys/capability.h in $try" >&5
+printf %s "checking for sys/capability.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <sys/capability.h>
+int
+main (void)
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+
+ smart_include="-isystem $try"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+
+ smart_include=
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam 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_sys_capability_h" = "xyes"; then
+
+printf "%s\n" "#define HAVE_CAPABILITY_H 1" >>confdefs.h
+
+ else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cap headers not found, will not perform debugger checks. Use --with-cap-include-dir=<path>." >&5
+printf "%s\n" "$as_me: WARNING: cap headers not found, will not perform debugger checks. Use --with-cap-include-dir=<path>." >&2;}
+ fi
+fi
+
+
+ac_fn_c_check_type "$LINENO" "off_t" "ac_cv_type_off_t" "$ac_includes_default"
+if test "x$ac_cv_type_off_t" = xyes
+then :
+
+else $as_nop
+
+printf "%s\n" "#define off_t long int" >>confdefs.h
+
+fi
+
+
+ ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default
+"
+if test "x$ac_cv_type_pid_t" = xyes
+then :
+
+else $as_nop
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #if defined _WIN64 && !defined __CYGWIN__
+ LLP64
+ #endif
+
+int
+main (void)
+{
+
+ ;
+ return 0;
+}
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+ ac_pid_type='int'
+else $as_nop
+ ac_pid_type='__int64'
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+
+printf "%s\n" "#define pid_t $ac_pid_type" >>confdefs.h
+
+
+fi
+
+
+ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default"
+if test "x$ac_cv_type_size_t" = xyes
+then :
+
+else $as_nop
+
+printf "%s\n" "#define size_t unsigned int" >>confdefs.h
+
+fi
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for uid_t in sys/types.h" >&5
+printf %s "checking for uid_t in sys/types.h... " >&6; }
+if test ${ac_cv_type_uid_t+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "uid_t" >/dev/null 2>&1
+then :
+ ac_cv_type_uid_t=yes
+else $as_nop
+ ac_cv_type_uid_t=no
+fi
+rm -rf conftest*
+
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uid_t" >&5
+printf "%s\n" "$ac_cv_type_uid_t" >&6; }
+if test $ac_cv_type_uid_t = no; then
+
+printf "%s\n" "#define uid_t int" >>confdefs.h
+
+
+printf "%s\n" "#define gid_t int" >>confdefs.h
+
+fi
+
+
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for socklen_t" >&5
+printf %s "checking for socklen_t... " >&6; }
+if test ${ac_cv_type_socklen_t+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_cv_type_socklen_t=no
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef HAVE_SYS_TYPES_H
+ # include <sys/types.h>
+ #endif
+
+ #ifdef HAVE_SYS_SOCKET_H
+ # include <sys/socket.h>
+ #endif
+
+int
+main (void)
+{
+socklen_t foo
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+ ac_cv_type_socklen_t=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+
+
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_socklen_t" >&5
+printf "%s\n" "$ac_cv_type_socklen_t" >&6; }
+
+ if test "$ac_cv_type_socklen_t" != "yes"; then
+
+printf "%s\n" "#define socklen_t int" >>confdefs.h
+
+ fi
+
+
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for uint8_t" >&5
+printf %s "checking for uint8_t... " >&6; }
+if test ${ac_cv_type_uint8_t+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_cv_type_uint8_t=no
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef HAVE_INTTYPES_H
+ # include <inttypes.h>
+ #endif
+
+ #ifdef HAVE_STDINT_H
+ # include <stdint.h>
+ #endif
+
+int
+main (void)
+{
+uint8_t foo
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+ ac_cv_type_uint8_t=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+
+
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uint8_t" >&5
+printf "%s\n" "$ac_cv_type_uint8_t" >&6; }
+
+ if test "$ac_cv_type_uint8_t" != "yes"; then
+
+printf "%s\n" "#define uint8_t unsigned char" >>confdefs.h
+
+ fi
+
+
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for uint16_t" >&5
+printf %s "checking for uint16_t... " >&6; }
+if test ${ac_cv_type_uint16_t+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_cv_type_uint16_t=no
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef HAVE_INTTYPES_H
+ # include <inttypes.h>
+ #endif
+
+ #ifdef HAVE_STDINT_H
+ # include <stdint.h>
+ #endif
+
+int
+main (void)
+{
+uint16_t foo
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+ ac_cv_type_uint16_t=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+
+
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uint16_t" >&5
+printf "%s\n" "$ac_cv_type_uint16_t" >&6; }
+
+ if test "$ac_cv_type_uint16_t" != "yes"; then
+
+printf "%s\n" "#define uint16_t unsigned short" >>confdefs.h
+
+ fi
+
+
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for uint32_t" >&5
+printf %s "checking for uint32_t... " >&6; }
+if test ${ac_cv_type_uint32_t+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_cv_type_uint32_t=no
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef HAVE_INTTYPES_H
+ # include <inttypes.h>
+ #endif
+
+ #ifdef HAVE_STDINT_H
+ # include <stdint.h>
+ #endif
+
+int
+main (void)
+{
+uint32_t foo
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+ ac_cv_type_uint32_t=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+
+
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uint32_t" >&5
+printf "%s\n" "$ac_cv_type_uint32_t" >&6; }
+
+ if test "$ac_cv_type_uint32_t" != "yes"; then
+
+printf "%s\n" "#define uint32_t unsigned int" >>confdefs.h
+
+ fi
+
+
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for uint64_t" >&5
+printf %s "checking for uint64_t... " >&6; }
+if test ${ac_cv_type_uint64_t+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_cv_type_uint64_t=no
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef HAVE_INTTYPES_H
+ # include <inttypes.h>
+ #endif
+
+ #ifdef HAVE_STDINT_H
+ # include <stdint.h>
+ #endif
+
+int
+main (void)
+{
+uint64_t foo
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+ ac_cv_type_uint64_t=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+
+
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uint64_t" >&5
+printf "%s\n" "$ac_cv_type_uint64_t" >&6; }
+
+ if test "$ac_cv_type_uint64_t" != "yes"; then
+
+printf "%s\n" "#define uint64_t unsigned long long" >>confdefs.h
+
+ fi
+
+
+ac_fn_c_check_type "$LINENO" "__uint128_t" "ac_cv_type___uint128_t" "$ac_includes_default"
+if test "x$ac_cv_type___uint128_t" = xyes
+then :
+
+printf "%s\n" "#define HAVE___UINT128_T 1" >>confdefs.h
+
+fi
+
+
+ac_fn_c_check_type "$LINENO" "uint128_t" "ac_cv_type_uint128_t" "
+ #ifdef HAVE_INTTYPES_H
+ # include <inttypes.h>
+ #endif
+
+ #ifdef HAVE_STDINT_H
+ # include <stdint.h>
+ #endif
+
+
+"
+if test "x$ac_cv_type_uint128_t" = xyes
+then :
+
+printf "%s\n" "#define HAVE_UINT128_T 1" >>confdefs.h
+
+fi
+
+
+ac_fn_c_check_type "$LINENO" "struct in6_addr" "ac_cv_type_struct_in6_addr" "
+ #ifdef HAVE_NETINET_IN_H
+ # include <netinet/in.h>
+ #endif
+
+
+"
+if test "x$ac_cv_type_struct_in6_addr" = xyes
+then :
+
+printf "%s\n" "#define HAVE_STRUCT_IN6_ADDR 1" >>confdefs.h
+
+fi
+
+
+ac_fn_c_check_type "$LINENO" "struct sockaddr_storage" "ac_cv_type_struct_sockaddr_storage" "
+ #ifdef HAVE_NETINET_IN_H
+ # include <netinet/in.h>
+ #endif
+
+ #ifdef HAVE_SYS_SOCKET_H
+ # include <sys/socket.h>
+ #endif
+
+"
+if test "x$ac_cv_type_struct_sockaddr_storage" = xyes
+then :
+
+printf "%s\n" "#define HAVE_STRUCT_SOCKADDR_STORAGE 1" >>confdefs.h
+
+fi
+
+
+ac_fn_c_check_type "$LINENO" "struct sockaddr_in6" "ac_cv_type_struct_sockaddr_in6" "
+ #ifdef HAVE_NETINET_IN_H
+ # include <netinet/in.h>
+ #endif
+
+"
+if test "x$ac_cv_type_struct_sockaddr_in6" = xyes
+then :
+
+printf "%s\n" "#define HAVE_STRUCT_SOCKADDR_IN6 1" >>confdefs.h
+
+fi
+
+
+ac_fn_c_check_type "$LINENO" "struct addrinfo" "ac_cv_type_struct_addrinfo" "
+ #ifdef HAVE_SYS_TYPES_H
+ # include <sys/types.h>
+ #endif
+
+ #ifdef HAVE_SYS_SOCKET_H
+ # include <sys/socket.h>
+ #endif
+
+ #ifdef HAVE_NETDB_H
+ # include <netdb.h>
+ #endif
+
+
+"
+if test "x$ac_cv_type_struct_addrinfo" = xyes
+then :
+
+printf "%s\n" "#define HAVE_STRUCT_ADDRINFO 1" >>confdefs.h
+
+fi
+
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if sig_t is defined" >&5
+printf %s "checking if sig_t is defined... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #ifdef HAVE_SIGNAL_H
+ # include <signal.h>
+ #endif
+
+int
+main (void)
+{
+
+ sig_t func;
+ return 0;
+
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+
+printf "%s\n" "#define HAVE_SIG_T 1" >>confdefs.h
+
+
+else $as_nop
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+
+ac_fn_c_check_func "$LINENO" "bindat" "ac_cv_func_bindat"
+if test "x$ac_cv_func_bindat" = xyes
+then :
+ printf "%s\n" "#define HAVE_BINDAT 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "clock_gettime" "ac_cv_func_clock_gettime"
+if test "x$ac_cv_func_clock_gettime" = xyes
+then :
+ printf "%s\n" "#define HAVE_CLOCK_GETTIME 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "closefrom" "ac_cv_func_closefrom"
+if test "x$ac_cv_func_closefrom" = xyes
+then :
+ printf "%s\n" "#define HAVE_CLOSEFROM 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "ctime_r" "ac_cv_func_ctime_r"
+if test "x$ac_cv_func_ctime_r" = xyes
+then :
+ printf "%s\n" "#define HAVE_CTIME_R 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "dladdr" "ac_cv_func_dladdr"
+if test "x$ac_cv_func_dladdr" = xyes
+then :
+ printf "%s\n" "#define HAVE_DLADDR 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "fcntl" "ac_cv_func_fcntl"
+if test "x$ac_cv_func_fcntl" = xyes
+then :
+ printf "%s\n" "#define HAVE_FCNTL 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "fopencookie" "ac_cv_func_fopencookie"
+if test "x$ac_cv_func_fopencookie" = xyes
+then :
+ printf "%s\n" "#define HAVE_FOPENCOOKIE 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "funopen" "ac_cv_func_funopen"
+if test "x$ac_cv_func_funopen" = xyes
+then :
+ printf "%s\n" "#define HAVE_FUNOPEN 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "getaddrinfo" "ac_cv_func_getaddrinfo"
+if test "x$ac_cv_func_getaddrinfo" = xyes
+then :
+ printf "%s\n" "#define HAVE_GETADDRINFO 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "getnameinfo" "ac_cv_func_getnameinfo"
+if test "x$ac_cv_func_getnameinfo" = xyes
+then :
+ printf "%s\n" "#define HAVE_GETNAMEINFO 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "getopt_long" "ac_cv_func_getopt_long"
+if test "x$ac_cv_func_getopt_long" = xyes
+then :
+ printf "%s\n" "#define HAVE_GETOPT_LONG 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "getpeereid" "ac_cv_func_getpeereid"
+if test "x$ac_cv_func_getpeereid" = xyes
+then :
+ printf "%s\n" "#define HAVE_GETPEEREID 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "getresuid" "ac_cv_func_getresuid"
+if test "x$ac_cv_func_getresuid" = xyes
+then :
+ printf "%s\n" "#define HAVE_GETRESUID 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "gettimeofday" "ac_cv_func_gettimeofday"
+if test "x$ac_cv_func_gettimeofday" = xyes
+then :
+ printf "%s\n" "#define HAVE_GETTIMEOFDAY 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "getusershell" "ac_cv_func_getusershell"
+if test "x$ac_cv_func_getusershell" = xyes
+then :
+ printf "%s\n" "#define HAVE_GETUSERSHELL 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "gmtime_r" "ac_cv_func_gmtime_r"
+if test "x$ac_cv_func_gmtime_r" = xyes
+then :
+ printf "%s\n" "#define HAVE_GMTIME_R 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "if_indextoname" "ac_cv_func_if_indextoname"
+if test "x$ac_cv_func_if_indextoname" = xyes
+then :
+ printf "%s\n" "#define HAVE_IF_INDEXTONAME 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "inet_aton" "ac_cv_func_inet_aton"
+if test "x$ac_cv_func_inet_aton" = xyes
+then :
+ printf "%s\n" "#define HAVE_INET_ATON 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "inet_ntop" "ac_cv_func_inet_ntop"
+if test "x$ac_cv_func_inet_ntop" = xyes
+then :
+ printf "%s\n" "#define HAVE_INET_NTOP 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "inet_pton" "ac_cv_func_inet_pton"
+if test "x$ac_cv_func_inet_pton" = xyes
+then :
+ printf "%s\n" "#define HAVE_INET_PTON 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "initgroups" "ac_cv_func_initgroups"
+if test "x$ac_cv_func_initgroups" = xyes
+then :
+ printf "%s\n" "#define HAVE_INITGROUPS 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "kqueue" "ac_cv_func_kqueue"
+if test "x$ac_cv_func_kqueue" = xyes
+then :
+ printf "%s\n" "#define HAVE_KQUEUE 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "localtime_r" "ac_cv_func_localtime_r"
+if test "x$ac_cv_func_localtime_r" = xyes
+then :
+ printf "%s\n" "#define HAVE_LOCALTIME_R 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "mallopt" "ac_cv_func_mallopt"
+if test "x$ac_cv_func_mallopt" = xyes
+then :
+ printf "%s\n" "#define HAVE_MALLOPT 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "mkdirat" "ac_cv_func_mkdirat"
+if test "x$ac_cv_func_mkdirat" = xyes
+then :
+ printf "%s\n" "#define HAVE_MKDIRAT 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "openat" "ac_cv_func_openat"
+if test "x$ac_cv_func_openat" = xyes
+then :
+ printf "%s\n" "#define HAVE_OPENAT 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "pthread_sigmask" "ac_cv_func_pthread_sigmask"
+if test "x$ac_cv_func_pthread_sigmask" = xyes
+then :
+ printf "%s\n" "#define HAVE_PTHREAD_SIGMASK 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "setlinebuf" "ac_cv_func_setlinebuf"
+if test "x$ac_cv_func_setlinebuf" = xyes
+then :
+ printf "%s\n" "#define HAVE_SETLINEBUF 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "setresuid" "ac_cv_func_setresuid"
+if test "x$ac_cv_func_setresuid" = xyes
+then :
+ printf "%s\n" "#define HAVE_SETRESUID 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "setsid" "ac_cv_func_setsid"
+if test "x$ac_cv_func_setsid" = xyes
+then :
+ printf "%s\n" "#define HAVE_SETSID 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "setuid" "ac_cv_func_setuid"
+if test "x$ac_cv_func_setuid" = xyes
+then :
+ printf "%s\n" "#define HAVE_SETUID 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "setvbuf" "ac_cv_func_setvbuf"
+if test "x$ac_cv_func_setvbuf" = xyes
+then :
+ printf "%s\n" "#define HAVE_SETVBUF 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "sigaction" "ac_cv_func_sigaction"
+if test "x$ac_cv_func_sigaction" = xyes
+then :
+ printf "%s\n" "#define HAVE_SIGACTION 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "sigprocmask" "ac_cv_func_sigprocmask"
+if test "x$ac_cv_func_sigprocmask" = xyes
+then :
+ printf "%s\n" "#define HAVE_SIGPROCMASK 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "snprintf" "ac_cv_func_snprintf"
+if test "x$ac_cv_func_snprintf" = xyes
+then :
+ printf "%s\n" "#define HAVE_SNPRINTF 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "strcasecmp" "ac_cv_func_strcasecmp"
+if test "x$ac_cv_func_strcasecmp" = xyes
+then :
+ printf "%s\n" "#define HAVE_STRCASECMP 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "strlcat" "ac_cv_func_strlcat"
+if test "x$ac_cv_func_strlcat" = xyes
+then :
+ printf "%s\n" "#define HAVE_STRLCAT 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "strlcpy" "ac_cv_func_strlcpy"
+if test "x$ac_cv_func_strlcpy" = xyes
+then :
+ printf "%s\n" "#define HAVE_STRLCPY 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "strncasecmp" "ac_cv_func_strncasecmp"
+if test "x$ac_cv_func_strncasecmp" = xyes
+then :
+ printf "%s\n" "#define HAVE_STRNCASECMP 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "strsep" "ac_cv_func_strsep"
+if test "x$ac_cv_func_strsep" = xyes
+then :
+ printf "%s\n" "#define HAVE_STRSEP 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "strsignal" "ac_cv_func_strsignal"
+if test "x$ac_cv_func_strsignal" = xyes
+then :
+ printf "%s\n" "#define HAVE_STRSIGNAL 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "unlinkat" "ac_cv_func_unlinkat"
+if test "x$ac_cv_func_unlinkat" = xyes
+then :
+ printf "%s\n" "#define HAVE_UNLINKAT 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "vdprintf" "ac_cv_func_vdprintf"
+if test "x$ac_cv_func_vdprintf" = xyes
+then :
+ printf "%s\n" "#define HAVE_VDPRINTF 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "vsnprintf" "ac_cv_func_vsnprintf"
+if test "x$ac_cv_func_vsnprintf" = xyes
+then :
+ printf "%s\n" "#define HAVE_VSNPRINTF 1" >>confdefs.h
+
+fi
+
+
+if test "x$ac_cv_header_utmpx_h" = "xyes"; then
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ut_xtime in struct utmpx" >&5
+printf %s "checking for ut_xtime in struct utmpx... " >&6; }
+
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <utmpx.h>
+#ifdef HAVE_STDDEF_H
+#include <stddef.h>
+#endif
+#ifndef offsetof
+#define offsetof(TYPE, MEMBER) ((int) &((TYPE *)0)->MEMBER)
+#endif
+
+int
+main (void)
+{
+ int foo = offsetof(struct utmpx, ut_xtime)
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+ has_element=" "
+else $as_nop
+ has_element=
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+
+ ac_safe_type=`echo "struct utmpx" | sed 'y% %_%'`
+ if test "x$has_element" != "x"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ eval "ac_cv_type_${ac_safe_type}_has_ut_xtime=yes"
+ else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ eval "ac_cv_type_${ac_safe_type}_has_ut_xtime="
+ fi
+
+ if test "x$ac_cv_type_struct_utmpx_has_ut_xtime" = "x"; then
+
+printf "%s\n" "#define ut_xtime ut_tv.tv_sec" >>confdefs.h
+
+ fi
+fi
+
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ipi_addr in struct in_pktinfo" >&5
+printf %s "checking for ipi_addr in struct in_pktinfo... " >&6; }
+
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <netinet/in.h>
+#ifdef HAVE_STDDEF_H
+#include <stddef.h>
+#endif
+#ifndef offsetof
+#define offsetof(TYPE, MEMBER) ((int) &((TYPE *)0)->MEMBER)
+#endif
+
+int
+main (void)
+{
+ int foo = offsetof(struct in_pktinfo, ipi_addr)
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+ has_element=" "
+else $as_nop
+ has_element=
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+
+ ac_safe_type=`echo "struct in_pktinfo" | sed 'y% %_%'`
+ if test "x$has_element" != "x"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ eval "ac_cv_type_${ac_safe_type}_has_ipi_addr=yes"
+ else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ eval "ac_cv_type_${ac_safe_type}_has_ipi_addr="
+ fi
+
+if test "x$ac_cv_type_struct_in_pktinfo_has_ipi_addr" = "xyes"; then
+
+printf "%s\n" "#define HAVE_IP_PKTINFO /**/" >>confdefs.h
+
+fi
+
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ipi6_addr in struct in6_pktinfo" >&5
+printf %s "checking for ipi6_addr in struct in6_pktinfo... " >&6; }
+
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <netinet/in.h>
+#ifdef HAVE_STDDEF_H
+#include <stddef.h>
+#endif
+#ifndef offsetof
+#define offsetof(TYPE, MEMBER) ((int) &((TYPE *)0)->MEMBER)
+#endif
+
+int
+main (void)
+{
+ int foo = offsetof(struct in6_pktinfo, ipi6_addr)
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+ has_element=" "
+else $as_nop
+ has_element=
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+
+ ac_safe_type=`echo "struct in6_pktinfo" | sed 'y% %_%'`
+ if test "x$has_element" != "x"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ eval "ac_cv_type_${ac_safe_type}_has_ipi6_addr=yes"
+ else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ eval "ac_cv_type_${ac_safe_type}_has_ipi6_addr="
+ fi
+
+if test "x$ac_cv_type_struct_in6_pktinfo_has_ipi6_addr" = "xyes"; then
+
+printf "%s\n" "#define HAVE_IN6_PKTINFO /**/" >>confdefs.h
+
+fi
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if htonll is defined" >&5
+printf %s "checking if htonll is defined... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <sys/types.h>
+ #include <netinet/in.h>
+
+int
+main (void)
+{
+
+ return htonll(0);
+
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+
+printf "%s\n" "#define HAVE_HTONLL 1" >>confdefs.h
+
+
+else $as_nop
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if htonlll is defined" >&5
+printf %s "checking if htonlll is defined... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <sys/types.h>
+ #include <netinet/in.h>
+
+int
+main (void)
+{
+
+ return htonlll(0);
+
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+
+printf "%s\n" "#define HAVE_HTONLLL 1" >>confdefs.h
+
+
+else $as_nop
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5
+printf %s "checking for an ANSI C-conforming const... " >&6; }
+if test ${ac_cv_c_const+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main (void)
+{
+
+#ifndef __cplusplus
+ /* Ultrix mips cc rejects this sort of thing. */
+ typedef int charset[2];
+ const charset cs = { 0, 0 };
+ /* SunOS 4.1.1 cc rejects this. */
+ char const *const *pcpcc;
+ char **ppc;
+ /* NEC SVR4.0.2 mips cc rejects this. */
+ struct point {int x, y;};
+ static struct point const zero = {0,0};
+ /* IBM XL C 1.02.0.0 rejects this.
+ It does not let you subtract one const X* pointer from another in
+ an arm of an if-expression whose if-part is not a constant
+ expression */
+ const char *g = "string";
+ pcpcc = &g + (g ? g-g : 0);
+ /* HPUX 7.0 cc rejects these. */
+ ++pcpcc;
+ ppc = (char**) pcpcc;
+ pcpcc = (char const *const *) ppc;
+ { /* SCO 3.2v4 cc rejects this sort of thing. */
+ char tx;
+ char *t = &tx;
+ char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+ *t++ = 0;
+ if (s) return 0;
+ }
+ { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */
+ int x[] = {25, 17};
+ const int *foo = &x[0];
+ ++foo;
+ }
+ { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+ typedef const int *iptr;
+ iptr p = 0;
+ ++p;
+ }
+ { /* IBM XL C 1.02.0.0 rejects this sort of thing, saying
+ "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+ struct s { int j; const int *ap[3]; } bx;
+ struct s *b = &bx; b->j = 5;
+ }
+ { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+ const int foo = 10;
+ if (!foo) return 0;
+ }
+ return !cs[0] && !zero.x;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+ ac_cv_c_const=yes
+else $as_nop
+ ac_cv_c_const=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5
+printf "%s\n" "$ac_cv_c_const" >&6; }
+if test $ac_cv_c_const = no; then
+
+printf "%s\n" "#define const /**/" >>confdefs.h
+
+fi
+
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking type of OS" >&5
+printf %s "checking type of OS... " >&6; }
+OS=`uname -s`
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OS" >&5
+printf "%s\n" "$OS" >&6; }
+if test "$OS" = "OS/2"; then
+ LIBPREFIX=
+else
+ LIBPREFIX=lib
+fi
+
+
+if test "x$developer" = "xyes"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Setting additional developer CFLAGS" >&5
+printf "%s\n" "$as_me: Setting additional developer CFLAGS" >&6;}
+
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for the compiler flag \"-Wdocumentation\"" >&5
+printf %s "checking for the compiler flag \"-Wdocumentation\"... " >&6; }
+if test ${ax_cv_cc_wdocumentation_flag+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+
+
+ CFLAGS_SAVED=$CFLAGS
+ CFLAGS="$CFLAGS -Werror -Wdocumentation"
+
+ 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
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main (void)
+{
+return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+ ax_cv_cc_wdocumentation_flag="yes"
+else $as_nop
+ ax_cv_cc_wdocumentation_flag="no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ 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
+
+
+ CFLAGS="$CFLAGS_SAVED"
+
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_cc_wdocumentation_flag" >&5
+printf "%s\n" "$ax_cv_cc_wdocumentation_flag" >&6; }
+
+ if test "x$ax_cv_cc_wdocumentation_flag" = "xyes"; then
+ devcflags="-Wdocumentation"
+
+printf "%s\n" "#define HAVE_WDOCUMENTATION 1" >>confdefs.h
+
+ fi
+
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for the compiler flag \"-Weverything\"" >&5
+printf %s "checking for the compiler flag \"-Weverything\"... " >&6; }
+if test ${ax_cv_cc_weverything_flag+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+
+
+ CFLAGS_SAVED=$CFLAGS
+ CFLAGS="$CFLAGS -Werror -Weverything -Wno-reserved-id-macro -Wno-unused-macros -Wno-unreachable-code-return -Wno-poison-system-directories"
+
+ 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
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main (void)
+{
+return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+ ax_cv_cc_weverything_flag="yes"
+else $as_nop
+ ax_cv_cc_weverything_flag="no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ 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
+
+
+ CFLAGS="$CFLAGS_SAVED"
+
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_cc_weverything_flag" >&5
+printf "%s\n" "$ax_cv_cc_weverything_flag" >&6; }
+
+ if test "x$ax_cv_cc_weverything_flag" = "xyes"; then
+ devcflags="$devcflags -W -Weverything -Wformat=2 -Wno-missing-field-initializers -Wno-date-time -Wno-padded -Wno-gnu-zero-variadic-macro-arguments -Wno-shorten-64-to-32 -Wno-sign-conversion -Wno-conversion -Wno-switch-enum -Wno-gnu-statement-expression -Wno-extended-offsetof -Wno-cast-align -Wno-documentation-unknown-command -Wno-covered-switch-default -Wno-packed $verify_ptr $fips"
+ else
+ if test "x$GCC" = "xyes"; then
+ devcflags="$devcflags -Wshadow -Wpointer-arith -Wcast-qual -Wcast-align -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wnested-externs -W -Wredundant-decls -Wundef -Wformat-y2k -Wno-format-extra-args -Wno-format-zero-length -Wno-cast-align -Wformat-nonliteral -Wformat-security -Wformat=2 $verify_ptr $fips"
+ INSTALLSTRIP=""
+ fi
+ fi
+
+ fsanitizeflags=
+
+ if test "x$fuzzer" = "xyes" && test "x$ax_cv_cc_clang" = "xyes"; then
+ fsanitizeflags="$fsanitizeflags,fuzzer"
+ fi
+
+ if test "x$address_sanitizer" = "xyes"; then
+ devcflags="$devcflags -fno-omit-frame-pointer -fno-optimize-sibling-calls"
+
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for the compiler flag \"-fsanitize-address-use-after-scope\"" >&5
+printf %s "checking for the compiler flag \"-fsanitize-address-use-after-scope\"... " >&6; }
+if test ${ax_cv_cc_sanitize_address_use_after_scope+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+
+
+ CFLAGS_SAVED=$CFLAGS
+ CFLAGS="$CFLAGS -Werror -fsanitize=address -fsanitize-address-use-after-scope"
+
+ 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
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main (void)
+{
+return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+ ax_cv_cc_sanitize_address_use_after_scope="yes"
+else $as_nop
+ ax_cv_cc_sanitize_address_use_after_scope="no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ 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
+
+
+ CFLAGS="$CFLAGS_SAVED"
+
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_cc_sanitize_address_use_after_scope" >&5
+printf "%s\n" "$ax_cv_cc_sanitize_address_use_after_scope" >&6; }
+
+ if test "x$ax_cv_cc_sanitize_address_use_after_scope" = "xyes"; then
+ devcflags="$devcflags -fsanitize-address-use-after-scope"
+ fi
+
+ ac_fn_c_check_header_compile "$LINENO" "sanitizer/lsan_interface.h" "ac_cv_header_sanitizer_lsan_interface_h" "$ac_includes_default"
+if test "x$ac_cv_header_sanitizer_lsan_interface_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SANITIZER_LSAN_INTERFACE_H 1" >>confdefs.h
+
+fi
+
+ fsanitizeflags="$fsanitizeflags,address"
+ fi
+
+ if test "x$leak_sanitizer" = "xyes"; then
+ fsanitizeflags="$fsanitizeflags,leak"
+ fi
+
+ if test "x$thread_sanitizer" = "xyes"; then
+ fsanitizeflags="$fsanitizeflags,thread"
+ fi
+
+ if test "x$undefined_behaviour_sanitizer" = "xyes"; then
+ devcflags="$devcflags -fno-sanitize-recover=undefined -fno-omit-frame-pointer"
+ devldflags="$devldflags -fno-sanitize-recover=undefined"
+ fsanitizeflags="$fsanitizeflags,undefined"
+ fi
+
+ if test "x$fsanitizeflags" != "x"; then
+ fsanitizeflags="$(echo $fsanitizeflags | sed 's/^,*//')"
+ devcflags="-fsanitize=$fsanitizeflags $devcflags"
+ devldflags="-fsanitize=$fsanitizeflags $devldflags"
+ fi
+
+ devcflags="$(echo $devcflags | sed -e 's/\\t//g;s/ //g')"
+ devldflags="$(echo $devldflags | sed -e 's/\\t//g;s/ //g')"
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Developer CFLAGS are \"$devcflags\"" >&5
+printf "%s\n" "$as_me: Developer CFLAGS are \"$devcflags\"" >&6;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Developer LDFLAGS are \"$devldflags\"" >&5
+printf "%s\n" "$as_me: Developer LDFLAGS are \"$devldflags\"" >&6;}
+
+ if test "x$EXPERIMENTAL" != "xno"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: is developer build, enabling experimental modules implicitly, disable with --without-experimental-modules" >&5
+printf "%s\n" "$as_me: is developer build, enabling experimental modules implicitly, disable with --without-experimental-modules" >&6;}
+ EXPERIMENTAL=yes
+ fi
+else
+ devcflags=""
+ devldflags=""
+ CFLAGS="$CFLAGS -DNDEBUG"
+ INSTALLSTRIP=""
+fi
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if building with -DNDEBUG" >&5
+printf %s "checking if building with -DNDEBUG... " >&6; }
+if echo "$CFLAGS" | grep '\-DNDEBUG' > /dev/null; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+
+printf "%s\n" "#define WITH_NDEBUG 1" >>confdefs.h
+
+else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+
+export EXPERIMENTAL
+
+if test -d $srcdir/.git -a "x$GIT" = "xyes"; then
+ RADIUSD_VERSION_COMMIT=`git log --pretty=format:'%h' -n 1 | cut -c1-9`
+
+printf "%s\n" "#define RADIUSD_VERSION_COMMIT ${RADIUSD_VERSION_COMMIT}" >>confdefs.h
+
+fi
+
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for __thread support in compiler" >&5
+printf %s "checking for __thread support in compiler... " >&6; }
+ if test "$cross_compiling" = yes
+then :
+ have_tls=no
+else $as_nop
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ static __thread int val;
+ int main(int argc, char **argv) {
+ val = 0;
+ return val;
+ }
+
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"
+then :
+ have_tls=yes
+else $as_nop
+ have_tls=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $have_tls" >&5
+printf "%s\n" "$have_tls" >&6; }
+ if test "x$have_tls" = "xyes"; then
+
+printf "%s\n" "#define TLS_STORAGE_CLASS __thread" >>confdefs.h
+
+ fi
+
+ if test "x$have_tls" = "xno"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for __declspec(thread) support in compiler" >&5
+printf %s "checking for __declspec(thread) support in compiler... " >&6; }
+ if test "$cross_compiling" = yes
+then :
+ have_tls=no
+else $as_nop
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ static _Thread_local int val;
+ int main(int argc, char **argv) {
+ val = 0;
+ return val;
+ }
+
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"
+then :
+ have_tls=yes
+else $as_nop
+ have_tls=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $have_tls" >&5
+printf "%s\n" "$have_tls" >&6; }
+ if test "x$have_tls" = "xyes"; then
+
+printf "%s\n" "#define TLS_STORAGE_CLASS __declspec(thread)" >>confdefs.h
+
+ fi
+ fi
+ if test "x$have_tls" = "xno"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for _Thread_local support in compiler" >&5
+printf %s "checking for _Thread_local support in compiler... " >&6; }
+ if test "$cross_compiling" = yes
+then :
+ have_tls=no
+else $as_nop
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ static _Thread_local int val;
+ int main(int argc, char **argv) {
+ val = 0;
+ return val;
+ }
+
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"
+then :
+ have_tls=yes
+else $as_nop
+ have_tls=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $have_tls" >&5
+printf "%s\n" "$have_tls" >&6; }
+ if test "x$have_tls" = "xyes"; then
+
+printf "%s\n" "#define TLS_STORAGE_CLASS _Thread_local" >>confdefs.h
+
+ fi
+ fi
+
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for __builtin_choose_expr support in compiler" >&5
+printf %s "checking for __builtin_choose_expr support in compiler... " >&6; }
+if test ${ax_cv_cc_builtin_choose_expr+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+
+ if test "$cross_compiling" = yes
+then :
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+printf "%s\n" "$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 $as_nop
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+
+ int main(int argc, char **argv) {
+ if ((argc < 0) || !argv) return 1; /* -Werror=unused-parameter */
+ return __builtin_choose_expr(0, 1, 0);
+ }
+
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"
+then :
+ ax_cv_cc_builtin_choose_expr=yes
+else $as_nop
+ ax_cv_cc_builtin_choose_expr=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
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_cc_builtin_choose_expr" >&5
+printf "%s\n" "$ax_cv_cc_builtin_choose_expr" >&6; }
+ if test "x$ax_cv_cc_builtin_choose_expr" = "xyes"; then
+
+printf "%s\n" "#define HAVE_BUILTIN_CHOOSE_EXPR 1" >>confdefs.h
+
+ fi
+
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for __builtin_types_compatible_p support in compiler" >&5
+printf %s "checking for __builtin_types_compatible_p support in compiler... " >&6; }
+if test ${ax_cv_cc_builtin_types_compatible_p+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+
+ if test "$cross_compiling" = yes
+then :
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+printf "%s\n" "$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 $as_nop
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+
+ int main(int argc, char **argv) {
+ if ((argc < 0) || !argv) return 1; /* -Werror=unused-parameter */
+ return !(__builtin_types_compatible_p(char *, char *));
+ }
+
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"
+then :
+ ax_cv_cc_builtin_types_compatible_p=yes
+else $as_nop
+ ax_cv_cc_builtin_types_compatible_p=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
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_cc_builtin_types_compatible_p" >&5
+printf "%s\n" "$ax_cv_cc_builtin_types_compatible_p" >&6; }
+ if test "x$ax_cv_cc_builtin_types_compatible_p" = "xyes"; then
+
+printf "%s\n" "#define HAVE_BUILTIN_TYPES_COMPATIBLE_P 1" >>confdefs.h
+
+ fi
+
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for __builtin_bswap64 support in compiler" >&5
+printf %s "checking for __builtin_bswap64 support in compiler... " >&6; }
+if test ${ax_cv_cc_builtin_bswap64+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+
+ if test "$cross_compiling" = yes
+then :
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+printf "%s\n" "$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 $as_nop
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+
+ int main(int argc, char **argv) {
+ if ((argc < 0) || !argv) return 1; /* -Werror=unused-parameter */
+ return (__builtin_bswap64(0));
+ }
+
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"
+then :
+ ax_cv_cc_builtin_bswap64=yes
+else $as_nop
+ ax_cv_cc_builtin_bswap64=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
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_cc_builtin_bswap64" >&5
+printf "%s\n" "$ax_cv_cc_builtin_bswap64" >&6; }
+ if test "x$ax_cv_cc_builtin_bswap64" = "xyes"; then
+
+printf "%s\n" "#define HAVE_BUILTIN_BSWAP_64 1" >>confdefs.h
+
+ fi
+
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for __attribute__((__bounded__)) support in compiler" >&5
+printf %s "checking for __attribute__((__bounded__)) support in compiler... " >&6; }
+if test ${ax_cv_cc_bounded_attribute+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+
+ CFLAGS_SAVED=$CFLAGS
+ CFLAGS="$CFLAGS -Werror"
+ if test "$cross_compiling" = yes
+then :
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+printf "%s\n" "$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 $as_nop
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+
+ void test(char *buff) __attribute__ ((__bounded__ (__string__, 1, 1)));
+ int main(int argc, char **argv) {
+ if ((argc < 0) || !argv) return 1; /* -Werror=unused-parameter */
+ return 0;
+ }
+
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"
+then :
+ ax_cv_cc_bounded_attribute=yes
+else $as_nop
+ ax_cv_cc_bounded_attribute=no
+
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+ CFLAGS="$CFLAGS_SAVED"
+
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_cc_bounded_attribute" >&5
+printf "%s\n" "$ax_cv_cc_bounded_attribute" >&6; }
+ if test "x$ax_cv_cc_bounded_attribute" = "xyes"; then
+
+printf "%s\n" "#define HAVE_ATTRIBUTE_BOUNDED 1" >>confdefs.h
+
+ fi
+
+
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for talloc_set_memlimit in -ltalloc" >&5
+printf %s "checking for talloc_set_memlimit in -ltalloc... " >&6; }
+if test ${ac_cv_lib_talloc_talloc_set_memlimit+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ltalloc $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+char talloc_set_memlimit ();
+int
+main (void)
+{
+return talloc_set_memlimit ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+ ac_cv_lib_talloc_talloc_set_memlimit=yes
+else $as_nop
+ ac_cv_lib_talloc_talloc_set_memlimit=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_talloc_talloc_set_memlimit" >&5
+printf "%s\n" "$ac_cv_lib_talloc_talloc_set_memlimit" >&6; }
+if test "x$ac_cv_lib_talloc_talloc_set_memlimit" = xyes
+then :
+
+
+printf "%s\n" "#define HAVE_TALLOC_SET_MEMLIMIT 1" >>confdefs.h
+
+
+
+fi
+
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for crypt in -lcrypt" >&5
+printf %s "checking for crypt in -lcrypt... " >&6; }
+if test ${ac_cv_lib_crypt_crypt+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcrypt $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+char crypt ();
+int
+main (void)
+{
+return crypt ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+ ac_cv_lib_crypt_crypt=yes
+else $as_nop
+ ac_cv_lib_crypt_crypt=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypt_crypt" >&5
+printf "%s\n" "$ac_cv_lib_crypt_crypt" >&6; }
+if test "x$ac_cv_lib_crypt_crypt" = xyes
+then :
+ CRYPTLIB="-lcrypt"
+
+fi
+
+
+if test "$CRYPTLIB" != ""; then
+
+printf "%s\n" "#define HAVE_CRYPT /**/" >>confdefs.h
+
+else
+ ac_fn_c_check_func "$LINENO" "crypt" "ac_cv_func_crypt"
+if test "x$ac_cv_func_crypt" = xyes
+then :
+
+printf "%s\n" "#define HAVE_CRYPT /**/" >>confdefs.h
+
+fi
+
+fi
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for crypt_r in -lcrypt" >&5
+printf %s "checking for crypt_r in -lcrypt... " >&6; }
+if test ${ac_cv_lib_crypt_crypt_r+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcrypt $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+char crypt_r ();
+int
+main (void)
+{
+return crypt_r ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+ ac_cv_lib_crypt_crypt_r=yes
+else $as_nop
+ ac_cv_lib_crypt_crypt_r=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypt_crypt_r" >&5
+printf "%s\n" "$ac_cv_lib_crypt_crypt_r" >&6; }
+if test "x$ac_cv_lib_crypt_crypt_r" = xyes
+then :
+
+printf "%s\n" "#define HAVE_CRYPT_R /**/" >>confdefs.h
+
+fi
+
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for setkey in -lcipher" >&5
+printf %s "checking for setkey in -lcipher... " >&6; }
+if test ${ac_cv_lib_cipher_setkey+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcipher $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+char setkey ();
+int
+main (void)
+{
+return setkey ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+ ac_cv_lib_cipher_setkey=yes
+else $as_nop
+ ac_cv_lib_cipher_setkey=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_cipher_setkey" >&5
+printf "%s\n" "$ac_cv_lib_cipher_setkey" >&6; }
+if test "x$ac_cv_lib_cipher_setkey" = xyes
+then :
+ CRYPTLIB="${CRYPTLIB} -lcipher"
+
+fi
+
+
+
+execinfo_lib_dir=
+
+# Check whether --with-execinfo-lib-dir was given.
+if test ${with_execinfo_lib_dir+y}
+then :
+ withval=$with_execinfo_lib_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need execinfo-lib-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ execinfo_lib_dir="$withval"
+ ;;
+ esac
+
+fi
+
+
+execinfo_include_dir=
+
+# Check whether --with-execinfo-include-dir was given.
+if test ${with_execinfo_include_dir+y}
+then :
+ withval=$with_execinfo_include_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need execinfo-include-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ execinfo_include_dir="$withval"
+ ;;
+ esac
+
+fi
+
+
+smart_try_dir=$execinfo_include_dir
+
+
+ac_safe=`echo "execinfo.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
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for execinfo.h in $try" >&5
+printf %s "checking for execinfo.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <execinfo.h>
+int
+main (void)
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+
+ smart_include="-isystem $try"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+
+ smart_include=
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ done
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_include" = "x"; then
+ for _prefix in $smart_prefix; do
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ${_prefix}/execinfo.h" >&5
+printf %s "checking for ${_prefix}/execinfo.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <execinfo.h>
+int
+main (void)
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+
+ smart_include="-isystem ${_prefix}/"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+
+ smart_include=
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ done
+fi
+
+if test "x$smart_include" = "x"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for execinfo.h" >&5
+printf %s "checking for execinfo.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <execinfo.h>
+int
+main (void)
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+
+ smart_include=" "
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+
+ smart_include=
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+if test "x$smart_include" = "x"; then
+
+ for try in $_smart_include_dir; do
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for execinfo.h in $try" >&5
+printf %s "checking for execinfo.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <execinfo.h>
+int
+main (void)
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+
+ smart_include="-isystem $try"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+
+ smart_include=
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam 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_execinfo_h" = "xyes"; then
+ smart_try_dir=$execinfo_lib_dir
+
+
+sm_lib_safe=`echo "execinfo" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "backtrace_symbols" | sed 'y%./+-%__p_%'`
+
+old_LIBS="$LIBS"
+old_CPPFLAGS="$CPPFLAGS"
+smart_lib=
+smart_ldflags=
+smart_lib_dir=
+
+if test "x$smart_try_dir" != "x"; then
+ for try in $smart_try_dir; do
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for backtrace_symbols in -lexecinfo in $try" >&5
+printf %s "checking for backtrace_symbols in -lexecinfo in $try... " >&6; }
+ LIBS="-lexecinfo $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char backtrace_symbols();
+int
+main (void)
+{
+backtrace_symbols()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+
+ smart_lib="-lexecinfo"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+ LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_lib" = "x"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for backtrace_symbols in -lexecinfo" >&5
+printf %s "checking for backtrace_symbols in -lexecinfo... " >&6; }
+ LIBS="-lexecinfo $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char backtrace_symbols();
+int
+main (void)
+{
+backtrace_symbols()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+
+ smart_lib="-lexecinfo"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ 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
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for backtrace_symbols in -lexecinfo in $try" >&5
+printf %s "checking for backtrace_symbols in -lexecinfo in $try... " >&6; }
+ LIBS="-lexecinfo $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char backtrace_symbols();
+int
+main (void)
+{
+backtrace_symbols()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+
+ smart_lib="-lexecinfo"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ 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_execinfo_backtrace_symbols" != "xyes"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if execinfo provided as part of libc" >&5
+printf %s "checking if execinfo provided as part of libc... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <execinfo.h>
+
+int
+main (void)
+{
+
+ void *sym[1];
+ backtrace_symbols(&sym, sizeof(sym))
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ ac_cv_lib_execinfo_backtrace_symbols="yes"
+
+else $as_nop
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+ fi
+
+ if test "x$ac_cv_lib_execinfo_backtrace_symbols" = "xyes"; then
+
+printf "%s\n" "#define HAVE_EXECINFO 1" >>confdefs.h
+
+ fi
+fi
+
+PCRE=yes
+
+# Check whether --with-pcre was given.
+if test ${with_pcre+y}
+then :
+ withval=$with_pcre; case "$withval" in
+ no)
+ PCRE=no
+ ;;
+ yes)
+ PCRE=yes
+ ;;
+ esac
+
+fi
+
+
+pcre_lib_dir=
+
+# Check whether --with-pcre-lib-dir was given.
+if test ${with_pcre_lib_dir+y}
+then :
+ withval=$with_pcre_lib_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need pcre-lib-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ pcre_lib_dir="$withval"
+ ;;
+ esac
+
+fi
+
+
+pcre_include_dir=
+
+# Check whether --with-pcre-include-dir was given.
+if test ${with_pcre_include_dir+y}
+then :
+ withval=$with_pcre_include_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need pcre-include-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ pcre_include_dir="$withval"
+ ;;
+ esac
+
+fi
+
+
+REGEX=
+
+# Check whether --with-regex was given.
+if test ${with_regex+y}
+then :
+ withval=$with_regex; case "$withval" in
+ no)
+ REGEX=no
+ ;;
+ *)
+ ;;
+ esac
+
+fi
+
+
+if test "x$REGEX" != "xno" && test "x$PCRE" != "xno"; then
+ smart_try_dir=$pcre_include_dir
+
+
+ac_safe=`echo "pcre.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
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pcre.h in $try" >&5
+printf %s "checking for pcre.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <pcre.h>
+int
+main (void)
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+
+ smart_include="-isystem $try"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+
+ smart_include=
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ done
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_include" = "x"; then
+ for _prefix in $smart_prefix; do
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ${_prefix}/pcre.h" >&5
+printf %s "checking for ${_prefix}/pcre.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <pcre.h>
+int
+main (void)
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+
+ smart_include="-isystem ${_prefix}/"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+
+ smart_include=
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ done
+fi
+
+if test "x$smart_include" = "x"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pcre.h" >&5
+printf %s "checking for pcre.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <pcre.h>
+int
+main (void)
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+
+ smart_include=" "
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+
+ smart_include=
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+if test "x$smart_include" = "x"; then
+
+ for try in $_smart_include_dir; do
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pcre.h in $try" >&5
+printf %s "checking for pcre.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <pcre.h>
+int
+main (void)
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+
+ smart_include="-isystem $try"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+
+ smart_include=
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam 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_pcre_h" = "xyes"; then
+ smart_try_dir=$pcre_lib_dir
+
+
+sm_lib_safe=`echo "pcre" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "pcre_compile" | 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
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pcre_compile in -lpcre in $try" >&5
+printf %s "checking for pcre_compile in -lpcre in $try... " >&6; }
+ LIBS="-lpcre $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char pcre_compile();
+int
+main (void)
+{
+pcre_compile()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+
+ smart_lib="-lpcre"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+ LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_lib" = "x"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pcre_compile in -lpcre" >&5
+printf %s "checking for pcre_compile in -lpcre... " >&6; }
+ LIBS="-lpcre $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char pcre_compile();
+int
+main (void)
+{
+pcre_compile()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+
+ smart_lib="-lpcre"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ 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
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pcre_compile in -lpcre in $try" >&5
+printf %s "checking for pcre_compile in -lpcre in $try... " >&6; }
+ LIBS="-lpcre $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char pcre_compile();
+int
+main (void)
+{
+pcre_compile()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+
+ smart_lib="-lpcre"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ 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_pcre_pcre_compile" = "xyes"; then
+ REGEX=yes
+
+printf "%s\n" "#define HAVE_PCRE 1" >>confdefs.h
+
+
+printf "%s\n" "#define HAVE_BINSAFE_REGEX 1" >>confdefs.h
+
+ fi
+ fi
+fi
+
+if test "x$REGEX" = "x"; then
+ smart_try_dir=
+
+
+ac_safe=`echo "regex.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
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for regex.h in $try" >&5
+printf %s "checking for regex.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <regex.h>
+int
+main (void)
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+
+ smart_include="-isystem $try"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+
+ smart_include=
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ done
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_include" = "x"; then
+ for _prefix in $smart_prefix; do
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ${_prefix}/regex.h" >&5
+printf %s "checking for ${_prefix}/regex.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <regex.h>
+int
+main (void)
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+
+ smart_include="-isystem ${_prefix}/"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+
+ smart_include=
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ done
+fi
+
+if test "x$smart_include" = "x"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for regex.h" >&5
+printf %s "checking for regex.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <regex.h>
+int
+main (void)
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+
+ smart_include=" "
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+
+ smart_include=
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+if test "x$smart_include" = "x"; then
+
+ for try in $_smart_include_dir; do
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for regex.h in $try" >&5
+printf %s "checking for regex.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <regex.h>
+int
+main (void)
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+
+ smart_include="-isystem $try"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ break
+
+else $as_nop
+
+ smart_include=
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam 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_regex_h" = "xyes"; then
+ REGEX=yes
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for extended regular expressions" >&5
+printf %s "checking for extended regular expressions... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <regex.h>
+ #ifdef REG_EXTENDED
+ yes
+ #endif
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "yes" >/dev/null 2>&1
+then :
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+
+printf "%s\n" "#define HAVE_REG_EXTENDED 1" >>confdefs.h
+
+
+else $as_nop
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+
+fi
+rm -rf conftest*
+
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for regcomp in -lregex" >&5
+printf %s "checking for regcomp in -lregex... " >&6; }
+if test ${ac_cv_lib_regex_regcomp+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lregex $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. */
+char regcomp ();
+int
+main (void)
+{
+return regcomp ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+ ac_cv_lib_regex_regcomp=yes
+else $as_nop
+ ac_cv_lib_regex_regcomp=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_regex_regcomp" >&5
+printf "%s\n" "$ac_cv_lib_regex_regcomp" >&6; }
+if test "x$ac_cv_lib_regex_regcomp" = xyes
+then :
+
+ LIBS="-lregex $LIBS"
+
+
+fi
+
+
+ ac_fn_c_check_func "$LINENO" "regncomp" "ac_cv_func_regncomp"
+if test "x$ac_cv_func_regncomp" = xyes
+then :
+ printf "%s\n" "#define HAVE_REGNCOMP 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "regnexec" "ac_cv_func_regnexec"
+if test "x$ac_cv_func_regnexec" = xyes
+then :
+ printf "%s\n" "#define HAVE_REGNEXEC 1" >>confdefs.h
+
+fi
+
+ if test x"$ac_cv_func_regncomp" = x"yes" && test x"$ac_cv_func_regnexec" = x"yes"; then
+
+printf "%s\n" "#define HAVE_BINSAFE_REGEX 1" >>confdefs.h
+
+ fi
+ fi
+fi
+
+#
+# Some platforms require an explicit -latomic
+#
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing __atomic_load_4" >&5
+printf %s "checking for library containing __atomic_load_4... " >&6; }
+if test ${ac_cv_search___atomic_load_4+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_func_search_save_LIBS=$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. */
+char __atomic_load_4 ();
+int
+main (void)
+{
+return __atomic_load_4 ();
+ ;
+ return 0;
+}
+_ACEOF
+for ac_lib in '' atomic
+do
+ if test -z "$ac_lib"; then
+ ac_res="none required"
+ else
+ ac_res=-l$ac_lib
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ fi
+ if ac_fn_c_try_link "$LINENO"
+then :
+ ac_cv_search___atomic_load_4=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext
+ if test ${ac_cv_search___atomic_load_4+y}
+then :
+ break
+fi
+done
+if test ${ac_cv_search___atomic_load_4+y}
+then :
+
+else $as_nop
+ ac_cv_search___atomic_load_4=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search___atomic_load_4" >&5
+printf "%s\n" "$ac_cv_search___atomic_load_4" >&6; }
+ac_res=$ac_cv_search___atomic_load_4
+if test "$ac_res" != no
+then :
+ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+fi
+
+
+if test "x$REGEX" = "xyes"; then
+
+printf "%s\n" "#define HAVE_REGEX 1" >>confdefs.h
+
+fi
+
+
+printf "%s\n" "#define GNUSTYLE 1" >>confdefs.h
+
+
+
+printf "%s\n" "#define SYSVSTYLE 2" >>confdefs.h
+
+
+
+printf "%s\n" "#define BSDSTYLE 3" >>confdefs.h
+
+
+gethostbyaddrrstyle=""
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking gethostbyaddr_r() syntax" >&5
+printf %s "checking gethostbyaddr_r() syntax... " >&6; }
+case "$host" in
+ *-freebsd*)
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC options needed to detect all undeclared functions" >&5
+printf %s "checking for $CC options needed to detect all undeclared functions... " >&6; }
+if test ${ac_cv_c_undeclared_builtin_options+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_save_CFLAGS=$CFLAGS
+ ac_cv_c_undeclared_builtin_options='cannot detect'
+ for ac_arg in '' -fno-builtin; do
+ CFLAGS="$ac_save_CFLAGS $ac_arg"
+ # This test program should *not* compile successfully.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main (void)
+{
+(void) strchr;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+
+else $as_nop
+ # This test program should compile successfully.
+ # No library function is consistently available on
+ # freestanding implementations, so test against a dummy
+ # declaration. Include always-available headers on the
+ # off chance that they somehow elicit warnings.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <float.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stddef.h>
+extern void ac_decl (int, char *);
+
+int
+main (void)
+{
+(void) ac_decl (0, (char *) 0);
+ (void) ac_decl;
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+ if test x"$ac_arg" = x
+then :
+ ac_cv_c_undeclared_builtin_options='none needed'
+else $as_nop
+ ac_cv_c_undeclared_builtin_options=$ac_arg
+fi
+ break
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ done
+ CFLAGS=$ac_save_CFLAGS
+
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_undeclared_builtin_options" >&5
+printf "%s\n" "$ac_cv_c_undeclared_builtin_options" >&6; }
+ case $ac_cv_c_undeclared_builtin_options in #(
+ 'cannot detect') :
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot make $CC report undeclared builtins
+See \`config.log' for more details" "$LINENO" 5; } ;; #(
+ 'none needed') :
+ ac_c_undeclared_builtin_options='' ;; #(
+ *) :
+ ac_c_undeclared_builtin_options=$ac_cv_c_undeclared_builtin_options ;;
+esac
+
+ac_fn_check_decl "$LINENO" "gethostbyaddr_r" "ac_cv_have_decl_gethostbyaddr_r" "
+ #ifdef HAVE_NETDB_H
+ #include <netdb.h>
+ #endif
+
+" "$ac_c_undeclared_builtin_options" "CFLAGS"
+if test "x$ac_cv_have_decl_gethostbyaddr_r" = xyes
+then :
+ ac_have_decl=1
+else $as_nop
+ ac_have_decl=0
+fi
+printf "%s\n" "#define HAVE_DECL_GETHOSTBYADDR_R $ac_have_decl" >>confdefs.h
+if test $ac_have_decl = 1
+then :
+
+else $as_nop
+
+
+printf "%s\n" "#define GETHOSTBYADDRRSTYLE BSDSTYLE" >>confdefs.h
+
+ gethostbyaddrrstyle=BSD
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: FreeBSD overridden to BSD-style" >&5
+printf "%s\n" "$as_me: WARNING: FreeBSD overridden to BSD-style" >&2;}
+
+fi
+
+ ;;
+esac
+
+if test "x$gethostbyaddrrstyle" = "x"; then
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <stdio.h>
+ #include <netdb.h>
+
+int
+main (void)
+{
+ gethostbyaddr_r(NULL, 0, 0, NULL, NULL, 0, NULL, NULL)
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+
+
+printf "%s\n" "#define GETHOSTBYADDRRSTYLE GNUSTYLE" >>confdefs.h
+
+ gethostbyaddrrstyle=GNU
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+
+if test "x$gethostbyaddrrstyle" = "x"; then
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <stdio.h>
+ #include <netdb.h>
+
+int
+main (void)
+{
+ gethostbyaddr_r(NULL, 0, 0, NULL, NULL, 0, NULL)
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+
+
+printf "%s\n" "#define GETHOSTBYADDRRSTYLE SYSVSTYLE" >>confdefs.h
+
+ gethostbyaddrrstyle=SYSV
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+
+
+if test "x$gethostbyaddrrstyle" = "x"; then
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <stdio.h>
+ #include <netdb.h>
+
+int
+main (void)
+{
+ gethostbyaddr(NULL, 0, 0)
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+
+
+printf "%s\n" "#define GETHOSTBYADDRRSTYLE BSDSTYLE" >>confdefs.h
+
+ gethostbyaddrrstyle=BSD
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+
+if test "x$gethostbyaddrrstyle" = "x"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none! It must not exist, here." >&5
+printf "%s\n" "none! It must not exist, here." >&6; }
+else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${gethostbyaddrrstyle}-style" >&5
+printf "%s\n" "${gethostbyaddrrstyle}-style" >&6; }
+fi
+
+if test "x$gethostbyaddrrstyle" = "xBSD"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: ****** BSD-style gethostbyaddr might NOT be thread-safe! ****** " >&5
+printf "%s\n" "$as_me: WARNING: ****** BSD-style gethostbyaddr might NOT be thread-safe! ****** " >&2;}
+fi
+
+gethostbynamerstyle=""
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking gethostbyname_r() syntax" >&5
+printf %s "checking gethostbyname_r() syntax... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <stdio.h>
+ #include <netdb.h>
+
+int
+main (void)
+{
+ gethostbyname_r(NULL, NULL, NULL, 0, NULL, NULL)
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+
+
+printf "%s\n" "#define GETHOSTBYNAMERSTYLE GNUSTYLE" >>confdefs.h
+
+ gethostbynamerstyle=GNU
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+
+if test "x$gethostbynamerstyle" = "x"; then
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <stdio.h>
+ #include <netdb.h>
+
+int
+main (void)
+{
+ gethostbyname_r(NULL, NULL, NULL, 0, NULL)
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+
+
+printf "%s\n" "#define GETHOSTBYNAMERSTYLE SYSVSTYLE" >>confdefs.h
+
+ gethostbynamerstyle=SYSV
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+
+if test "x$gethostbynamerstyle" = "x"; then
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <stdio.h>
+ #include <netdb.h>
+
+int
+main (void)
+{
+ gethostbyname(NULL)
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+
+
+printf "%s\n" "#define GETHOSTBYNAMERSTYLE BSDSTYLE" >>confdefs.h
+
+ gethostbynamerstyle=BSD
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+
+if test "x$gethostbynamerstyle" = "x"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none! It must not exist, here." >&5
+printf "%s\n" "none! It must not exist, here." >&6; }
+else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${gethostbynamerstyle}-style" >&5
+printf "%s\n" "${gethostbynamerstyle}-style" >&6; }
+fi
+
+if test "x$gethostbynamerstyle" = "xBSD"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: ****** BSD-style gethostbyname might NOT be thread-safe! ****** " >&5
+printf "%s\n" "$as_me: WARNING: ****** BSD-style gethostbyname might NOT be thread-safe! ****** " >&2;}
+fi
+
+if test "x$ac_cv_header_pwd_h" = "xyes"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking getpwnam_r" >&5
+printf %s "checking getpwnam_r... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <stdlib.h>
+ #include <sys/types.h>
+ #include <pwd.h>
+
+int
+main (void)
+{
+ getpwnam_r(NULL, NULL, NULL, 0, NULL)
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+
+printf "%s\n" "#define HAVE_GETPWNAM_R 1" >>confdefs.h
+
+
+else $as_nop
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+
+if test "x$ac_cv_header_grp_h" = "xyes"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking getgrnam_r" >&5
+printf %s "checking getgrnam_r... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <stdlib.h>
+ #include <sys/types.h>
+ #include <grp.h>
+
+int
+main (void)
+{
+ getgrnam_r(NULL, NULL, NULL, 0, NULL)
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+
+printf "%s\n" "#define HAVE_GETGRNAM_R 1" >>confdefs.h
+
+
+else $as_nop
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+
+
+
+printf "%s\n" "#define POSIXSTYLE 1" >>confdefs.h
+
+
+printf "%s\n" "#define SOLARISSTYLE 2" >>confdefs.h
+
+ctimerstyle=""
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking ctime_r() syntax" >&5
+printf %s "checking ctime_r() syntax... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <time.h>
+
+int
+main (void)
+{
+ ctime_r(NULL, NULL, 0)
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+
+
+printf "%s\n" "#define CTIMERSTYLE SOLARISSTYLE" >>confdefs.h
+
+ ctimerstyle="SOLARIS"
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+
+if test "x$ctimerstyle" = "x"; then
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <time.h>
+
+int
+main (void)
+{
+ ctime_r(NULL, NULL)
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+
+
+printf "%s\n" "#define CTIMERSTYLE POSIXSTYLE" >>confdefs.h
+
+ ctimerstyle="POSIX"
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+
+if test "x$ctimerstyle" = "x"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none! It must not exist, here." >&5
+printf "%s\n" "none! It must not exist, here." >&6; }
+else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${ctimerstyle}-style" >&5
+printf "%s\n" "${ctimerstyle}-style" >&6; }
+fi
+
+HOSTINFO=$host
+
+
+
+top_builddir=`pwd`
+export top_builddir
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: top_builddir=$top_builddir" >&5
+printf "%s\n" "top_builddir=$top_builddir" >&6; }
+
+
+
+
+if test "x$EXPERIMENTAL" = "xyes"; then
+ for foo in `ls -1 "${srcdir}"/src/modules | grep rlm_`; do
+ MODULES="$MODULES $foo"
+ done
+else
+ for foo in `cat "${srcdir}"/src/modules/stable`; do
+ MODULES="$MODULES $foo"
+ done
+fi
+
+mysubdirs=""
+for bar in $MODULES; do
+ if test -f "${srcdir}"/src/modules/$bar/configure; then
+ mysubdirs="$mysubdirs src/modules/$bar"
+ fi
+done
+
+
+
+subdirs="$subdirs $mysubdirs"
+
+
+
+if test "x$ax_cv_cc_no_date_time_flag" = "xyes" && test "x$reproducible_builds" != "xyes"; then
+ CFLAGS="-Wno-date-time $CFLAGS"
+fi
+
+CFLAGS="$CFLAGS $devcflags"
+LDFLAGS="$LDFLAGS $devldflags"
+
+if test "x$werror" = "xyes"; then
+ CFLAGS="-Werror $CFLAGS"
+fi
+
+ac_config_commands="$ac_config_commands stamp-h"
+
+ac_config_commands="$ac_config_commands build-radpaths-h"
+
+ac_config_commands="$ac_config_commands main-chmod"
+
+ac_config_commands="$ac_config_commands scripts-chmod"
+
+
+
+
+
+
+USE_STATIC_LIBS="yes"
+
+
+
+ac_config_files="$ac_config_files ./Make.inc ./src/include/build-radpaths-h ./src/main/radsniff.mk ./src/main/checkrad ./src/main/radlast ./src/main/radtest ./scripts/rc.radiusd ./scripts/cron/radiusd.cron.daily ./scripts/cron/radiusd.cron.monthly ./scripts/cryptpasswd ./raddb/radrelay.conf ./raddb/radiusd.conf"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# 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_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+printf "%s\n" "$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+y} || &/
+ 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
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+printf "%s\n" "$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
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+printf "%s\n" "$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=`printf "%s\n" "$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"
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+printf "%s\n" "$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
+as_nop=:
+if test ${ZSH_VERSION+y} && (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 $as_nop
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+
+# Reset variables that may have inherited troublesome values from
+# the environment.
+
+# IFS needs to be set, to space, tab, and newline, in precisely that order.
+# (If _AS_PATH_WALK were called with IFS unset, it would have the
+# side effect of setting IFS to empty, thus disabling word splitting.)
+# Quoting is to prevent editors from complaining about space-tab.
+as_nl='
+'
+export as_nl
+IFS=" "" $as_nl"
+
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# Ensure predictable behavior from utilities with locale-dependent output.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# We cannot yet rely on "unset" to work, but we need these variables
+# to be unset--not just set to an empty or harmless value--now, to
+# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct
+# also avoids known problems related to "unset" and subshell syntax
+# in other old shells (e.g. bash 2.01 and pdksh 5.2.14).
+for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH
+do eval test \${$as_var+y} \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+
+# Ensure that fds 0, 1, and 2 are open.
+if (exec 3>&0) 2>/dev/null; then :; else exec 0</dev/null; fi
+if (exec 3>&1) 2>/dev/null; then :; else exec 1>/dev/null; fi
+if (exec 3>&2) ; then :; else exec 2>/dev/null; fi
+
+# The user is always right.
+if ${PATH_SEPARATOR+false} :; 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
+
+
+# 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
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ 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
+ printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+
+
+# 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
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ printf "%s\n" "$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_nop
+ 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_nop
+ 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 ||
+printf "%s\n" 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
+
+
+# Determine whether it's possible to make 'echo' print without a newline.
+# These variables are no longer used directly by Autoconf, but are AC_SUBSTed
+# for compatibility with existing Makefiles.
+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
+
+# For backward compatibility with old third-party macros, we provide
+# the shell variables $as_echo and $as_echo_n. New code should use
+# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively.
+as_echo='printf %s\n'
+as_echo_n='printf %s'
+
+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=`printf "%s\n" "$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 ||
+printf "%s\n" 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 freeradius $as_me $Id$, which was
+generated by GNU Autoconf 2.71. 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"
+config_commands="$ac_config_commands"
+
+_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
+
+Configuration commands:
+$config_commands
+
+Report bugs to <http://bugs.freeradius.org>.
+freeradius home page: <http://www.freeradius.org>."
+
+_ACEOF
+ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"`
+ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"`
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config='$ac_cs_config_escaped'
+ac_cs_version="\\
+freeradius config.status $Id$
+configured by $0, generated by GNU Autoconf 2.71,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2021 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 )
+ printf "%s\n" "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ printf "%s\n" "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`printf "%s\n" "$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=`printf "%s\n" "$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 )
+ printf "%s\n" "$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
+ \printf "%s\n" "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
+ printf "%s\n" "$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
+ "src/include/autoconf.h") CONFIG_HEADERS="$CONFIG_HEADERS src/include/autoconf.h" ;;
+ "stamp-h") CONFIG_COMMANDS="$CONFIG_COMMANDS stamp-h" ;;
+ "build-radpaths-h") CONFIG_COMMANDS="$CONFIG_COMMANDS build-radpaths-h" ;;
+ "main-chmod") CONFIG_COMMANDS="$CONFIG_COMMANDS main-chmod" ;;
+ "scripts-chmod") CONFIG_COMMANDS="$CONFIG_COMMANDS scripts-chmod" ;;
+ "./Make.inc") CONFIG_FILES="$CONFIG_FILES ./Make.inc" ;;
+ "./src/include/build-radpaths-h") CONFIG_FILES="$CONFIG_FILES ./src/include/build-radpaths-h" ;;
+ "./src/main/radsniff.mk") CONFIG_FILES="$CONFIG_FILES ./src/main/radsniff.mk" ;;
+ "./src/main/checkrad") CONFIG_FILES="$CONFIG_FILES ./src/main/checkrad" ;;
+ "./src/main/radlast") CONFIG_FILES="$CONFIG_FILES ./src/main/radlast" ;;
+ "./src/main/radtest") CONFIG_FILES="$CONFIG_FILES ./src/main/radtest" ;;
+ "./scripts/rc.radiusd") CONFIG_FILES="$CONFIG_FILES ./scripts/rc.radiusd" ;;
+ "./scripts/cron/radiusd.cron.daily") CONFIG_FILES="$CONFIG_FILES ./scripts/cron/radiusd.cron.daily" ;;
+ "./scripts/cron/radiusd.cron.monthly") CONFIG_FILES="$CONFIG_FILES ./scripts/cron/radiusd.cron.monthly" ;;
+ "./scripts/cryptpasswd") CONFIG_FILES="$CONFIG_FILES ./scripts/cryptpasswd" ;;
+ "./raddb/radrelay.conf") CONFIG_FILES="$CONFIG_FILES ./raddb/radrelay.conf" ;;
+ "./raddb/radiusd.conf") CONFIG_FILES="$CONFIG_FILES ./raddb/radiusd.conf" ;;
+
+ *) 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+y} || CONFIG_FILES=$config_files
+ test ${CONFIG_HEADERS+y} || CONFIG_HEADERS=$config_headers
+ test ${CONFIG_COMMANDS+y} || CONFIG_COMMANDS=$config_commands
+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 :C $CONFIG_COMMANDS"
+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=`printf "%s\n" "$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 '`
+ printf "%s\n" "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+printf "%s\n" "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`printf "%s\n" "$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 ||
+printf "%s\n" 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=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`printf "%s\n" "$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@*)
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+printf "%s\n" "$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"; } &&
+ { printf "%s\n" "$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
+printf "%s\n" "$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
+ {
+ printf "%s\n" "/* $configure_input */" >&1 \
+ && 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
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
+printf "%s\n" "$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
+ printf "%s\n" "/* $configure_input */" >&1 \
+ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \
+ || as_fn_error $? "could not create -" "$LINENO" 5
+ fi
+ ;;
+
+ :C) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5
+printf "%s\n" "$as_me: executing $ac_file commands" >&6;}
+ ;;
+ esac
+
+
+ case $ac_file$ac_mode in
+ "stamp-h":C) echo timestamp > src/include/stamp-h ;;
+ "build-radpaths-h":C) (cd ./src/include && /bin/sh ./build-radpaths-h) ;;
+ "main-chmod":C) (cd ./src/main && chmod +x checkrad radlast radtest) ;;
+ "scripts-chmod":C) (cd ./scripts && chmod +x rc.radiusd cron/radiusd.cron.daily cron/radiusd.cron.monthly cryptpasswd) ;;
+
+ 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=`printf "%s\n" "$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=`printf "%s\n" "$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)"
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: $ac_msg" >&5
+ printf "%s\n" "$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=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`printf "%s\n" "$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 configure.gnu first; this name is used for a wrapper for
+ # Metaconfig's "Configure" on case-insensitive file systems.
+ 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
+ else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: no configuration information is in $ac_dir" >&5
+printf "%s\n" "$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
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&5
+printf "%s\n" "$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
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
+
+
+module_list=$(find src/modules/ -type d -name 'rlm_*' -print | sort)
+
+echo
+echo Module configure status report
+echo ------------------------------
+
+for module in $module_list; do
+ module_name="$(basename $module)"
+ module_print="$(echo "$module_name ........................" | cut -c 1-25)"
+ module_status="OK"
+
+ if test -r $module/configure.ac; then
+ if test -r $module/config.report; then
+ module_status=$(cat $module/config.report)
+ fi
+ fi
+
+ $as_echo "$module_print $module_status"
+done
+
+
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..a24a806
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,2645 @@
+dnl #############################################################
+dnl #
+dnl # For information about autoconf, see:
+dnl #
+dnl # http://www.gnu.org/software/autoconf/
+dnl #
+dnl # The recommended order is:
+dnl #
+dnl # AC_INIT
+dnl # 0. checks for compiler, libtool, and command line options
+dnl # 1. checks for programs
+dnl # 2. checks for libraries
+dnl # 3. checks for header files
+dnl # 4. checks for typedefs
+dnl # 5. checks for structures and functions
+dnl # 6. checks for compiler characteristics
+dnl # 7. checks for library functions
+dnl # 8. checks for system services
+dnl # AC_OUTPUT
+dnl #
+dnl #############################################################
+
+AC_PREREQ([2.69])
+export CFLAGS LIBS LDFLAGS CPPFLAGS
+
+AC_INIT([freeradius],[$Id$],[http://bugs.freeradius.org],[],[http://www.freeradius.org])
+AC_CONFIG_MACRO_DIR([m4])
+AC_CONFIG_SRCDIR([src/main/radiusd.c])
+AC_CONFIG_HEADER([src/include/autoconf.h])
+
+dnl #############################################################
+dnl #
+dnl # Custom hackery to discover version at configure time
+dnl #
+dnl #############################################################
+RADIUSD_MAJOR_VERSION=`cat VERSION | cut -f1 -d.`
+RADIUSD_MINOR_VERSION=`cat VERSION | cut -f2 -d.`
+RADIUSD_INCRM_VERSION=`cat VERSION | cut -f3 -d. | sed 's/[[\.-]].*$//'`
+
+RADIUSD_VERSION=`printf "%02i%02i%02i" $RADIUSD_MAJOR_VERSION $RADIUSD_MINOR_VERSION $RADIUSD_INCRM_VERSION`
+
+dnl #
+dnl # Still useful for custom builds
+dnl #
+RADIUSD_VERSION_STRING=`cat VERSION`
+
+dnl #
+dnl # Add definitions to Make.inc as it's used by various build targets
+dnl #
+AC_SUBST([RADIUSD_VERSION_STRING])
+
+dnl #
+dnl # Add definitions to autoconf.h, so that the headers that we install
+dnl # contain the version number of the server.
+dnl #
+AC_DEFINE_UNQUOTED([RADIUSD_VERSION], [${RADIUSD_VERSION}], [Version integer in format <ma><ma><mi><mi><in><in>])
+AC_DEFINE_UNQUOTED([RADIUSD_VERSION_STRING], ["${RADIUSD_VERSION_STRING}"], [Raw version string from VERSION file])
+
+dnl #############################################################
+dnl #
+dnl # Override some of the default autoconf variables such as
+dnl # CFLAGS if were building in developer mode
+dnl #
+dnl #############################################################
+
+dnl #
+dnl # Unset ASAN_OPTIONS and LSAN_OPTIONS so they don't interfere
+dnl # with the build process.
+dnl #
+unset ASAN_OPTIONS
+unset LSAN_OPTIONS
+
+dnl #
+dnl # check for JSON.pm, ASCIIDOCTOR and pandoc
+dnl #
+AC_PATH_PROG(ASCIIDOCTOR, asciidoctor)
+if test "x$ac_cv_path_ASCIIDOCTOR" = "x"; then
+ AC_MSG_WARN([asciidoctor not found - Please install if you want build the docs])
+fi
+
+AC_PATH_PROG(PANDOC, pandoc)
+if test "x$ac_cv_path_PANDOC" = "x"; then
+ AC_MSG_WARN([pandoc not found - Please install if you want build the docs])
+else
+ #
+ # Pandoc v2 onwards renamed --latex-engine to --pdf-engine
+ #
+ if pandoc --help 2>&1 | grep -q "latex-engine"; then
+ PANDOC_ENGINE=latex
+ else
+ PANDOC_ENGINE=pdf
+ fi
+ AC_SUBST(PANDOC_ENGINE)
+fi
+
+# pandoc and asciidoctor is defined? then check it.
+if test "x$ac_cv_path_PANDOC" != "x" && test "x$ac_cv_path_ASCIIDOCTOR" != "x"; then
+ AX_PROG_PERL_MODULES(JSON, , AC_MSG_WARN([Perl JSON module not found - Please install if you want build the docs]))
+fi
+
+dnl #
+dnl # check for doxygen
+dnl #
+AC_PATH_PROG(DOXYGEN, doxygen)
+if test "x$ac_cv_path_DOXYGEN" != "x"; then
+ AC_PATH_PROG(GRAPHVIZ_DOT, dot)
+ if test "x$ac_cv_path_GRAPHVIZ_DOT" = "x"; then
+ AC_MSG_WARN([dot not found - Please install the graphviz if you want to build the docs/source])
+ fi
+else
+ AC_MSG_WARN([doxygen not found - Please install if you want build the docs/source])
+fi
+
+dnl #
+dnl # check for Antora
+dnl #
+AC_PATH_PROG(ANTORA, antora)
+if test "x$ac_cv_path_ANTORA" = "x"; then
+ AC_MSG_WARN([antora not found - Please install if you want build the site])
+fi
+
+dnl #
+dnl # Enable developer features like debugging symbols.
+dnl # These checks must be done before expanding the AC_PROG_CC
+dnl # and AC_PROG_CXX macros.
+dnl #
+AC_ARG_ENABLE(developer,
+[ --enable-developer enables features of interest to developers.],
+[ case "$enableval" in
+ no)
+ developer=no
+ ;;
+ *)
+ developer=yes
+ esac ]
+)
+
+dnl #
+dnl # Turn on the developer flag when taken from a git checkout (not a release)
+dnl #
+if test -d $srcdir/.git; then
+ if test "x$developer" != "xno"; then
+ AC_MSG_NOTICE([found .git directory, enabling developer build implicitly, disable with --disable-developer])
+ developer="yes"
+ fi
+fi
+
+dnl #
+dnl # Autoconf sets -O2 and -g by default, but this is a PITA for debugging
+dnl # so we remove the defaults if were building in developer mode, and set
+dnl # -g3 so nice things like macro values are included. Other arguments are
+dnl # added later when we know what compiler were using.
+dnl #
+if test "x$developer" = "xyes"; then
+ : ${CFLAGS=-g3}
+fi
+
+dnl #
+dnl # The developer option WITH_VERIFY_PTR significantly scews profiling so
+dnl # we allow it to be disabled.
+dnl #
+AC_ARG_ENABLE(verify-ptr,
+[ --disable-verify-ptr disables WITH_VERIFY_PTR developer build option.],
+[ case "$enableval" in
+ no)
+ verify_ptr=""
+ ;;
+ *)
+ verify_ptr="-DWITH_VERIFY_PTR=1"
+ esac ],
+[ verify_ptr="-DWITH_VERIFY_PTR=1" ],
+)
+
+dnl #
+dnl # Hard-code FIPS support/
+dnl #
+AC_ARG_ENABLE(fips-workaround,
+[ --enable-fips-workaround enables local MD4, MD5, etc. functionality to avoid OpenSSL FIPS issues.],
+[ case "$enableval" in
+ no)
+ fips=""
+ ;;
+ *)
+ fips="-DWITH_FIPS=1"
+ esac ],
+[ fips="" ],
+)
+
+dnl #############################################################
+dnl #
+dnl # 0. Checks for compiler, libtool, and command line options.
+dnl #
+dnl #############################################################
+
+dnl #
+dnl # Get system information
+dnl #
+AC_CANONICAL_TARGET
+
+dnl #
+dnl # clang etc. on OSX no longer searches the default paths for things,
+dnl # so we have to add them back in.
+dnl #
+case "$host" in
+ *-darwin*)
+ CFLAGS="$CFLAGS -DDARWIN"
+ LDFLAGS="-L/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib $LDFLAGS"
+ LIBS="-F /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/ -framework DirectoryService $LIBS"
+ ;;
+esac
+
+
+dnl #
+dnl # Check for GNU cc
+dnl #
+AC_PROG_CC
+AC_PROG_CXX
+
+dnl #
+dnl # check for AIX, to allow us to use some BSD functions
+dnl # must be before macros that call the compiler.
+dnl #
+AC_USE_SYSTEM_EXTENSIONS
+
+AC_PROG_GCC_TRADITIONAL
+AC_PROG_CC_SUNPRO
+AC_PROG_RANLIB
+
+dnl #
+dnl # Definitive check for whether the compiler is clang
+dnl #
+AX_CC_IS_CLANG
+if test "x$ax_cv_cc_clang" = "xyes"; then
+ AC_SUBST(clang_path, "$CC")
+else
+ AC_SUBST(clang_path, "")
+fi
+
+
+dnl #
+dnl # Set Default CFLAGS for GCC compatible compilers
+dnl #
+if test "x$GCC" = "xyes"; then
+ CFLAGS="$CFLAGS -Wall -std=c99 -D_GNU_SOURCE"
+fi
+
+dnl #
+dnl # -Wno-unknown-warning-option means the compiler doesn't complain about diag pragmas
+dnl # for warnings it doesn't understand. This may sound like a bad idea, but consider
+dnl # the number of different compiler versions we build under, and the fact that the
+dnl # more anally retentive warnings are likely to be added in later versions.
+dnl #
+AX_CC_NO_UNKNOWN_WARNING_OPTION_FLAG
+if test "x$ax_cv_cc_no_unknown_warning_option_flag" = "xyes"; then
+ CFLAGS="$CFLAGS -Wno-unknown-warning-option"
+fi
+
+dnl #
+dnl # -Qunused-arguments means the compiler won't complain about unsupported arguments
+dnl #
+AX_CC_QUNUSED_ARGUMENTS_FLAG
+if test "x$ax_cv_cc_qunused_arguments_flag" = "xyes"; then
+ CFLAGS="$CFLAGS -Qunused-arguments"
+ LDFLAGS="$LDFLAGS -Qunused-arguments"
+fi
+
+dnl #
+dnl # Check for presence of -Wno-date-time warning. Older compilers
+dnl # don't have it, and newer compilers warn without it...
+dnl #
+AX_CC_NO_DATE_TIME_FLAG
+
+dnl #
+dnl # Compile in large (2G+) file support.
+dnl #
+AC_SYS_LARGEFILE
+
+dnl #
+dnl # check for system bytesex
+dnl # AC_DEFINES WORDS_BIGENDIAN
+dnl #
+AC_C_BIGENDIAN(
+ [AC_DEFINE(FR_BIG_ENDIAN, 1, [Define if your processor stores words with the most significant byte first])],
+ [AC_DEFINE(FR_LITTLE_ENDIAN, 1, [Define if your processor stores words with the least significant byte first])]
+)
+
+dnl #
+dnl # Find GNU Make.
+dnl #
+AC_CHECK_PROG(GMAKE, gmake, yes, no)
+if test $GMAKE = no; then
+ AC_PATH_PROG(MAKE, make, /usr/local/bin/make)
+else
+ AC_PATH_PROG(MAKE, gmake, /usr/local/gnu/bin/make)
+fi
+makever=`$ac_cv_path_MAKE --version 2>&1 | grep "GNU Make"`
+if test -z "$makever"; then
+ AC_MSG_ERROR([GNU Make is not installed. Please download and install it from ftp://prep.ai.mit.edu/pub/gnu/make/ before continuing.])
+fi
+
+dnl #
+dnl # autoconf explicitly sets MAKEFLAGS and MFLAGS to '' even though we
+dnl # didn't tell it to, so we have to use FR_MAKEFLAGS.
+dnl #
+dnl # determine the number of cores available and set the number of build
+dnl # processes appropriately.
+dnl #
+AX_SYSTEM_CORES
+
+dnl # Temporarily disabled because test and installation targets do not
+dnl # have dependencies set up correctly for multiple build processes.
+dnl if test "x$ax_cv_system_cores" != "x"; then
+dnl : ${FR_MAKEFLAGS=-j$ax_cv_system_cores}
+dnl fi
+AC_SUBST(FR_MAKEFLAGS)
+
+dnl #
+dnl # See if we have Git.
+dnl #
+AC_CHECK_PROG(GIT, git, yes, no)
+
+dnl Put this in later, when all distributed modules use autoconf.
+dnl AC_ARG_WITH(disablemodulefoo,
+dnl [ --without-rlm_foo Disables module compilation. Module list:]
+dnl esyscmd([find src/modules -type d -name rlm_\* -print |\
+dnl sed -e 's%src/modules/.*/% (sub)- %; s%.*/%- %' |\
+dnl awk '{print " "$0}']))
+
+AC_ARG_ENABLE(strict-dependencies,
+[ --enable-strict-dependencies fail configure on lack of module dependancy.])
+
+AC_ARG_ENABLE(werror,
+[ --enable-werror causes the build to fail if any warnings are generated.],
+[ case "$enableval" in
+ no)
+ werror=no
+ ;;
+ *)
+ werror=yes
+ esac ]
+)
+
+dnl #
+dnl # extra argument: --with-docdir
+dnl #
+docdir='${datadir}/doc/freeradius'
+AC_MSG_CHECKING([docdir])
+AC_ARG_WITH(docdir,
+[ --with-docdir=DIR directory for documentation [DATADIR/doc/freeradius] ],
+[ case "$withval" in
+ no)
+ docdir=no
+ ;;
+ yes)
+ ;;
+ [[\\/$]]* | ?:[[\\/]]* )
+ docdir="$withval"
+ ;;
+ *)
+ AC_MSG_ERROR([expected an absolute directory name for --with-docdir: $withval])
+ ;;
+ esac ]
+)
+AC_SUBST(docdir)
+AC_MSG_RESULT($docdir)
+if test "x$docdir" = xno; then
+ AC_MSG_WARN([Documentation files will NOT be installed.])
+fi
+
+dnl #
+dnl # extra argument: --with-logdir
+dnl #
+logdir='${localstatedir}/log/radius'
+AC_MSG_CHECKING(logdir)
+AC_ARG_WITH(logdir,
+[ --with-logdir=DIR directory for logfiles [LOCALSTATEDIR/log/radius] ],
+[ case "$withval" in
+ no)
+ AC_MSG_ERROR([Need logdir])
+ ;;
+ yes)
+ ;;
+ [[\\/$]]* | ?:[[\\/]]* )
+ logdir="$withval"
+ ;;
+ *)
+ AC_MSG_ERROR([expected an absolute directory name for --with-logdir: $withval])
+ ;;
+ esac ]
+)
+AC_SUBST(logdir)
+AC_MSG_RESULT($logdir)
+
+dnl #
+dnl # extra argument: --with-radacctdir
+dnl #
+radacctdir='${logdir}/radacct'
+AC_MSG_CHECKING(radacctdir)
+AC_ARG_WITH(radacctdir,
+[ --with-radacctdir=DIR directory for detail files [LOGDIR/radacct] ],
+[ case "$withval" in
+ no)
+ AC_MSG_ERROR([Need radacctdir])
+ ;;
+ yes)
+ ;;
+ [[\\/$]]* | ?:[[\\/]]* )
+ radacctdir="$withval"
+ ;;
+ *)
+ AC_MSG_ERROR([expected an absolute directory name for --with-radacctdir: $withval])
+ ;;
+ esac ]
+)
+AC_SUBST(radacctdir)
+AC_MSG_RESULT($radacctdir)
+
+dnl #
+dnl # extra argument: --with-raddbdir
+dnl #
+raddbdir='${sysconfdir}/raddb'
+AC_MSG_CHECKING(raddbdir)
+AC_ARG_WITH(raddbdir,
+[ --with-raddbdir=DIR directory for config files [SYSCONFDIR/raddb] ],
+[ case "$withval" in
+ no)
+ AC_MSG_ERROR([Need raddbdir])
+ ;;
+ yes)
+ ;;
+ [[\\/$]]* | ?:[[\\/]]* )
+ raddbdir="$withval"
+ ;;
+ *)
+ AC_MSG_ERROR([expected an absolute directory name for --with-raddbdir: $withval])
+ ;;
+ esac ]
+)
+AC_SUBST(raddbdir)
+AC_MSG_RESULT($raddbdir)
+
+dnl #
+dnl # extra argument: --with-dictdir
+dnl #
+dictdir='${datarootdir}/freeradius'
+AC_MSG_CHECKING(dictdir)
+AC_ARG_WITH(dictdir,
+[ --with-dictdir=DIR directory for dictionary files [DATAROOTDIR/freeradius] ],
+[ case "$withval" in
+ no)
+ AC_MSG_ERROR([Need dictdir])
+ ;;
+ yes)
+ ;;
+ [[\\/$]]* | ?:[[\\/]]* )
+ dictdir="$withval"
+ ;;
+ *)
+ AC_MSG_ERROR([expected an absolute directory name for --with-dictdir: $withval])
+ ;;
+ esac ]
+)
+AC_SUBST(dictdir)
+AC_MSG_RESULT($dictdir)
+
+modconfdir='${raddbdir}/mods-config'
+AC_SUBST(modconfdir)
+
+dnl #
+dnl # extra argument: --with-ascend-binary
+dnl #
+WITH_ASCEND_BINARY=yes
+AC_ARG_WITH(ascend-binary,
+[ --with-ascend-binary include support for Ascend binary filter attributes (default=yes)],
+[ case "$withval" in
+ yes)
+ ;;
+ *)
+ WITH_ASCEND_BINARY=no
+ esac ]
+)
+if test "x$WITH_ASCEND_BINARY" = "xyes"; then
+ AC_DEFINE(WITH_ASCEND_BINARY, [1], [include support for Ascend binary filter attributes])
+fi
+
+dnl #
+dnl # extra argument: --with-radiusv11
+dnl #
+WITH_RADIUSV11=
+AC_ARG_WITH(radiusv11,
+[ --with-radiusv11 compile in RADIUSv11 support. (default=no)],
+[ case "$withval" in
+ yes)
+ WITH_RADIUSV11=yes
+ ;;
+ *)
+ ;;
+ esac ]
+)
+if test "x$WITH_RADIUSCV11" = "xyes"; then
+ AC_DEFINE(WITH_RADIUSV11, [1], [define if you want RADIUSv11 support (For RADSec et al)])
+fi
+
+dnl #
+dnl # extra argument: --with-threads
+dnl #
+WITH_THREADS=yes
+AC_ARG_WITH(threads,
+[ --with-threads use threads, if available. (default=yes) ],
+[ case "$withval" in
+ yes)
+ ;;
+ *)
+ WITH_THREADS=no
+ esac ]
+)
+
+dnl #
+dnl # extra argument: --with-tcp
+dnl #
+WITH_TCP=yes
+AC_ARG_WITH(tcp,
+[ --with-tcp compile in TCP support. (default=yes)],
+[ case "$withval" in
+ yes)
+ ;;
+ *)
+ WITH_TCP=no
+ esac ]
+)
+if test "x$WITH_TCP" = "xyes"; then
+ AC_DEFINE(WITH_TCP, [1], [define if you want TCP support (For RADSec et al)])
+fi
+
+dnl #
+dnl # extra argument: --with-vmps
+dnl #
+WITH_VMPS=yes
+AC_ARG_WITH(vmps,
+[ --with-vmps compile in VMPS support. (default=yes)],
+[ case "$withval" in
+ yes)
+ ;;
+ *)
+ WITH_VMPS=no
+ esac ]
+)
+if test "x$WITH_VMPS" = "xyes"; then
+ AC_DEFINE(WITH_VMPS, [1], [define if you want VMPS support])
+fi
+
+dnl #
+dnl # extra argument: --with-dhcp
+dnl #
+WITH_DHCP=yes
+AC_ARG_WITH(dhcp,
+[ --with-dhcp compile in DHCP support. (default=yes)],
+[ case "$withval" in
+ yes)
+ ;;
+ *)
+ WITH_DHCP=no
+ esac ]
+)
+if test "x$WITH_DHCP" = "xyes"; then
+ AC_DEFINE(WITH_DHCP, [1], [define if you want DHCP support])
+fi
+AC_SUBST(WITH_DHCP)
+
+dnl #
+dnl # Allow the user to specify a list of modules to be linked
+dnl # statically to the server.
+dnl #
+STATIC_MODULES=
+AC_ARG_WITH(static_modules,
+[ --with-static-modules=QUOTED-MODULE-LIST],[
+ for i in $withval; do
+ STATIC_MODULES="$STATIC_MODULES -dlpreopen ../modules/rlm_$i/rlm_$i.la"
+ done
+])
+
+USE_SHARED_LIBS=yes
+AC_ARG_WITH(shared-libs,
+[AS_HELP_STRING([--with-shared-libs ],
+[build dynamic libraries and link against them. (default=yes)])],
+[ case "$withval" in
+ no)
+ USE_SHARED_LIBS=no
+ ;;
+ *)
+ esac
+])
+
+MODULES=
+AC_ARG_WITH(modules,
+[ --with-modules=QUOTED-MODULE-LIST],[
+ for i in $withval; do
+ MODULES="$MODULES $i"
+ done
+])
+
+dnl #
+dnl # extra argument: --with-experimental-modules
+dnl #
+EXPERIMENTAL=
+AC_ARG_WITH(experimental-modules,
+[AS_HELP_STRING([--with-experimental-modules],
+[use experimental and unstable modules. (default=no, unless --enable-developer=yes)])],
+[ case "$withval" in
+ yes)
+ EXPERIMENTAL=yes
+ ;;
+ no)
+ EXPERIMENTAL=no
+ ;;
+ *)
+ esac ]
+)
+
+dnl #
+dnl # extra argument: --with-udpfromto
+dnl #
+WITH_UDPFROMTO=yes
+AC_ARG_WITH(udpfromto,
+[ --with-udpfromto compile in UDPFROMTO support. (default=yes)],
+[ case "$withval" in
+ yes)
+ WITH_UDPFROMTO=yes
+ ;;
+ *)
+ WITH_UDPFROMTO=no
+ esac ]
+)
+
+if test "x$WITH_UDPFROMTO" = "xyes"; then
+ AC_DEFINE(WITH_UDPFROMTO, [], [define if you want udpfromto])
+fi
+
+dnl #
+dnl # These next two arguments don't actually do anything. They're
+dnl # place holders so that the top-level configure script can tell
+dnl # the user how to configure lower-level modules
+dnl #
+
+dnl #
+dnl # extra argument: --with-rlm-FOO-lib-dir
+dnl #
+AC_ARG_WITH(rlm-FOO-lib-dir,
+[AS_HELP_STRING([--with-rlm-FOO-lib-dir=DIR],
+[directory in which to look for library files used by module FOO])],
+[ case "$withval" in
+ *)
+ ;;
+ esac ]
+)
+
+dnl #
+dnl # extra argument: --with-rlm-FOO-include-dir
+dnl #
+AC_ARG_WITH(rlm-FOO-include-dir,
+[AS_HELP_STRING([--with-rlm-FOO-include-dir=DIR],
+[directory in which to look for include files used by module FOO])],
+[ case "$withval" in
+ *)
+ ;;
+ esac ]
+)
+
+dnl #
+dnl # extra argument: --with-openssl
+dnl #
+WITH_OPENSSL=yes
+AC_ARG_WITH(openssl,
+[ --with-openssl use OpenSSL. (default=yes)],
+[ case "$withval" in
+ no)
+ WITH_OPENSSL=no
+ ;;
+ *)
+ WITH_OPENSSL=yes
+ ;;
+ esac ]
+)
+if test "x$WITH_THREADS" = "xno"; then
+ if test "x$WITH_OPENSSL" = "xyes"; then
+ AC_MSG_ERROR([[Threads are required when using OpenSSL, use --with-threads=yes]])
+ fi
+fi
+
+dnl #
+dnl # extra argument: --with-openssl-lib-dir=dir
+dnl #
+openssl_lib_dir=
+AC_ARG_WITH(openssl-lib-dir,
+[AS_HELP_STRING([--with-openssl-lib-dir=DIR],
+[directory to look for OpenSSL library files])],
+[ case "$withval" in
+ *) openssl_lib_dir="$withval"
+ ;;
+ esac ]
+)
+
+dnl #
+dnl # extra argument: --with-openssl-includes=dir
+dnl #
+openssl_include_dir=
+AC_ARG_WITH(openssl-include-dir,
+[AS_HELP_STRING([--with-openssl-include-dir=DIR],
+[directory to look for OpenSSL include files])],
+[ case "$withval" in
+ *) openssl_include_dir="$withval"
+ ;;
+ esac ]
+)
+
+dnl #
+dnl # extra argument: --disable-openssl-version-check
+dnl #
+AC_ARG_ENABLE(openssl-version-check,
+[AS_HELP_STRING([--disable-openssl-version-check],
+ [disable vulnerable OpenSSL version check])]
+)
+if test "x$enable_openssl_version_check" != "xno"; then
+ AC_DEFINE(ENABLE_OPENSSL_VERSION_CHECK, [1],
+ [Define to 1 to have OpenSSL version check enabled])
+ openssl_version_check_config="\
+ #
+ # allow_vulnerable_openssl: Allow the server to start with
+ # versions of OpenSSL known to have critical vulnerabilities.
+ #
+ # This check is based on the version number reported by libssl
+ # and may not reflect patches applied to libssl by
+ # distribution maintainers.
+ #
+ allow_vulnerable_openssl = no"
+else
+ openssl_version_check_config=
+fi
+AC_SUBST([openssl_version_check_config])
+
+dnl #
+dnl # extra argument: --enable-reproducible-builds
+dnl #
+AC_ARG_ENABLE(reproducible-builds,
+[AS_HELP_STRING([--enable-reproducible-builds],
+ [ensure the build does not change each time])],
+[ case "$enableval" in
+ yes)
+ AC_DEFINE(ENABLE_REPRODUCIBLE_BUILDS, [1],
+ [Define to ensure each build is the same])
+ reproducible_builds=yes
+ ;;
+ *)
+ reproducible_builds=no
+ esac ]
+)
+
+dnl #
+dnl # Enable the -fsanitize=fuzzer and link in the address sanitizer
+dnl # libraries.
+dnl #
+AC_ARG_ENABLE(fuzzer,
+[AS_HELP_STRING([--enable-fuzzer],
+ [build with support for a fuzzer])],
+[ case "$enableval" in
+ no)
+ fuzzer=no
+ ;;
+ *)
+ fuzzer=yes
+ esac ]
+)
+
+dnl #
+dnl # Enable the -fsanitize=address and link in the address sanitizer
+dnl # libraries.
+dnl #
+AC_ARG_ENABLE(address-sanitizer,
+[AS_HELP_STRING([--enable-address-sanitizer],
+ [build with support for address sanitizer.])],
+[ case "$enableval" in
+ no)
+ address_sanitizer=no
+ ;;
+ *)
+ address_sanitizer=yes
+ esac ]
+)
+
+dnl #
+dnl # Enable -fsanitize=leak and link in the leak sanitizer
+dnl # libraries.
+dnl #
+AC_ARG_ENABLE(leak-sanitizer,
+[AS_HELP_STRING([--enable-leak-sanitizer],
+ [build with support for leak sanitizer.])],
+[ case "$enableval" in
+ no)
+ leak_sanitizer=no
+ ;;
+ *)
+ leak_sanitizer=yes
+ esac ]
+)
+
+dnl #
+dnl # Enable -fsanitize=thread and link in the thread sanitizer
+dnl # libraries.
+dnl #
+AC_ARG_ENABLE(thread-sanitizer,
+[AS_HELP_STRING([--enable-thread-sanitizer],
+ [build with support for thread sanitizer.])],
+[ case "$enableval" in
+ no)
+ thread_sanitizer=no
+ ;;
+ *)
+ thread_sanitizer=yes
+ esac ]
+)
+
+dnl #
+dnl # Enable the -fsanitize=undefined and link in the address sanitizer
+dnl # libraries.
+dnl #
+AC_ARG_ENABLE(undefined-behaviour-sanitizer,
+[AS_HELP_STRING([--enable-undefined-behaviour-sanitizer],
+ [build with support for undefined behaviour sanitizer.])],
+[ case "$enableval" in
+ no)
+ undefined_behaviour_sanitizer=no
+ ;;
+ *)
+ undefined_behaviour_sanitizer=yes
+ esac ]
+)
+
+dnl #############################################################
+dnl #
+dnl # 1. Checks for programs
+dnl #
+dnl #############################################################
+
+CHECKRAD=checkrad
+AC_PATH_PROG(PERL, perl, /usr/local/bin/perl)
+if test "x$ac_cv_path_PERL" = "x"; then
+ AC_MSG_WARN([perl not found - Simultaneous-Use and checkrad may not work])
+fi
+AC_PATH_PROG(SNMPGET, snmpget)
+if test "x$ac_cv_path_SNMPGET" = "x"; then
+ AC_MSG_WARN([snmpget not found - Simultaneous-Use and checkrad may not work])
+fi
+
+AC_PATH_PROG(SNMPWALK, snmpwalk)
+if test "x$ac_cv_path_SNMPWALK" = "x"; then
+ AC_MSG_WARN([snmpwalk not found - Simultaneous-Use and checkrad may not work])
+fi
+
+AC_PATH_PROG(RUSERS, rusers, /usr/bin/rusers)
+
+dnl #
+dnl # FIXME This is truly gross.
+dnl #
+missing_dir=`cd $ac_aux_dir && pwd`
+AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir)
+AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir)
+AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir)
+
+AC_PATH_PROG(DIRNAME,dirname)
+AC_PATH_PROG(GREP,grep)
+
+dnl #############################################################
+dnl #
+dnl # 2. Checks for libraries
+dnl #
+dnl #############################################################
+
+dnl Check for talloc
+dnl extra argument: --with-talloc-lib-dir=DIR
+talloc_lib_dir=
+AC_ARG_WITH(talloc-lib-dir,
+ [AS_HELP_STRING([--with-talloc-lib-dir=DIR],
+ [directory in which to look for talloc library files])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR([Need talloc-lib-dir])
+ ;;
+ yes)
+ ;;
+ *)
+ talloc_lib_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-talloc-include-dir=DIR
+talloc_include_dir=
+AC_ARG_WITH(talloc-include-dir,
+ [AS_HELP_STRING([--with-talloc-include-dir=DIR],
+ [directory in which to look for talloc include files])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR([Need talloc-include-dir])
+ ;;
+ yes)
+ ;;
+ *)
+ talloc_include_dir="$withval"
+ ;;
+ esac])
+
+smart_try_dir="$talloc_lib_dir"
+FR_SMART_CHECK_LIB(talloc, _talloc)
+if test "x$ac_cv_lib_talloc__talloc" != "xyes"; then
+ AC_MSG_WARN([talloc library not found. Use --with-talloc-lib-dir=<path>.])
+ AC_MSG_ERROR([FreeRADIUS requires libtalloc])
+fi
+
+TALLOC_LIBS="${smart_lib}"
+TALLOC_LDFLAGS="${smart_ldflags}"
+AC_SUBST(TALLOC_LIBS)
+AC_SUBST(TALLOC_LDFLAGS)
+LIBS="$old_LIBS"
+
+dnl #
+dnl # If using pthreads, check for -lpthread (posix) or -lc_r (*BSD)
+dnl #
+old_CFLAGS=$CFLAGS
+if test "x$WITH_THREADS" = "xyes"; then
+ if test $ac_cv_prog_suncc = "yes"; then
+ CFLAGS="$CFLAGS -mt"
+ fi
+
+ AC_CHECK_HEADERS(pthread.h, [],
+ [
+ WITH_THREADS="no"
+ fail=[pthread.h]
+ ])
+
+ dnl #
+ dnl # pthread stuff is usually in -lpthread
+ dnl # or in -lc_r, on *BSD
+ dnl #
+ dnl # On Some systems, we need extra pre-processor flags, to get them to
+ dnl # to do the threading properly.
+ dnl #
+ if test "x$WITH_THREADS" != "xno"; then
+ AC_CHECK_LIB(pthread, pthread_create,
+ [
+ HAVE_LPTHREAD='yes'
+ CFLAGS="$CFLAGS -D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS"
+ LIBS="-lpthread $LIBS"
+
+ dnl #
+ dnl # -pthread should add all required CPP definitions and linker
+ dnl # arguments. But not all compilers support it, or some compilers
+ dnl # only support it on certain platforms.
+ dnl #
+ AX_CC_PTHREAD_FLAG
+ if test "x$ax_cv_cc_pthread_flag" != 'xyes'; then
+ CFLAGS="$CFLAGS -pthread"
+ fi
+ ]
+ )
+
+ dnl #
+ dnl # Check for libc_r which used to be the threading library used
+ dnl # for FreeBSD. Internet says it may be deprecated, but if we
+ dnl # can't find lpthread it's probably worth checking.
+ dnl #
+ if test "x$HAVE_LPTHREAD" != "xyes"; then
+ AC_CHECK_LIB(c_r, pthread_create,
+ [
+ CFLAGS="$CFLAGS -D_THREAD_SAFE"
+
+ dnl #
+ dnl # -pthread should add all required CPP definitions and linker
+ dnl # arguments. But not all compilers support it, or some compilers
+ dnl # only support it on certain platforms.
+ dnl #
+ AX_CC_PTHREAD_FLAG
+ if test "x$ax_cv_cc_pthread_flag" != 'xyes'; then
+ LIBS="-lc_r $LIBS"
+ else
+ CFLAGS="$CFLAGS -pthread"
+ fi
+ ],
+ [ fail=[-lc_r or -lpthread] ]
+ )
+ fi
+ fi
+
+ if test "x$WITH_THREADS" != "xyes"; then
+ AC_MSG_WARN([silently not building with thread support.])
+ AC_MSG_WARN([FAILURE: thread support requires: $fail.])
+ else
+ AC_DEFINE(WITH_THREADS, [1], [define if you want thread support])
+ fi
+fi
+
+dnl #
+dnl # If we have NO pthread libraries, remove any knowledge of threads.
+dnl #
+if test "x$WITH_THREADS" != "xyes"; then
+ CFLAGS=$old_CFLAGS
+ ac_cv_header_pthread_h="no"
+ WITH_THREADS=no
+else
+ dnl #
+ dnl # We need sem_init() and friends, as they're the friendliest
+ dnl # semaphore functions for threading.
+ dnl #
+ dnl # HP/UX requires linking with librt, too, to get the sem_* symbols.
+ dnl # Some systems have them in -lsem
+ dnl # Solaris has them in -lposix4
+ dnl # NetBSD has them in -lsemaphore
+ dnl #
+
+ AC_SEARCH_LIBS(sem_init, pthread sem posix4 rt semaphore,
+ [],
+ [AC_MSG_ERROR([[-lsem not found. You may want to download it from ftp://ftp.to.gd-es.com/pub/BSDI/libsem.tar.bz2 or ftp://ftp.freeradius.org/pub/radius/contrib/libsem.tar.gz]])]
+ )
+fi
+
+dnl #
+dnl # Check if we have -ldl
+dnl #
+AC_CHECK_LIB(dl, dlopen)
+
+dnl #
+dnl # Check if we need -lsocket
+dnl #
+AC_CHECK_LIB(socket, getsockname)
+
+dnl #
+dnl # Check for -lresolv
+dnl # This library may be needed later.
+dnl #
+AC_CHECK_LIB(resolv, inet_aton)
+
+dnl #
+dnl # Check if we need -lnsl. Usually if we want to
+dnl # link against -lsocket we need to include -lnsl as well.
+dnl #
+AC_CHECK_LIB(nsl, inet_ntoa)
+AC_CHECK_LIB(ws2_32, htonl)
+
+dnl #
+dnl # Check the pcap library for the RADIUS sniffer.
+dnl #
+dnl extra argument: --with-pcap-lib-dir=DIR
+pcap_lib_dir=
+AC_ARG_WITH(pcap-lib-dir,
+ [AS_HELP_STRING([--with-pcap-lib-dir=DIR],
+ [directory in which to look for pcap library files])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR([Need pcap-lib-dir])
+ ;;
+ yes)
+ ;;
+ *)
+ pcap_lib_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-pcap-include-dir=DIR
+pcap_include_dir=
+AC_ARG_WITH(pcap-include-dir,
+ [AS_HELP_STRING([--with-pcap-include-dir=DIR],
+ [directory in which to look for pcap include files])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR([Need pcap-include-dir])
+ ;;
+ yes)
+ ;;
+ *)
+ pcap_include_dir="$withval"
+ ;;
+ esac])
+
+smart_try_dir="$pcap_lib_dir"
+FR_SMART_CHECK_LIB(pcap, pcap_open_live)
+if test "x$ac_cv_lib_pcap_pcap_open_live" != "xyes"; then
+ AC_MSG_WARN([pcap library not found, silently disabling the RADIUS sniffer, and ARP listener. Use --with-pcap-lib-dir=<path>.])
+else
+ AC_CHECK_FUNCS(\
+ pcap_fopen_offline \
+ pcap_dump_fopen \
+ pcap_create \
+ pcap_activate
+ )
+
+ PCAP_LIBS="${smart_lib}"
+ PCAP_LDFLAGS="${smart_ldflags}"
+fi
+dnl Set by FR_SMART_CHECK_LIB
+LIBS="${old_LIBS}"
+
+dnl Check for collectdclient
+dnl extra argument: --with-collectdclient-lib-dir=DIR
+collectdclient_lib_dir=
+AC_ARG_WITH(collectdclient-lib-dir,
+ [AS_HELP_STRING([--with-collectdclient-lib-dir=DIR],
+ [directory in which to look for collectdclient library files])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR([Need collectdclient-lib-dir])
+ ;;
+ yes)
+ ;;
+ *)
+ collectdclient_lib_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-collectdclient-include-dir=DIR
+collectdclient_include_dir=
+AC_ARG_WITH(collectdclient-include-dir,
+ [AS_HELP_STRING([--with-collectdclient-include-dir=DIR],
+ [directory in which to look for collectdclient include files])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR([Need collectdclient-include-dir])
+ ;;
+ yes)
+ ;;
+ *)
+ collectdclient_include_dir="$withval"
+ ;;
+ esac])
+
+smart_try_dir="$collectdclient_lib_dir"
+FR_SMART_CHECK_LIB(collectdclient, lcc_connect)
+if test "x$ac_cv_lib_collectdclient_lcc_connect" != "xyes"; then
+ AC_MSG_WARN([collectdclient library not found. Use --with-collectdclient-lib-dir=<path>.])
+else
+ COLLECTDC_LIBS="${smart_lib}"
+ COLLECTDC_LDFLAGS="${smart_ldflags}"
+fi
+dnl Set by FR_SMART_CHECKLIB
+LIBS="${old_LIBS}"
+
+dnl Check for cap
+dnl extra argument: --with-cap-lib-dir=DIR
+cap_lib_dir=
+AC_ARG_WITH(cap-lib-dir,
+ [AS_HELP_STRING([--with-cap-lib-dir=DIR],
+ [directory in which to look for cap library files])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR([Need cap-lib-dir])
+ ;;
+ yes)
+ ;;
+ *)
+ cap_lib_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-cap-include-dir=DIR
+cap_include_dir=
+AC_ARG_WITH(cap-include-dir,
+ [AS_HELP_STRING([--with-cap-include-dir=DIR],
+ [directory in which to look for cap include files])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR([Need cap-include-dir])
+ ;;
+ yes)
+ ;;
+ *)
+ cap_include_dir="$withval"
+ ;;
+ esac])
+
+smart_try_dir="$cap_lib_dir"
+FR_SMART_CHECK_LIB(cap, cap_get_proc)
+if test "x$ac_cv_lib_cap_cap_get_proc" != "xyes"; then
+ AC_MSG_WARN([cap library not found, debugger checks will not be enabled. Use --with-cap-lib-dir=<path>.])
+else
+ AC_DEFINE(HAVE_LIBCAP, 1,
+ [Define to 1 if you have the `cap' library (-lcap).]
+ )
+ HAVE_LIBCAP=1
+fi
+
+dnl #
+dnl # Check for libreadline
+dnl #
+VL_LIB_READLINE
+
+dnl #
+dnl # Checks for systemd
+dnl #
+dnl # extra argument: --with-systemd
+dnl #
+AC_ARG_WITH([systemd],
+ AS_HELP_STRING([--with-systemd], [add systemd support, if available (default=no)]),
+ [ case "$withval" in
+ no)
+ WITH_SYSTEMD=no
+ ;;
+ *)
+ WITH_SYSTEMD=yes
+ esac ],
+ [WITH_SYSTEMD=no])
+
+dnl #
+dnl # extra argument: --systemd-lib-dir=dir
+dnl #
+systemd_lib_dir=
+AC_ARG_WITH(systemd-lib-dir,
+ [AS_HELP_STRING([--with-systemd-lib-dir=DIR],
+ [directory to look for systemd library files])],
+ [ case "$withval" in
+ *) systemd_lib_dir="$withval"
+ ;;
+ esac ]
+)
+
+dnl #
+dnl # extra argument: --with-systemd-includes=dir
+dnl #
+systemd_include_dir=
+AC_ARG_WITH(systemd-include-dir,
+ [AS_HELP_STRING([--with-systemd-include-dir=DIR],
+ [directory to look for systemd include files])],
+ [ case "$withval" in
+ *) systemd_include_dir="$withval"
+ ;;
+ esac ]
+)
+
+if test "x$WITH_SYSTEMD" = xyes; then
+ smart_try_dir="$systemd_lib_dir"
+ FR_SMART_CHECK_LIB(systemd, sd_notify)
+ if test "x$ac_cv_lib_systemd_sd_notify" != "xyes"; then
+ AC_MSG_WARN([systemd library not found. Use --with-systemd-lib-dir=<path>.])
+ else
+ AC_DEFINE([HAVE_SYSTEMD], [1],
+ [Define to 1 if you have the `systemd' library (-lsystemd).]
+ )
+ HAVE_SYSTEMD=1
+ SYSTEMD_LIBS="${smart_lib}"
+ SYSTEMD_LDFLAGS="${smart_ldflags}"
+ fi
+ dnl Set by FR_SMART_CHECKLIB
+ LIBS="${old_LIBS}"
+fi
+
+if test "x$HAVE_SYSTEMD" = x; then
+ AC_MSG_NOTICE([skipping test for systemd watchdog])
+else
+ smart_try_dir="$systemd_lib_dir"
+ FR_SMART_CHECK_LIB(systemd, sd_watchdog_enabled)
+ if test "x$ac_cv_lib_systemd_sd_watchdog_enabled" != "xyes"; then
+ AC_MSG_WARN([systemd watchdog is only available from systemd 209.])
+ else
+ AC_DEFINE([HAVE_SYSTEMD_WATCHDOG], [1],
+ [Define to 1 if you have watchdog support in the `systemd' library (-lsystemd).]
+ )
+ fi
+ dnl Set by FR_SMART_CHECKLIB
+ LIBS="${old_LIBS}"
+fi
+
+dnl #
+dnl # Check for the systemd headers
+dnl #
+if test "x$WITH_SYSTEMD" != xyes || test "x$SYSTEMD_LIBS" = x; then
+ AC_MSG_NOTICE([skipping test for systemd/sd-daemon.h.])
+else
+ smart_try_dir="$systemd_include_dir"
+ FR_SMART_CHECK_INCLUDE([systemd/sd-daemon.h])
+ if test "x$ac_cv_header_systemd_sdmdaemon_h" = "xyes"; then
+ AC_DEFINE(HAVE_SYSTEMD_SD_DAEMON_H, 1, [Define to 1 if you have the <systemd/sd-daemon.h> header file.])
+ AC_SUBST(SYSTEMD_LIBS)
+ AC_SUBST(SYSTEMD_LDFLAGS)
+ else
+ AC_MSG_WARN([systemd headers not found. Use --with-systemd-include-dir=<path>.])
+ fi
+fi
+
+dnl #############################################################
+dnl #
+dnl # 3. Checks for header files
+dnl #
+dnl #############################################################
+
+dnl #
+dnl # Check for talloc header files
+dnl #
+smart_try_dir="$talloc_include_dir"
+FR_SMART_CHECK_INCLUDE([talloc.h])
+if test "x$ac_cv_header_talloc_h" != "xyes"; then
+ AC_MSG_WARN([talloc headers not found. Use --with-talloc-include-dir=<path>.])
+ AC_MSG_ERROR([FreeRADIUS requires libtalloc])
+fi
+
+dnl #
+dnl # Interix requires us to set -D_ALL_SOURCE, otherwise
+dnl # getopt will be #included, but won't link. <sigh>
+dnl #
+dnl # On the other hand, it's 20222. Interix has likely been dead for a decade. :(
+dnl #
+case "$host" in
+ *-interix*)
+ CFLAGS="$CFLAGS -D_ALL_SOURCE"
+ ;;
+ *-darwin*)
+ AC_DEFINE([__APPLE_USE_RFC_3542], 1, [Force OSX >= 10.7 Lion to use RFC2292 IPv6 socket options])
+ ;;
+esac
+
+AC_HEADER_DIRENT
+AC_HEADER_STDC
+AC_HEADER_TIME
+AC_HEADER_SYS_WAIT
+
+AC_CHECK_HEADERS( \
+ arpa/inet.h \
+ crypt.h \
+ dlfcn.h \
+ errno.h \
+ fcntl.h \
+ features.h \
+ fnmatch.h \
+ getopt.h \
+ glob.h \
+ grp.h \
+ inttypes.h \
+ limits.h \
+ linux/if_packet.h \
+ malloc.h \
+ netdb.h \
+ netinet/in.h \
+ prot.h \
+ pwd.h \
+ resource.h \
+ semaphore.h \
+ sia.h \
+ siad.h \
+ signal.h \
+ stdatomic.h \
+ stdalign.h \
+ stdbool.h \
+ stddef.h \
+ stdint.h \
+ stdio.h \
+ sys/event.h \
+ sys/fcntl.h \
+ sys/prctl.h \
+ sys/procctl.h \
+ sys/ptrace.h \
+ sys/resource.h \
+ sys/security.h \
+ sys/select.h \
+ sys/socket.h \
+ sys/time.h \
+ sys/types.h \
+ sys/un.h \
+ sys/wait.h \
+ syslog.h \
+ unistd.h \
+ utime.h \
+ utmp.h \
+ utmpx.h \
+ winsock.h
+)
+
+dnl #
+dnl # FreeBSD requires sys/socket.h before net/if.h
+dnl #
+AC_CHECK_HEADERS(net/if.h, [], [],
+ [
+ #ifdef HAVE_SYS_SOCKET_H
+ # include <sys/socket.h>
+ #endif
+ ]
+)
+
+dnl #
+dnl # other checks which require headers
+dnl #
+if test "x$ac_cv_header_sys_security_h" = "xyes" && test "x$ac_cv_header_prot_h" = "xyes"
+then
+ AC_DEFINE(OSFC2, [], [define if you have OSFC2 authentication])
+fi
+
+if test "x$ac_cv_header_sia_h" = "xyes" && test "x$ac_cv_header_siad_h" = "xyes"
+then
+ AC_DEFINE(OSFSIA, [], [define if you have OSFSIA authentication])
+fi
+
+dnl #
+dnl # Were we told to use OpenSSL, if we were and we find an error, call AC_MSG_FAILURE and exit
+dnl #
+if test "x$WITH_OPENSSL" = xyes; then
+ OLD_LIBS="$LIBS"
+
+ dnl #
+ dnl # Apparently OpenSSL will attempt to build with kerberos if we don't pass this?!
+ dnl #
+ CFLAGS="$CFLAGS -DOPENSSL_NO_KRB5"
+
+ dnl #
+ dnl # Check we can link to libcrypto and libssl
+ dnl #
+ smart_try_dir="$openssl_lib_dir"
+ FR_SMART_CHECK_LIB(crypto, DH_new)
+ if test "x$ac_cv_lib_crypto_DH_new" = "xyes"; then
+ AC_DEFINE(HAVE_LIBCRYPTO, 1, [Define to 1 if you have the `crypto' library (-lcrypto).])
+ OPENSSL_LIBS="$smart_lib"
+ OPENSSL_LDFLAGS="$smart_ldflags"
+
+ FR_SMART_CHECK_LIB(ssl, SSL_new)
+ if test "x$ac_cv_lib_ssl_SSL_new" != "xyes"; then
+ AC_MSG_FAILURE([failed linking to libssl. Use --with-openssl-lib-dir=<path>, or --with-openssl=no (builds without OpenSSL)])
+ else
+ AC_DEFINE(HAVE_LIBSSL, 1, [Define to 1 if you have the `ssl' library (-lssl).])
+ OPENSSL_LIBS="$OPENSSL_LIBS $smart_lib"
+
+ if test "$OPENSSL_LDFLAGS" != "$smart_ldflags"; then
+ AC_MSG_FAILURE(["inconsistent LDFLAGS between -lssl '$smart_ldflags' and -lcrypto '$OPENSSL_LDFLAGS'"])
+ fi
+ fi
+ else
+ AC_MSG_FAILURE([failed linking to libcrypto. Use --with-openssl-lib-dir=<path>, or --with-openssl=no (builds without OpenSSL)])
+ fi
+
+ smart_try_dir="$openssl_include_dir"
+ FR_SMART_CHECK_INCLUDE(openssl/ssl.h)
+ if test "x$ac_cv_header_openssl_ssl_h" = "xyes"; then
+ AC_DEFINE(HAVE_OPENSSL_SSL_H, 1, [Define to 1 if you have the <openssl/ssl.h> header file.])
+
+ AC_CHECK_HEADERS( \
+ openssl/asn1.h \
+ openssl/conf.h \
+ openssl/crypto.h \
+ openssl/err.h \
+ openssl/evp.h \
+ openssl/hmac.h \
+ openssl/md5.h \
+ openssl/md4.h \
+ openssl/rand.h \
+ openssl/sha.h \
+ openssl/ssl.h \
+ openssl/ocsp.h \
+ openssl/engine.h,
+ [ OPENSSL_CPPFLAGS="$smart_include" ],
+ [
+ AC_MSG_FAILURE([failed locating OpenSSL headers. Use --with-openssl-include-dir=<path>, or --with-openssl=no (builds without OpenSSL)])
+ ]
+ )
+
+ AC_MSG_CHECKING([for OpenSSL version >= 1.0.2])
+ AC_EGREP_CPP(yes,
+ [#include <openssl/crypto.h>
+ #if (OPENSSL_VERSION_NUMBER >= 0x10002000L)
+ yes
+ #endif
+ ],
+ [
+ AC_MSG_RESULT(yes)
+ ],
+ [
+ AC_MSG_RESULT(no)
+ AC_MSG_FAILURE([OpenSSL version too old])
+ ]
+ )
+
+ dnl #
+ dnl # CPPFLAGS are passed to the compiler first, so we use
+ dnl # them to ensure things like --sysroot don't override the
+ dnl # library location we discovered previously.
+ dnl #
+ old_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="$OPENSSL_CPPFLAGS $CPPFLAGS"
+
+ dnl #
+ dnl # Now check that the header versions match the library
+ dnl #
+ AC_MSG_CHECKING([OpenSSL library and header version consistency])
+ AC_RUN_IFELSE(
+ [AC_LANG_PROGRAM(
+ [[
+ #include <stdio.h>
+ #include <openssl/opensslv.h>
+ #include <openssl/crypto.h>
+ ]],
+ [[
+ printf("library: %lx header: %lx... ", (unsigned long) SSLeay(), (unsigned long) OPENSSL_VERSION_NUMBER);
+ if (SSLeay() == OPENSSL_VERSION_NUMBER) {
+ return 0;
+ } else {
+ return 1;
+ }
+ ]]
+ )],
+ [
+ AC_MSG_RESULT(yes)
+ ],
+ [
+ AC_MSG_RESULT(no)
+ AC_MSG_FAILURE([OpenSSL library version does not match header version])
+ ],
+ [
+ AC_MSG_RESULT([cross-compiling (assuming yes)])
+ ]
+ )
+ dnl #
+ dnl # Check if the new HMAC_CTX interface is defined
+ dnl #
+ AC_CHECK_FUNCS( \
+ SSL_get_client_random \
+ SSL_get_server_random \
+ SSL_SESSION_get_master_key \
+ HMAC_CTX_new \
+ HMAC_CTX_free \
+ ASN1_STRING_get0_data \
+ CONF_modules_load_file \
+ CRYPTO_set_id_callback \
+ CRYPTO_set_locking_callback
+ )
+ CPPFLAGS="$old_CPPFLAGS"
+ fi
+
+ LIBS="$OLD_LIBS"
+ AC_SUBST(OPENSSL_LIBS)
+ AC_SUBST(OPENSSL_LDFLAGS)
+ AC_SUBST(OPENSSL_CPPFLAGS)
+ export OPENSSL_LIBS OPENSSL_LDFLAGS OPENSSL_CPPFLAGS
+fi
+
+dnl #
+dnl # Check the pcap includes for the RADIUS sniffer.
+dnl #
+if test "x$PCAP_LIBS" = x; then
+ AC_MSG_NOTICE([skipping test for pcap.h.])
+else
+ dnl #
+ dnl # Check for pcap header files
+ dnl #
+ smart_try_dir="$pcap_include_dir"
+ FR_SMART_CHECK_INCLUDE([pcap.h])
+ if test "x$ac_cv_header_pcap_h" = "xyes" && test "x$ac_cv_lib_pcap_pcap_open_live" = "xyes"; then
+ AC_DEFINE(HAVE_LIBPCAP, 1, [Define to 1 if you have the `pcap' library (-lpcap) and header file <pcap.h>.])
+ AC_SUBST(PCAP_LIBS)
+ AC_SUBST(PCAP_LDFLAGS)
+ else
+ AC_MSG_WARN([pcap headers not found, silently disabling the RADIUS sniffer, and ARP listener. Use --with-pcap-include-dir=<path>.])
+ fi
+fi
+
+dnl Check for collectd-client
+if test "x$COLLECTDC_LIBS" = x; then
+ AC_MSG_NOTICE([skipping test for collectd/client.h.])
+else
+ dnl #
+ dnl # Check for collectd-client header files
+ dnl #
+ smart_try_dir="$collectdclient_include_dir"
+ FR_SMART_CHECK_INCLUDE([collectd/client.h])
+ if test "x$ac_cv_header_collectd_client_h" = "xyes"; then
+ AC_DEFINE(HAVE_COLLECTDC_H, 1, [Define to 1 if you have the `collectdclient' library (-lcollectdclient).])
+ AC_SUBST(COLLECTDC_LIBS)
+ AC_SUBST(COLLECTDC_LDFLAGS)
+ else
+ AC_MSG_WARN([collectdclient headers not found. Use --with-collectdclient-include-dir=<path>.])
+ fi
+fi
+
+dnl #
+dnl # Check the CAP includes for debugger checks
+dnl #
+if test "x$HAVE_LIBCAP" = x; then
+ AC_MSG_NOTICE([skipping test for cap.h.])
+else
+ dnl #
+ dnl # Check for CAP header files
+ dnl #
+ smart_try_dir="$cap_include_dir"
+ FR_SMART_CHECK_INCLUDE([sys/capability.h])
+ if test "x$ac_cv_header_sys_capability_h" = "xyes"; then
+ AC_DEFINE(HAVE_CAPABILITY_H, 1, [Define to 1 if you have the <sys/capability.h> header file.])
+ else
+ AC_MSG_WARN([cap headers not found, will not perform debugger checks. Use --with-cap-include-dir=<path>.])
+ fi
+fi
+
+dnl #############################################################
+dnl #
+dnl # 4. Checks for typedefs
+dnl #
+dnl #############################################################
+
+dnl #
+dnl # Ensure that these are defined
+dnl #
+AC_TYPE_OFF_T
+AC_TYPE_PID_T
+AC_TYPE_SIZE_T
+AC_TYPE_UID_T
+
+dnl #
+dnl # Check for socklen_t
+dnl #
+FR_CHECK_TYPE_INCLUDE(
+ [
+ #ifdef HAVE_SYS_TYPES_H
+ # include <sys/types.h>
+ #endif
+
+ #ifdef HAVE_SYS_SOCKET_H
+ # include <sys/socket.h>
+ #endif
+ ],
+ socklen_t, int, [socklen_t is generally 'int' on systems which don't use it]
+)
+
+dnl #
+dnl # Check for uint8_t
+dnl #
+FR_CHECK_TYPE_INCLUDE(
+ [
+ #ifdef HAVE_INTTYPES_H
+ # include <inttypes.h>
+ #endif
+
+ #ifdef HAVE_STDINT_H
+ # include <stdint.h>
+ #endif
+ ],
+ uint8_t, unsigned char, [uint8_t should be the canonical 'octet' for network traffic]
+)
+
+dnl #
+dnl # Check for uint16_t
+dnl #
+FR_CHECK_TYPE_INCLUDE(
+ [
+ #ifdef HAVE_INTTYPES_H
+ # include <inttypes.h>
+ #endif
+
+ #ifdef HAVE_STDINT_H
+ # include <stdint.h>
+ #endif
+ ],
+ uint16_t, unsigned short, [uint16_t should be the canonical '2 octets' for network traffic]
+)
+
+dnl #
+dnl # Check for uint32_t
+dnl #
+FR_CHECK_TYPE_INCLUDE(
+ [
+ #ifdef HAVE_INTTYPES_H
+ # include <inttypes.h>
+ #endif
+
+ #ifdef HAVE_STDINT_H
+ # include <stdint.h>
+ #endif
+ ],
+ uint32_t, unsigned int, [uint32_t should be the canonical 'network integer']
+)
+
+dnl #
+dnl # Check for uint64_t
+dnl #
+FR_CHECK_TYPE_INCLUDE(
+ [
+ #ifdef HAVE_INTTYPES_H
+ # include <inttypes.h>
+ #endif
+
+ #ifdef HAVE_STDINT_H
+ # include <stdint.h>
+ #endif
+ ],
+ uint64_t, unsigned long long, [uint64_t is required for larger counters]
+)
+
+dnl #
+dnl # Check for __uint128_t (compiler builtin)
+dnl #
+AC_CHECK_TYPE(__uint128_t, AC_DEFINE(HAVE___UINT128_T, 1, [compiler specific 128 bit unsigned integer]), [], [])
+
+dnl #
+dnl # Check for uint128_t (fictitious future data type)
+dnl #
+AC_CHECK_TYPE(uint128_t, AC_DEFINE(HAVE_UINT128_T, 1, [128 bit unsigned integer]), [],
+ [
+ #ifdef HAVE_INTTYPES_H
+ # include <inttypes.h>
+ #endif
+
+ #ifdef HAVE_STDINT_H
+ # include <stdint.h>
+ #endif
+ ]
+)
+
+AC_CHECK_TYPE(struct in6_addr, AC_DEFINE(HAVE_STRUCT_IN6_ADDR, 1, [IPv6 address structure]), [],
+ [
+ #ifdef HAVE_NETINET_IN_H
+ # include <netinet/in.h>
+ #endif
+ ]
+)
+
+AC_CHECK_TYPE(struct sockaddr_storage, AC_DEFINE(HAVE_STRUCT_SOCKADDR_STORAGE, 1, [Generic socket addresses]), [],
+ [
+ #ifdef HAVE_NETINET_IN_H
+ # include <netinet/in.h>
+ #endif
+
+ #ifdef HAVE_SYS_SOCKET_H
+ # include <sys/socket.h>
+ #endif
+])
+
+AC_CHECK_TYPE(struct sockaddr_in6, AC_DEFINE(HAVE_STRUCT_SOCKADDR_IN6, 1, [IPv6 socket addresses]), [],
+ [
+ #ifdef HAVE_NETINET_IN_H
+ # include <netinet/in.h>
+ #endif
+])
+
+AC_CHECK_TYPE(struct addrinfo, AC_DEFINE(HAVE_STRUCT_ADDRINFO, 1, [Generic DNS lookups]), [],
+ [
+ #ifdef HAVE_SYS_TYPES_H
+ # include <sys/types.h>
+ #endif
+
+ #ifdef HAVE_SYS_SOCKET_H
+ # include <sys/socket.h>
+ #endif
+
+ #ifdef HAVE_NETDB_H
+ # include <netdb.h>
+ #endif
+ ]
+)
+
+dnl #
+dnl # Check for sig_t
+dnl #
+dnl # FR_CHECK_TYPE_INCLUDE doesn't work for callbacks as it doesn't produce typedefs
+dnl #
+AC_MSG_CHECKING([if sig_t is defined])
+AC_LINK_IFELSE(
+ [AC_LANG_PROGRAM(
+ [[
+ #ifdef HAVE_SIGNAL_H
+ # include <signal.h>
+ #endif
+ ]],
+ [[
+ sig_t func;
+ return 0;
+ ]]
+ )],
+ [
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_SIG_T, 1, [Define if the type sig_t is defined by signal.h])
+ ],
+ [
+ AC_MSG_RESULT(no)
+ ]
+)
+
+dnl #############################################################
+dnl #
+dnl # 5. Checks for structures and functions
+dnl #
+dnl #############################################################
+AC_CHECK_FUNCS( \
+ bindat \
+ clock_gettime \
+ closefrom \
+ ctime_r \
+ dladdr \
+ fcntl \
+ fopencookie \
+ funopen \
+ getaddrinfo \
+ getnameinfo \
+ getopt_long \
+ getpeereid \
+ getresuid \
+ gettimeofday \
+ getusershell \
+ gmtime_r \
+ if_indextoname \
+ inet_aton \
+ inet_ntop \
+ inet_pton \
+ initgroups \
+ kqueue \
+ localtime_r \
+ mallopt \
+ mkdirat \
+ openat \
+ pthread_sigmask \
+ setlinebuf \
+ setresuid \
+ setsid \
+ setuid \
+ setvbuf \
+ sigaction \
+ sigprocmask \
+ snprintf \
+ strcasecmp \
+ strlcat \
+ strlcpy \
+ strncasecmp \
+ strsep \
+ strsignal \
+ unlinkat \
+ vdprintf \
+ vsnprintf
+)
+
+dnl #
+dnl # Check if we have utmpx.h
+dnl # if so, check if struct utmpx has entry ut_xtime
+dnl # if not, set it to define ut_xtime = ut_tv.tv_sec
+dnl #
+if test "x$ac_cv_header_utmpx_h" = "xyes"; then
+ FR_CHECK_STRUCT_HAS_MEMBER([#include <utmpx.h>], [struct utmpx], ut_xtime)
+ if test "x$ac_cv_type_struct_utmpx_has_ut_xtime" = "x"; then
+ AC_DEFINE(ut_xtime, ut_tv.tv_sec, [define to something if you don't have ut_xtime in struct utmpx])
+ fi
+fi
+
+dnl #
+dnl # struct ip_pktinfo
+dnl #
+FR_CHECK_STRUCT_HAS_MEMBER([#include <netinet/in.h>], [struct in_pktinfo], ipi_addr)
+if test "x$ac_cv_type_struct_in_pktinfo_has_ipi_addr" = "xyes"; then
+ AC_DEFINE(HAVE_IP_PKTINFO, [], [define if you have IP_PKTINFO (Linux)])
+fi
+
+dnl #
+dnl # struct in6_pktinfo
+dnl #
+FR_CHECK_STRUCT_HAS_MEMBER([#include <netinet/in.h>], [struct in6_pktinfo], ipi6_addr)
+if test "x$ac_cv_type_struct_in6_pktinfo_has_ipi6_addr" = "xyes"; then
+ AC_DEFINE(HAVE_IN6_PKTINFO, [], [define if you have IN6_PKTINFO (Linux)])
+fi
+
+dnl #
+dnl # Check for htonll and htonlll
+dnl #
+AC_MSG_CHECKING([if htonll is defined])
+AC_LINK_IFELSE(
+ [AC_LANG_PROGRAM(
+ [[
+ #include <sys/types.h>
+ #include <netinet/in.h>
+ ]],
+ [[
+ return htonll(0);
+ ]]
+ )],
+ [
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_HTONLL, 1, [Define if the function (or macro) htonll exists.])
+ ],
+ [
+ AC_MSG_RESULT(no)
+ ]
+)
+
+AC_MSG_CHECKING([if htonlll is defined])
+AC_LINK_IFELSE(
+ [AC_LANG_PROGRAM(
+ [[
+ #include <sys/types.h>
+ #include <netinet/in.h>
+ ]],
+ [[
+ return htonlll(0);
+ ]]
+ )],
+ [
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_HTONLLL, 1, [Define if the function (or macro) htonlll exists.])
+ ],
+ [
+ AC_MSG_RESULT(no)
+ ]
+)
+
+dnl #############################################################
+dnl #
+dnl # 6. Checks for compiler characteristics
+dnl #
+dnl #############################################################
+
+dnl #
+dnl # Ensure that these are defined
+dnl #
+AC_C_CONST
+
+dnl #
+dnl # See if this is OS/2
+dnl #
+AC_MSG_CHECKING([type of OS])
+OS=`uname -s`
+AC_MSG_RESULT($OS)
+if test "$OS" = "OS/2"; then
+ LIBPREFIX=
+else
+ LIBPREFIX=lib
+fi
+AC_SUBST(LIBPREFIX)
+
+if test "x$developer" = "xyes"; then
+ AC_MSG_NOTICE([Setting additional developer CFLAGS])
+
+ dnl #
+ dnl # Tell the compiler to parse doxygen documentation and verify it against function and variable declarations
+ dnl #
+ AX_CC_WDOCUMENTATION_FLAG
+ if test "x$ax_cv_cc_wdocumentation_flag" = "xyes"; then
+ devcflags="-Wdocumentation"
+ AC_DEFINE([HAVE_WDOCUMENTATION],1,[Define if the compiler supports -Wdocumentation])
+ fi
+
+ dnl #
+ dnl # If we have -Weverything, it really means *everything* unlike -Wall
+ dnl # It's so verbose we need to turn off warnings which aren't useful.
+ dnl #
+ AX_CC_WEVERYTHING_FLAG
+ if test "x$ax_cv_cc_weverything_flag" = "xyes"; then
+ devcflags="$devcflags -W -Weverything -Wformat=2 -Wno-missing-field-initializers -Wno-date-time -Wno-padded -Wno-gnu-zero-variadic-macro-arguments -Wno-shorten-64-to-32 -Wno-sign-conversion -Wno-conversion -Wno-switch-enum -Wno-gnu-statement-expression -Wno-extended-offsetof -Wno-cast-align -Wno-documentation-unknown-command -Wno-covered-switch-default -Wno-packed $verify_ptr $fips"
+ else
+ if test "x$GCC" = "xyes"; then
+ devcflags="$devcflags -Wshadow -Wpointer-arith -Wcast-qual -Wcast-align -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wnested-externs -W -Wredundant-decls -Wundef -Wformat-y2k -Wno-format-extra-args -Wno-format-zero-length -Wno-cast-align -Wformat-nonliteral -Wformat-security -Wformat=2 $verify_ptr $fips"
+ INSTALLSTRIP=""
+ fi
+ fi
+
+ dnl #
+ dnl # Can't use mutliple -fsanitize flags, so we need to combine
+ dnl # the values into one.
+ dnl #
+ fsanitizeflags=
+
+ dnl #
+ dnl # If running with clang, add in FUZZER
+ dnl #
+ if test "x$fuzzer" = "xyes" && test "x$ax_cv_cc_clang" = "xyes"; then
+ dnl #
+ dnl # -fsanitize=fuzzer - Build with fuzzer support
+ dnl #
+ fsanitizeflags="$fsanitizeflags,fuzzer"
+ fi
+
+ dnl #
+ dnl # Add in ASAN
+ dnl #
+ if test "x$address_sanitizer" = "xyes"; then
+ dnl #
+ dnl # -fsanitize=address - Build with address sanitizer support
+ dnl # -fno-omit-frame-pointer - Always keep the frame pointer in a register
+ dnl # -fno-optimize-sibling-calls - Don't optimize away tail recursion.
+ dnl #
+ devcflags="$devcflags -fno-omit-frame-pointer -fno-optimize-sibling-calls"
+
+ AX_CC_SANITZE_ADDRESS_USE_AFTER_SCOPE_FLAG
+ if test "x$ax_cv_cc_sanitize_address_use_after_scope" = "xyes"; then
+ devcflags="$devcflags -fsanitize-address-use-after-scope"
+ fi
+
+ AC_CHECK_HEADERS(sanitizer/lsan_interface.h)
+ fsanitizeflags="$fsanitizeflags,address"
+ fi
+
+ dnl #
+ dnl # Add in LSAN
+ dnl #
+ if test "x$leak_sanitizer" = "xyes"; then
+ dnl #
+ dnl # -fsanitize=leak - Build with lsan support
+ dnl #
+ fsanitizeflags="$fsanitizeflags,leak"
+ fi
+
+ dnl #
+ dnl # Add in TSAN
+ dnl #
+ if test "x$thread_sanitizer" = "xyes"; then
+ dnl #
+ dnl # -fsanitize=thread - Build with tsan support
+ dnl #
+ fsanitizeflags="$fsanitizeflags,thread"
+ fi
+
+ dnl #
+ dnl # Add in UBSAN
+ dnl #
+ if test "x$undefined_behaviour_sanitizer" = "xyes"; then
+ dnl #
+ dnl # -fsanitize=undefined - Build with ubsan support
+ dnl # -fno-omit-frame-pointer - Always keep the frame pointer in a register
+ dnl #
+ devcflags="$devcflags -fno-sanitize-recover=undefined -fno-omit-frame-pointer"
+ devldflags="$devldflags -fno-sanitize-recover=undefined"
+ fsanitizeflags="$fsanitizeflags,undefined"
+ fi
+
+ if test "x$fsanitizeflags" != "x"; then
+ fsanitizeflags="$(echo $fsanitizeflags | sed 's/^,*//')"
+ devcflags="-fsanitize=$fsanitizeflags $devcflags"
+ devldflags="-fsanitize=$fsanitizeflags $devldflags"
+ fi
+
+ dnl #
+ dnl # Clean the flags up
+ dnl #
+ devcflags="$(echo $devcflags | sed -e 's/\\t//g;s/ //g')"
+ devldflags="$(echo $devldflags | sed -e 's/\\t//g;s/ //g')"
+
+ AC_MSG_NOTICE([Developer CFLAGS are "$devcflags"])
+ AC_MSG_NOTICE([Developer LDFLAGS are "$devldflags"])
+
+ dnl #
+ dnl # Enable experimental modules (we want to know if code changes breaks one of them)
+ dnl #
+ if test "x$EXPERIMENTAL" != "xno"; then
+ AC_MSG_NOTICE([is developer build, enabling experimental modules implicitly, disable with --without-experimental-modules])
+ EXPERIMENTAL=yes
+ fi
+else
+ devcflags=""
+ devldflags=""
+ CFLAGS="$CFLAGS -DNDEBUG"
+ INSTALLSTRIP=""
+fi
+
+dnl #
+dnl # May of been set outside of this configure script
+dnl #
+AC_MSG_CHECKING([if building with -DNDEBUG])
+if echo "$CFLAGS" | grep '\-DNDEBUG' > /dev/null; then
+ AC_MSG_RESULT([yes])
+ AC_DEFINE([WITH_NDEBUG], [1], [define if the server was built with -DNDEBUG])
+else
+ AC_MSG_RESULT([no])
+fi
+
+export EXPERIMENTAL
+
+dnl #
+dnl # append the current git hash onto the version string
+dnl #
+if test -d $srcdir/.git -a "x$GIT" = "xyes"; then
+ RADIUSD_VERSION_COMMIT=`git log --pretty=format:'%h' -n 1 | cut -c1-9`
+ AC_DEFINE_UNQUOTED([RADIUSD_VERSION_COMMIT],[${RADIUSD_VERSION_COMMIT}],[Commit HEAD at time of configuring])
+fi
+
+dnl #
+dnl # check for some compiler features
+dnl #
+FR_TLS
+FR_HAVE_BUILTIN_CHOOSE_EXPR
+FR_HAVE_BUILTIN_TYPES_COMPATIBLE_P
+FR_HAVE_BUILTIN_BSWAP64
+FR_HAVE_BOUNDED_ATTRIBUTE
+
+dnl #############################################################
+dnl #
+dnl # 7. Checks for library functions
+dnl #
+dnl #############################################################
+
+dnl #
+dnl # Check for talloc_set_memlimit
+dnl # This was only included in version 2.0.8
+dnl #
+AC_CHECK_LIB(talloc, talloc_set_memlimit,
+ [
+ AC_DEFINE(HAVE_TALLOC_SET_MEMLIMIT, 1, [Define to 1 if you have the function talloc_set_memlimit.])
+ ]
+)
+
+dnl #
+dnl # Check for libcrypt
+dnl # We use crypt(3) which may be in libc, or in libcrypt (eg FreeBSD)
+dnl #
+AC_CHECK_LIB(crypt, crypt,
+ CRYPTLIB="-lcrypt"
+)
+
+if test "$CRYPTLIB" != ""; then
+ AC_DEFINE(HAVE_CRYPT, [], [Do we have the crypt function])
+else
+ AC_CHECK_FUNC(crypt, AC_DEFINE(HAVE_CRYPT, [], [Do we have the crypt function]))
+fi
+
+dnl crypt_r is the GNU thread-safe version
+AC_CHECK_LIB(crypt, crypt_r, AC_DEFINE(HAVE_CRYPT_R, [], [Do we have the crypt_r function]))
+
+dnl Check for libcipher
+AC_CHECK_LIB(cipher, setkey,
+ CRYPTLIB="${CRYPTLIB} -lcipher"
+)
+AC_SUBST(CRYPTLIB)
+
+dnl #
+dnl # Check for libexecinfo support, on some systems this is built into libc
+dnl # on others it's a separate library.
+dnl #
+dnl extra argument: --with-execinfo-lib-dir
+execinfo_lib_dir=
+AC_ARG_WITH(execinfo-lib-dir,
+[AS_HELP_STRING([--with-execinfo-lib-dir=DIR],
+[directory in which to look for execinfo library files])],
+[ case "$withval" in
+ no)
+ AC_MSG_ERROR([Need execinfo-lib-dir])
+ ;;
+ yes)
+ ;;
+ *)
+ execinfo_lib_dir="$withval"
+ ;;
+ esac ]
+)
+
+dnl extra argument: --with-execinfo-include-dir
+execinfo_include_dir=
+AC_ARG_WITH(execinfo-include-dir,
+[AS_HELP_STRING([--with-execinfo-include-dir=DIR],
+[directory in which to look for execinfo include files])],
+[ case "$withval" in
+ no)
+ AC_MSG_ERROR([Need execinfo-include-dir])
+ ;;
+ yes)
+ ;;
+ *)
+ execinfo_include_dir="$withval"
+ ;;
+ esac ]
+)
+
+dnl #
+dnl # Look for execinfo.h and symbols
+dnl #
+smart_try_dir=$execinfo_include_dir
+FR_SMART_CHECK_INCLUDE(execinfo.h)
+if test "x$ac_cv_header_execinfo_h" = "xyes"; then
+ smart_try_dir=$execinfo_lib_dir
+ FR_SMART_CHECK_LIB(execinfo, backtrace_symbols)
+ if test "x$ac_cv_lib_execinfo_backtrace_symbols" != "xyes"; then
+ dnl # Might be provided as part of libc
+ AC_MSG_CHECKING([if execinfo provided as part of libc])
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[
+ #include <execinfo.h>
+ ]], [[
+ void *sym[1];
+ backtrace_symbols(&sym, sizeof(sym)) ]])],[
+ AC_MSG_RESULT(yes)
+ ac_cv_lib_execinfo_backtrace_symbols="yes"
+ ],[
+ AC_MSG_RESULT(no)
+ ])
+ fi
+
+ if test "x$ac_cv_lib_execinfo_backtrace_symbols" = "xyes"; then
+ AC_DEFINE(HAVE_EXECINFO, [1], [define this if we have <execinfo.h> and symbols])
+ fi
+fi
+
+dnl #
+dnl # Check for regular expression support.
+dnl #
+dnl extra argument: --with-pcre
+PCRE=yes
+AC_ARG_WITH(pcre,
+[AS_HELP_STRING([--with-pcre],
+[use libpcre (if available). (default=yes)])],
+[ case "$withval" in
+ no)
+ PCRE=no
+ ;;
+ yes)
+ PCRE=yes
+ ;;
+ esac ]
+)
+
+dnl extra argument: --with-pcre-lib-dir
+pcre_lib_dir=
+AC_ARG_WITH(pcre-lib-dir,
+[AS_HELP_STRING([--with-pcre-lib-dir=DIR],
+[directory in which to look for pcre library files])],
+[ case "$withval" in
+ no)
+ AC_MSG_ERROR(Need pcre-lib-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ pcre_lib_dir="$withval"
+ ;;
+ esac ]
+)
+
+dnl extra argument: --with-pcre-include-dir
+pcre_include_dir=
+AC_ARG_WITH(pcre-include-dir,
+[AS_HELP_STRING([--with-pcre-include-dir=DIR],
+[directory in which to look for pcre include files])],
+[ case "$withval" in
+ no)
+ AC_MSG_ERROR(Need pcre-include-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ pcre_include_dir="$withval"
+ ;;
+ esac ]
+)
+
+dnl extra argument: --with-regex
+REGEX=
+AC_ARG_WITH(regex,
+[AS_HELP_STRING([--with-regex],
+[Whether to build with regular expressions (default=yes)])],
+[ case "$withval" in
+ no)
+ REGEX=no
+ ;;
+ *)
+ ;;
+ esac ]
+)
+
+dnl #
+dnl # First look for PCRE
+dnl #
+if test "x$REGEX" != "xno" && test "x$PCRE" != "xno"; then
+ smart_try_dir=$pcre_include_dir
+ FR_SMART_CHECK_INCLUDE(pcre.h)
+ if test "x$ac_cv_header_pcre_h" = "xyes"; then
+ smart_try_dir=$pcre_lib_dir
+ FR_SMART_CHECK_LIB(pcre, pcre_compile)
+ if test "x$ac_cv_lib_pcre_pcre_compile" = "xyes"; then
+ REGEX=yes
+ AC_DEFINE(HAVE_PCRE, [1], [define this if we have libpcre])
+ AC_DEFINE(HAVE_BINSAFE_REGEX, 1, [Define if we have a binary safe regular expression library])
+ fi
+ fi
+fi
+
+dnl #
+dnl # If no PCRE, fallback to POSIX regular expressions
+dnl #
+if test "x$REGEX" = "x"; then
+ smart_try_dir=
+ FR_SMART_CHECK_INCLUDE(regex.h)
+ if test "x$ac_cv_header_regex_h" = "xyes"; then
+ REGEX=yes
+ AC_MSG_CHECKING([for extended regular expressions])
+ AC_EGREP_CPP(yes,
+ [
+ #include <regex.h>
+ #ifdef REG_EXTENDED
+ yes
+ #endif
+ ],
+ [
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_REG_EXTENDED, [1], [define this if we have REG_EXTENDED (from <regex.h>)])
+ ],
+ [
+ AC_MSG_RESULT(no)
+ ]
+ )
+
+ dnl #
+ dnl # Some platforms require the regex library to be linked explicitly
+ dnl #
+ AC_CHECK_LIB(regex, regcomp,
+ [
+ LIBS="-lregex $LIBS"
+ ]
+ )
+
+ dnl #
+ dnl # Check for some BSD extensions which allow normal regexes to be
+ dnl # binary safe.
+ dnl #
+ AC_CHECK_FUNCS(\
+ regncomp \
+ regnexec
+ )
+ if test x"$ac_cv_func_regncomp" = x"yes" && test x"$ac_cv_func_regnexec" = x"yes"; then
+ AC_DEFINE(HAVE_BINSAFE_REGEX, 1, [Define if we have a binary safe regular expression library])
+ fi
+ fi
+fi
+
+#
+# Some platforms require an explicit -latomic
+#
+AC_SEARCH_LIBS([__atomic_load_4], [atomic])
+
+if test "x$REGEX" = "xyes"; then
+ AC_DEFINE(HAVE_REGEX, 1, [Define if we have any regular expression library])
+fi
+
+dnl #
+dnl # Check the style of gethostbyaddr, in order of preference
+dnl # GNU (_r eight args)
+dnl #
+AC_DEFINE(GNUSTYLE, [1], [GNU-Style get*byaddr_r])
+
+dnl #
+dnl # SYSV (_r six args)
+dnl #
+AC_DEFINE(SYSVSTYLE, [2], [SYSV-Style get*byaddr_r])
+
+dnl #
+dnl # BSD (three args, may not be thread safe)
+dnl #
+AC_DEFINE(BSDSTYLE, [3], [BSD-Style get*byaddr_r])
+
+dnl #
+dnl # Tru64 has BSD version, but it is thread safe
+dnl # http://h30097.www3.hp.com/docs/base_doc/DOCUMENTATION/V51B_HTML/MAN/MAN3/1739____.HTM
+dnl # We need #stdio.h to define NULL on FreeBSD (at least)
+dnl #
+gethostbyaddrrstyle=""
+AC_MSG_CHECKING([gethostbyaddr_r() syntax])
+case "$host" in
+ *-freebsd*)
+ dnl #
+ dnl # With FreeBSD, check if there's a prototype for gethostbyaddr_r.
+ dnl # Some versions (FreeBSD 5.1?) have a symbol but no prototype - so we
+ dnl # override this test to BSDSTYLE. FreeBSD 6.2 and up have proper GNU
+ dnl # style support.
+ dnl #
+ AC_CHECK_DECLS([gethostbyaddr_r], [],
+ [
+ AC_DEFINE(GETHOSTBYADDRRSTYLE, BSDSTYLE,
+ [style of gethostbyaddr_r functions ])
+ gethostbyaddrrstyle=BSD
+ AC_MSG_WARN([FreeBSD overridden to BSD-style])
+ ],
+ [
+ #ifdef HAVE_NETDB_H
+ #include <netdb.h>
+ #endif
+ ])
+ ;;
+esac
+
+if test "x$gethostbyaddrrstyle" = "x"; then
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[
+ #include <stdio.h>
+ #include <netdb.h>
+ ]], [[ gethostbyaddr_r(NULL, 0, 0, NULL, NULL, 0, NULL, NULL) ]])],[
+ AC_DEFINE(GETHOSTBYADDRRSTYLE, GNUSTYLE, [style of gethostbyaddr_r functions ])
+ gethostbyaddrrstyle=GNU
+ ],[])
+fi
+
+if test "x$gethostbyaddrrstyle" = "x"; then
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[
+ #include <stdio.h>
+ #include <netdb.h>
+ ]], [[ gethostbyaddr_r(NULL, 0, 0, NULL, NULL, 0, NULL) ]])],[
+ AC_DEFINE(GETHOSTBYADDRRSTYLE, SYSVSTYLE, [style of gethostbyaddr_r functions ])
+ gethostbyaddrrstyle=SYSV
+ ],[])
+fi
+
+
+if test "x$gethostbyaddrrstyle" = "x"; then
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[
+ #include <stdio.h>
+ #include <netdb.h>
+ ]], [[ gethostbyaddr(NULL, 0, 0) ]])],[
+ AC_DEFINE(GETHOSTBYADDRRSTYLE, BSDSTYLE, [style of gethostbyaddr_r functions ])
+ gethostbyaddrrstyle=BSD
+ ],[])
+fi
+
+if test "x$gethostbyaddrrstyle" = "x"; then
+ AC_MSG_RESULT([none! It must not exist, here.])
+else
+ AC_MSG_RESULT([${gethostbyaddrrstyle}-style])
+fi
+
+if test "x$gethostbyaddrrstyle" = "xBSD"; then
+ AC_MSG_WARN([ ****** BSD-style gethostbyaddr might NOT be thread-safe! ****** ])
+fi
+
+dnl #
+dnl # Check the style of gethostbyname, in order of preference
+dnl # GNU (_r seven args)
+dnl # SYSV (_r five args)
+dnl # BSD (two args, may not be thread safe)
+dnl # Tru64 has BSD version, but it _is_ thread safe
+dnl # http://h30097.www3.hp.com/docs/base_doc/DOCUMENTATION/V51B_HTML/MAN/MAN3/1946____.HTM
+dnl # We need #stdio.h to define NULL on FreeBSD (at least)
+dnl #
+gethostbynamerstyle=""
+AC_MSG_CHECKING([gethostbyname_r() syntax])
+AC_LINK_IFELSE([AC_LANG_PROGRAM([[
+ #include <stdio.h>
+ #include <netdb.h>
+ ]], [[ gethostbyname_r(NULL, NULL, NULL, 0, NULL, NULL) ]])],[
+ AC_DEFINE(GETHOSTBYNAMERSTYLE, GNUSTYLE, [style of gethostbyname_r functions ])
+ gethostbynamerstyle=GNU
+],[])
+
+if test "x$gethostbynamerstyle" = "x"; then
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[
+ #include <stdio.h>
+ #include <netdb.h>
+ ]], [[ gethostbyname_r(NULL, NULL, NULL, 0, NULL) ]])],[
+ AC_DEFINE(GETHOSTBYNAMERSTYLE, SYSVSTYLE, [style of gethostbyname_r functions ])
+ gethostbynamerstyle=SYSV
+ ],[])
+fi
+
+if test "x$gethostbynamerstyle" = "x"; then
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[
+ #include <stdio.h>
+ #include <netdb.h>
+ ]], [[ gethostbyname(NULL) ]])],[
+ AC_DEFINE(GETHOSTBYNAMERSTYLE, BSDSTYLE, [style of gethostbyname_r functions ])
+ gethostbynamerstyle=BSD
+ ],[])
+fi
+
+if test "x$gethostbynamerstyle" = "x"; then
+ AC_MSG_RESULT([none! It must not exist, here.])
+else
+ AC_MSG_RESULT([${gethostbynamerstyle}-style])
+fi
+
+if test "x$gethostbynamerstyle" = "xBSD"; then
+ AC_MSG_WARN([ ****** BSD-style gethostbyname might NOT be thread-safe! ****** ])
+fi
+
+dnl #
+dnl # Check for thread-safe getpwnam_r and getgrnam_r
+dnl #
+if test "x$ac_cv_header_pwd_h" = "xyes"; then
+ AC_MSG_CHECKING([getpwnam_r])
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[
+ #include <stdlib.h>
+ #include <sys/types.h>
+ #include <pwd.h>
+ ]], [[ getpwnam_r(NULL, NULL, NULL, 0, NULL) ]])],[
+ AC_MSG_RESULT([yes])
+ AC_DEFINE(HAVE_GETPWNAM_R, 1,
+ [Define to 1 if you have the getpwnam_r.]
+ )
+ ],[
+ AC_MSG_RESULT(no)
+ ])
+fi
+
+if test "x$ac_cv_header_grp_h" = "xyes"; then
+ AC_MSG_CHECKING([getgrnam_r])
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[
+ #include <stdlib.h>
+ #include <sys/types.h>
+ #include <grp.h>
+ ]], [[ getgrnam_r(NULL, NULL, NULL, 0, NULL) ]])],[
+ AC_MSG_RESULT([yes])
+ AC_DEFINE(HAVE_GETGRNAM_R, 1,
+ [Define to 1 if you have the getgrnam_r.]
+ )
+ ],[
+ AC_MSG_RESULT(no)
+ ])
+fi
+
+
+dnl #
+dnl # Check for non-posix solaris ctime_r (extra buflen int arg)
+dnl #
+AC_DEFINE(POSIXSTYLE, [1], [Posix-Style ctime_r])
+AC_DEFINE(SOLARISSTYLE, [2], [Solaris-Style ctime_r])
+ctimerstyle=""
+AC_MSG_CHECKING([ctime_r() syntax])
+AC_LINK_IFELSE([AC_LANG_PROGRAM([[
+ #include <time.h>
+ ]], [[ ctime_r(NULL, NULL, 0) ]])],[
+ AC_DEFINE(CTIMERSTYLE, SOLARISSTYLE, [style of ctime_r function])
+ ctimerstyle="SOLARIS"
+],[])
+
+if test "x$ctimerstyle" = "x"; then
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[
+ #include <time.h>
+ ]], [[ ctime_r(NULL, NULL) ]])],[
+ AC_DEFINE(CTIMERSTYLE, POSIXSTYLE, [style of ctime_r function])
+ ctimerstyle="POSIX"
+ ],[])
+fi
+
+if test "x$ctimerstyle" = "x"; then
+ AC_MSG_RESULT([none! It must not exist, here.])
+else
+ AC_MSG_RESULT([${ctimerstyle}-style])
+fi
+
+AC_SUBST(HOSTINFO, $host)
+
+dnl #############################################################
+dnl #
+dnl # 8. Checks for system services
+dnl #
+dnl #############################################################
+
+dnl #
+dnl # Figure out where libtool is located,
+dnl #
+top_builddir=`pwd`
+export top_builddir
+AC_MSG_RESULT([top_builddir=$top_builddir])
+dnl # AC_SUBST(top_builddir)
+
+dnl #
+dnl # import libtool stuff
+dnl #
+dnl #############################################################
+dnl #
+dnl # Configure in any module directories.
+dnl #
+dnl #############################################################
+
+dnl ############################################################
+dnl # Remove any conflicting definitions if autoconf.h
+dnl # is being included by a module.
+dnl #############################################################
+AH_BOTTOM([#include <freeradius-devel/automask.h>])
+
+dnl ############################################################
+dnl # make modules by list
+dnl #############################################################
+if test "x$EXPERIMENTAL" = "xyes"; then
+ for foo in `ls -1 "${srcdir}"/src/modules | grep rlm_`; do
+ MODULES="$MODULES $foo"
+ done
+else
+ dnl #
+ dnl # make ONLY the stable modules
+ dnl #
+ for foo in `cat "${srcdir}"/src/modules/stable`; do
+ MODULES="$MODULES $foo"
+ done
+fi
+
+dnl ############################################################
+dnl # Add autoconf subdirs, based on the module list we
+dnl # previously created.
+dnl #############################################################
+mysubdirs=""
+for bar in $MODULES; do
+ if test -f "${srcdir}"/src/modules/$bar/configure; then
+ mysubdirs="$mysubdirs src/modules/$bar"
+ fi
+done
+
+dnl #
+dnl # Don't change the variable name here. Autoconf goes bonkers
+dnl # if you do.
+dnl #
+AC_CONFIG_SUBDIRS($mysubdirs)
+AC_SUBST(MODULES)
+
+dnl #
+dnl # If reproducible builds are not enabled, disable
+dnl # -Wdate-time so the compiler doesn't croak.
+dnl #
+if test "x$ax_cv_cc_no_date_time_flag" = "xyes" && test "x$reproducible_builds" != "xyes"; then
+ CFLAGS="-Wno-date-time $CFLAGS"
+fi
+
+dnl #############################################################
+dnl #
+dnl # Add $devcflags, $devldflags and -Werror last, so they don't
+dnl # interfere with autoconf's test programs.
+dnl #
+dnl #############################################################
+CFLAGS="$CFLAGS $devcflags"
+LDFLAGS="$LDFLAGS $devldflags"
+
+if test "x$werror" = "xyes"; then
+ CFLAGS="-Werror $CFLAGS"
+fi
+
+dnl #############################################################
+dnl #
+dnl # And finally, output the results.
+dnl #
+dnl #############################################################
+AC_CONFIG_COMMANDS([stamp-h], [echo timestamp > src/include/stamp-h])
+AC_CONFIG_COMMANDS([build-radpaths-h], [(cd ./src/include && /bin/sh ./build-radpaths-h)])
+AC_CONFIG_COMMANDS([main-chmod], [(cd ./src/main && chmod +x checkrad radlast radtest)])
+AC_CONFIG_COMMANDS([scripts-chmod], [(cd ./scripts && chmod +x rc.radiusd cron/radiusd.cron.daily cron/radiusd.cron.monthly cryptpasswd)])
+
+dnl #
+dnl # Substitute whatever libraries we found to be necessary
+dnl #
+AC_SUBST(LIBS)
+AC_SUBST(INSTALLSTRIP)
+
+AC_SUBST(USE_SHARED_LIBS)
+USE_STATIC_LIBS="yes"
+AC_SUBST(USE_STATIC_LIBS)
+AC_SUBST(STATIC_MODULES)
+
+AC_CONFIG_FILES([\
+ ./Make.inc \
+ ./src/include/build-radpaths-h \
+ ./src/main/radsniff.mk \
+ ./src/main/checkrad \
+ ./src/main/radlast \
+ ./src/main/radtest \
+ ./scripts/rc.radiusd \
+ ./scripts/cron/radiusd.cron.daily \
+ ./scripts/cron/radiusd.cron.monthly \
+ ./scripts/cryptpasswd \
+ ./raddb/radrelay.conf \
+ ./raddb/radiusd.conf
+])
+AC_OUTPUT
+
+FR_MODULE_REPORT
diff --git a/doc/.gitignore b/doc/.gitignore
new file mode 100644
index 0000000..e35d885
--- /dev/null
+++ b/doc/.gitignore
@@ -0,0 +1 @@
+_build
diff --git a/doc/ChangeLog b/doc/ChangeLog
new file mode 100644
index 0000000..6b7006e
--- /dev/null
+++ b/doc/ChangeLog
@@ -0,0 +1,189 @@
+FreeRADIUS 3.2.3 Fri 26 May 2023 12:00:00 EDT urgency=low
+ Configuration changes
+ * The rlm_ldap and rlm_sql modules now have a "max_retries" configuration
+ item in the pool section. This sets a limit on how many times an operation
+ will be retried if it fails indicating a connection issue.
+ * Added "check_crl" configuration to rlm_ldap. This only works with OpenSSL.
+ Many Linux distributions use other TLS libraries, which won't work.
+ * Note that rlm_ldap does not support "-=" operators. The documentation
+ disagreed with the code, so we fixed the documentation.
+ * If checkrad is called from SQL Simultaneous-Use checks it will now be
+ passed NAS-Port-Id (as stored in the database), rather than NAS-Port.
+
+ Feature improvements
+ * Add "max_retries" for connection pools. Fixes #4908. Patch from Nick Porter.
+ * Update dictionary.ciena, dictionary.huawei, dictionary.wifialliance and
+ dictionary.wispr; add dictionary.eleven.
+ * You can now list "eap" in the "pre-proxy" section. If the packet
+ contains a malformed EAP message, then the request will be rejected.
+ The home server will either reject (or discard) this packet anyways,
+ so this change can only help with large proxy scenarios.
+ * Show warnings if libldap is not using OpenSSL.
+ * Support RADIUS/1.1. See https://datatracker.ietf.org/doc/draft-dekok-radext-radiusv11/
+ Disabled by default, can be enabled by passing `--with-radiusv11` to the
+ configure script. For now, this is for testing interoperability.
+ * Add extra sanity checks for malformed EAP attributes.
+ * More TLS debugging output
+ * Clear old module instance data before HUP reload. Avoids burst memory use
+ when e.g. using large data files with rlm_files. Patch from Nick Porter.
+ * `rlm_cache_redis` is now included in the freeradius-redis packages.
+ * Separate out python2/python3 in Debian Packages. Previously python 2 or 3
+ was built depending on the system default which led to confusion. We now build
+ both freeradius-python2 and freeradius-python3 packages where possible.
+
+ Bug fixes
+ * Don't leak MD contexts with OpenSSL 3.0.
+ * Increase internal buffer size for TLS connections, which
+ can help with high-load proxies.
+ * Send Status-Server checks for TLS connections
+ * Give descriptive error if "update CoA" is used with "fake" packets,
+ as it won't work. i.e. inner-tunnel and virtual home servers.
+ * Many small ASAN / LSAN fixes from Jorge Pereira.
+ * Close inbound RADIUS/TLS socket on TLS errors. When a home server
+ sees a TLS error, it will now close the socket, so proxies do not
+ have an open (but dead) TLS connection.
+ * Fix mutex locking issues on inbound RADIUS/TLS connections.
+ This change avoids random issues with "bad record mac".
+ * Improve REST encoding loop. Patch from Herwin Weststrate. Closes #4950
+ * Correctly report the LDAP group a user was found in. Fixes #3084.
+ Patch from Nick Porter.
+ * Force correct packet type when running Post-Auth-Type. Helps with #4980
+ * Fix small leak in Client-Lost code. Patch from Terry Burton. PR #4996
+ * Fix TCP socket statistics. Closes #4990
+ * Use NAS-Port-Id instead of NAS-Port during SQL simultaneous-use
+ checks. Helps with #5010
+
+FreeRADIUS 3.2.2 Thu 16 Feb 2023 12:00:00 EDT urgency=low
+ Configuration changes
+ * The linelog module now has a "header" configuration item,
+ which places a header in any new file it creates.
+ * The ldap module now supports setting "cipher_list". See
+ mods-available/ldap.
+ * Add "connect_timeout" for outgoing TLS sockets. Helps with #3501.
+ * Add config section for xlats in rlm_rest and an option to
+ control REST body data encoding. Patches by Nick Porter.
+ * Allow Operator-Name and Called-Station-Id in attr_filter when
+ proxying. Helps with less work in Eduroam configurations.
+ * Ensure that the AcctUpdateTime field in SQL is always updated.
+ This is so that we can track when the last packet arrived.
+ * Update the default configuration to reply to NAS when accounting
+ proxying fails, but we still write to the detail file.
+
+ Feature improvements
+ * The "configure" process now gives a much clearer report
+ when it's finished. Patches by Matthew Newton.
+ * Fallback to "uname -n" on missing "hostname". Fixes #4771
+ * Export thread details in radmin "stats threads". Fixes #4770
+ * Improve queries for processing radacct into periodic usage data.
+ Fix from Nick Porter.
+ * Update dictionary.juniper
+ * Add dictionary.calix
+ * Fix dictionary.rfc6519 DS-Lite-Tunnel-Name to be "octets"
+ * Update documentation for robust-proxy-accounting, and be more
+ aggressive about sending packets.
+ * Add per-module README.md files in the source.
+ * Add default Visual Studio configuration for developers.
+ * Postgres can now automatically use alternate queries for errors
+ other than duplicate keys.
+ * %{listen:TLS-PSK-Identity} is now set when using PSK and psk_query
+ This helps the server track the identity of the client which is
+ connecting.
+ * Include thread stats in Status-Server attributes. Fixes #4870.
+ * Mark rlm_unbound stable and add to packages. Patches by Nick Porter.
+ * Remove broken/unsupported Dockerfiles for centos8 and
+ debian9.
+ * Ensure Docker containers have stable uid/gid. Patches
+ from Terry Burton.
+
+ Bug fixes
+ * Preliminary support for non-blocking TLS sockets. Helps with #3501.
+ * Fix support for partial certificate chains after adding reload
+ support. Fixes #4753
+ * Fix handling of debug_condition.
+ * Clean up home server states, and re-sync with the dictionaries.
+ * Correct certificate order when creating TLS-* attributes.
+ Fixes #4785
+ * Update use of isalpha() etc. so broken configurations have less
+ impact on the server.
+ * Outgoing TLS sockets now set SNI correctly from the "hostname"
+ configuration item.
+ * Support Apple Homebrew on the M1. Fixes #4754
+ * Better error messages when %{listen:TLS-...} is used.
+ * Getting statistics via Status-Server can now be done within a
+ virtual server. Fixes #4868
+ * Make TTLS+MS-CHAP work with TLS 1.3. Fixes #4878.
+ * Fix md5 xlat memory leak when using OpenSSL 3. Fix by Terry Burton.
+
+FreeRADIUS 3.2.1 Mon 03 Oct 2022 12:00:00 EDT urgency=low
+ Feature improvements
+ * Add dictionary.ciena, dictionary.nile, and DHCPv4 dictionaries.
+ * Add simultaneous-use queries for MS SQL.
+ * Add radmin command for "stats pool <module-name>"
+ Which prints out statistics about the connection pools
+ * Client statistics now shows "conflicts", to count conflicting
+ packets.
+ * New optional "lightweight accounting-on/off" strategy. When
+ refreshing queries.conf you should also add the new nasreload table
+ and corresponding GRANTs to your DB schema.
+ * Add TLS-Client-Cert-X509v3-Certificate-Policies, which helps with
+ Eduroam. Suggested by Stefan Winter.
+ * Allow auth+acct for TCP sockets, too.
+ * Add rlm_cache_redis. See raddb/mods-available/cache for details
+ * Allow radmin to look up home servers by name, too.
+ * Ensure that dynamic clients don't create loops on duplicates.
+ Reported by Sam Yee.
+ * Removed rlm_sqlhpwippool. There was no documentation, no configuration,
+ and the module was ~15 years old with no one using it.
+ * Marked rlm_python3 as stable.
+ * Add sigalgs_list. See raddb/mods-available/eap. Patch from
+ Boris Lytochkin.
+ * For rlm_linelog, when opening files in /dev, look at "permissions" to see
+ whether to open them r/w.
+ * More flexibility for dynamic home servers. See doc/configuration/dynamic_home_servers.md
+ and raddb/home_servers/README.md
+ * Allow setting of application_name for PostgreSQL. See mods-available/sql.
+
+ Bug fixes
+ * Correct test for open sessions in radacct for MS SQL.
+ * The linelog module now opens /dev/stdout in "write-only" mode
+ if the permissions are set to "u+w" (0002).
+ * Various fixes to rlm_unbound from Nick Porter.
+ * PEAP now correctly runs Post-Auth-Type Accept
+ * Create "TLS-Cert-*" for outbound Radsec, instead of TLS-Client-Cert-*
+ Fixes #4698. See sites-available/tls, and fix_cert_order.
+ * Minor updates and fixes to CI, Dockerfiles and packaging.
+ * Fix rlm_python3 build with python >= 3.10. Fixes #4441
+
+FreeRADIUS 3.2.0 Thu 21 Apr 2022 12:00:00 EDT urgency=low
+ Configuration changes
+ * "correct_escapes" has been removed, and is always set to "true"
+ internally. Configuration changes may be required if you are
+ using configurations from before 3.0.5. Other than this
+ difference, 3.2.x is compatible with 3.0.x, and configurations
+ from 3.0.x can be simply copied into a system running 3.2.x.
+
+ Feature improvements
+ * All features from 3.0.x are included in the 3.2.x releases. In addition:
+ * Support PEAP and TTLS with TLS 1.3. This has been
+ tested with wpa_supplicant and Windows 11.
+ * Add 'reset_day' and '%%r' parameter for rlm_sqlcounter to specify which
+ day of the month the counter should be reset.
+ * Partial backport of rlm_json from v4, providing the json_encode xlat.
+ See mods-available/json for documentation.
+ * Support for haproxy "PROXY" protocol.
+ See sites-available/tls, "proxy_protocol" and doc/antora/modules/howto/pages/protocols/proxy/
+ * Support for sending CoA-Request and Disconnect-Request packets
+ in "reverse" down RadSec tunnels. Experimental for now, and
+ undocumented.
+ * It is now possible to run a virtual server when saving / loading
+ TLS cache attributes. See sites-available/tls-cache for
+ more information.
+ * Removed the "cram" module. It was undocumented, and used old
+ and insecure authentication methods.
+ * Remove the "otp" module. The "otpd" program it needs is no longer available,
+ and the module has not been usable since at least 2015.
+ * All features from 3.0.x are included in the 3.2.x releases.
+ * 3.2.0 requires OpenSSL 1.0.2 or greater.
+
+ Bug fixes
+ * All bug fixes from 3.0.x are included in the 3.2.x releases.
diff --git a/doc/Makefile.sphinx b/doc/Makefile.sphinx
new file mode 100644
index 0000000..235ba9d
--- /dev/null
+++ b/doc/Makefile.sphinx
@@ -0,0 +1,95 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS =
+SPHINXBUILD = sphinx-build
+PAPER =
+BUILDDIR = _build
+
+# Internal variables.
+PAPEROPT_a4 = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+.PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest
+
+help:
+ @echo "Please use \`make <target>' where <target> is one of"
+ @echo " html to make standalone HTML files"
+ @echo " dirhtml to make HTML files named index.html in directories"
+ @echo " pdf to make standalone PDF files"
+ @echo " pickle to make pickle files"
+ @echo " json to make JSON files"
+ @echo " htmlhelp to make HTML files and a HTML help project"
+ @echo " qthelp to make HTML files and a qthelp project"
+ @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+ @echo " changes to make an overview of all changed/added/deprecated items"
+ @echo " linkcheck to check all external links for integrity"
+ @echo " doctest to run all doctests embedded in the documentation (if enabled)"
+
+clean:
+ -rm -rf $(BUILDDIR)/*
+
+html:
+ $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dirhtml:
+ $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+pdf:
+ $(SPHINXBUILD) -b pdf $(ALLSPHINXOPTS) _build/pdf
+ @echo
+ @echo "Build finished. The PDFs are in _build/pdf."
+
+pickle:
+ $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+ @echo
+ @echo "Build finished; now you can process the pickle files."
+
+json:
+ $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+ @echo
+ @echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+ $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+ @echo
+ @echo "Build finished; now you can run HTML Help Workshop with the" \
+ ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+qthelp:
+ $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+ @echo
+ @echo "Build finished; now you can run "qcollectiongenerator" with the" \
+ ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+ @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/FreeRADIUS.qhcp"
+ @echo "To view the help file:"
+ @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/FreeRADIUS.qhc"
+
+latex:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo
+ @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+ @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \
+ "run these through (pdf)latex."
+
+changes:
+ $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+ @echo
+ @echo "The overview file is in $(BUILDDIR)/changes."
+
+linkcheck:
+ $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+ @echo
+ @echo "Link check complete; look for any errors in the above output " \
+ "or in $(BUILDDIR)/linkcheck/output.txt."
+
+doctest:
+ $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+ @echo "Testing of doctests in the sources finished, look at the " \
+ "results in $(BUILDDIR)/doctest/output.txt."
diff --git a/doc/README b/doc/README
new file mode 100644
index 0000000..7801c90
--- /dev/null
+++ b/doc/README
@@ -0,0 +1,181 @@
+1. INTRO
+
+ The FreeRADIUS Server Project is a high performance and highly
+ configurable multi-protocol policy server, supporting RADIUS, DHCPv4
+ and VMPS. It is available under the terms of the GNU GPLv2.
+
+ All code in this server was written for this project.
+
+
+2. INSTALLATION
+
+ See the INSTALL file, in the parent directory.
+
+
+3. CONFIGURATION FILES
+
+ Much of the server documentation is included only in the comments in the
+ configuration files. Reading the configuration files is REQUIRED to fully
+ understand how to create complex configurations of the server.
+
+3a. 'clients.conf'
+
+ Make sure the clients (NAS, switches, access points etc) are set up to
+ use the host radiusd is running on as authentication and accounting host.
+ Configure these clients with a "radius secret", which should also be
+ entered into the client definition in /etc/raddb/clients.conf.
+ See also the manual page for clients.conf(5).
+
+3b. 'users'
+
+ Users may be defined in the "users" file (raddb/mods-config/files/authorize).
+ All entries are processed in the order as they appear in the file.
+ If an entry matches the username, radiusd will stop scanning the users
+ file (unless the attribute "Fall-Through = Yes" is set).
+
+ You can uses spaces in usernames by escaping them with \ or by using
+ quotes. For example, "joe user" or joe\ user.
+
+ The 'users' file is read by the "rlm_files" module.
+
+3c. NEW RADIUS ATTRIBUTES (to be used in the USERS file).
+
+ Name Type Descr.
+ ---- ---- ------
+ Simultaneous-Use integer Max. number of concurrent logins
+ Fall-Through integer Yes/No
+ Login-Time string Defines when user may login.
+ Current-Time string Allows you to perform time-based
+ checks when a request is received.
+
+ Login-Time defines the time span a user may login to the system. The
+ format of a so-called time string is like the format used by UUCP.
+ A time string may be a list of simple time strings separated by "|" or ",".
+
+ Each simple time string must begin with a day definition. That can be just
+ one day, multiple days, or a range of days separated by a hyphen. A
+ day is Mo, Tu, We, Th, Fr, Sa or Su, or Wk for Mo-Fr. "Any" or "Al"
+ means all days.
+
+ After that a range of hours follows in hhmm-hhmm format.
+
+ For example, "Wk2305-0855,Sa,Su2305-1655".
+
+ radiusd calculates the number of seconds left in the time span, and
+ sets the Session-Timeout to that number of seconds. So if someones
+ Login-Time is "Al0800-1800" and she logs in at 17:30, Session-Timeout
+ is set to 1800 seconds so that she is kicked off at 18:00.
+
+
+4. LOG FILES
+
+4a. /var/log/radius/radutmp
+
+ In this file the currently logged in users are held. The program "radwho"
+ reads this file and gives you a summary. Rogue sessions can be deleted
+ from this file with the "radzap" program.
+
+4b. /var/log/radius/radwtmp
+
+ This file is "wtmp" compatible and keeps a history of all radius logins/
+ logouts. This file can be read with the "last" program, and other Unix
+ accounting programs (such as "ac" and "sac") can be used to produce a
+ summary.
+
+4c. /var/log/radius/radius.log
+
+ All RADIUS informational, diagnostic and error messages are logged in
+ this file, including all login attempts.
+
+4d. /var/log/radius/radacct/<client_ip>/detail
+
+ This is the original radius logfile, as written by all the Livingston
+ radius servers. It's only created if the directory
+ /var/log/radius/radacct exists.
+
+ For more configuration options on the detail file please see
+ raddb/mods-available/detail as it expands upon this greatly.
+
+
+5. MORE INFO, SUPPORT
+
+ The latest version of FreeRADIUS is always available from
+ the git repository hosted on GitHub at
+
+ https://github.com/FreeRADIUS/freeradius-server
+
+ or see
+
+ http://freeradius.org/git/
+
+ for more information.
+
+ There are two mailing lists for users and developers. General
+ user, administrator and configuration issues should be discussed
+ on the users list at:
+
+ http://lists.freeradius.org/mailman/listinfo/freeradius-users
+
+ When asking for help on the users list, be sure the include a
+ detailed and clear description of the problem, together with
+ full debug output from FreeRADIUS, obtained by running
+
+ radiusd -X
+
+ Developers only discussion is to be had on the devel list:
+
+ http://lists.freeradius.org/mailman/listinfo/freeradius-devel
+
+ Please do not raise general configuration issues here.
+
+
+6. OTHER INFORMATION
+
+ The files in other directories are:
+
+ debian/ Files to build Debian Linux packages.
+
+ doc/ Various snippets of documentation
+ doc/rfc/ Copies of the RFC's. If you have Perl, do a 'make' in
+ that directory, and look at the HTML output.
+
+ man/ Unix Manual pages for the server, configuration files,
+ and associated utilities.
+
+ mibs/ SNMP Mibs for the server.
+
+ raddb/ Default configuration files for the server.
+
+ redhat/ Files to build RedHat RPM packages.
+
+ scripts/ Sample scripts for startup and maintenance.
+
+ share/ Attribute dictionaries.
+
+ src/ Source code
+ src/main source code for the daemon and associated utilities
+ src/lib source code for the RADIUS library
+ src/include header files
+ src/modules dynamic plug-in modules
+ src/tests test harness used by "make test"
+
+ suse/ Files to build SuSE RPM packages.
+
+
+ If you have ANY problems, concerns, or surprises when running
+ the server, then run it in debugging mode, as root, from the
+ command line:
+
+ # radiusd -X
+
+ It will produce a large number of messages. The answers to many
+ questions, and the solution to many problems, can usually be found in
+ these messages.
+
+ For further details, see:
+
+ https://freeradius.org/documentation/
+
+ and the 'bugs' file, in this directory.
+
+$Date$
diff --git a/doc/all.mk b/doc/all.mk
new file mode 100644
index 0000000..1a88f52
--- /dev/null
+++ b/doc/all.mk
@@ -0,0 +1,55 @@
+ifneq "$(docdir)" "no"
+install: install.doc
+
+clean: clean.doc
+
+DOCDIRS := $(patsubst doc/%,$(R)$(docdir)/%,$(filter-out doc/source%,$(shell find doc -type d)))
+DOCFILES := $(filter-out %~ %/all.mk %.gitignore doc/rfc/update.sh doc/source/%,$(shell find doc -type f))
+DOCINSTALL := $(patsubst doc/%,$(R)$(docdir)/%,$(DOCFILES))
+
+# Create the directories
+$(DOCDIRS):
+ @echo INSTALL $(patsubst $(R)$(docdir)/%,doc/%,$@)
+ @$(INSTALL) -d -m 755 $@
+
+# Files depend on directories (order only).
+# We don't care if the directories change.
+$(DOCINSTALL): | $(DOCDIRS)
+
+# Wildcard installation rule
+$(R)$(docdir)/%: doc/% | $(dir $@)
+ @echo INSTALL $<
+ @$(INSTALL) -m 644 $< $@
+
+install.doc: $(DOCINSTALL)
+
+.PHONY: clean.doc
+clean.doc:
+ @rm -rf doc/*~ doc/rfc/*~ build/docsite
+
+#
+# Deal with these later
+#
+DOCRST := $(wildcard *.rst)
+%.html: %.rst
+ @rst2html.py $^ > $@
+
+.PHONY: html
+html: $(DOCRST:.rst=.html)
+
+#
+# antora rebuilds the entire documentation site on each run
+# so we need to pick a single file to compare dependency
+# timestamps against.
+#
+# we use sitemap.xml as it'll be regenerated on every antora
+# run.
+#
+build/docsite/sitemap.xml: $(ADOC_FILES)
+ @echo ANTORA site.yml
+ ${Q}$(ANTORA) $(ANTORA_FLAGS) site.yml
+
+
+docsite: build/docsite/sitemap.xml
+
+endif
diff --git a/doc/antora/antora.yml b/doc/antora/antora.yml
new file mode 100644
index 0000000..e345e9c
--- /dev/null
+++ b/doc/antora/antora.yml
@@ -0,0 +1,18 @@
+#
+# Metadata for the freeradius-server component
+# Examples of other components are the PAM module,
+# apache module, and the client library.
+#
+name: freeradius-server
+title: The FreeRADIUS Server
+version: '3.2.3'
+start_page: ROOT:index.adoc
+nav:
+- modules/ROOT/nav.adoc
+- modules/installation/nav.adoc
+- modules/concepts/nav.adoc
+- modules/howto/nav.adoc
+- modules/tutorials/nav.adoc
+- modules/unlang/nav.adoc
+- modules/developers/nav.adoc
+- modules/raddb/nav.adoc
diff --git a/doc/antora/modules/ROOT/assets/images/favicon.png b/doc/antora/modules/ROOT/assets/images/favicon.png
new file mode 100644
index 0000000..8c71104
--- /dev/null
+++ b/doc/antora/modules/ROOT/assets/images/favicon.png
Binary files differ
diff --git a/doc/antora/modules/ROOT/assets/images/favicon.svg b/doc/antora/modules/ROOT/assets/images/favicon.svg
new file mode 100644
index 0000000..7476355
--- /dev/null
+++ b/doc/antora/modules/ROOT/assets/images/favicon.svg
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 19.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 160 160" style="enable-background:new 0 0 160 160;" xml:space="preserve">
+<style type="text/css">
+ .st0{fill:none;stroke:#FFD62B;stroke-width:3;stroke-miterlimit:10;}
+ .st1{fill:#B0C3C6;}
+ .st2{fill:none;stroke:#DEE7E8;stroke-miterlimit:10;}
+ .st3{fill:#00A6E2;}
+ .st4{fill:none;stroke:#B0C3C6;stroke-width:2;stroke-miterlimit:10;}
+ .st5{fill:#666666;}
+ .st6{fill:none;stroke:#B0C3C6;stroke-width:2;stroke-linejoin:round;stroke-miterlimit:10;}
+ .st7{fill:#00C9ED;}
+ .st8{fill:#FFFFFF;stroke:#B0C3C6;stroke-width:2;stroke-linejoin:round;stroke-miterlimit:10;}
+ .st9{fill:#303030;}
+ .st10{opacity:0.4;fill:#F6F6F6;}
+ .st11{fill:none;stroke:#999999;stroke-width:2;stroke-miterlimit:10;}
+ .st12{fill:#999999;}
+ .st13{fill:#FFFFFF;}
+ .st14{clip-path:url(#SVGID_2_);fill:#2F3537;}
+ .st15{opacity:0.3;fill:none;stroke:#9FB1B3;stroke-width:2;stroke-miterlimit:10;}
+ .st16{fill:none;stroke:#FFFFFF;stroke-miterlimit:10;}
+ .st17{fill:#FFFFFF;stroke:#FFFFFF;stroke-miterlimit:10;}
+ .st18{fill:none;stroke:#303030;stroke-miterlimit:10;}
+ .st19{opacity:0.8;fill:#B0C3C6;}
+ .st20{opacity:0.7;}
+ .st21{opacity:0.8;clip-path:url(#SVGID_4_);fill:#00A6E2;}
+ .st22{opacity:0.8;fill:#00A6E2;}
+ .st23{opacity:0.8;clip-path:url(#SVGID_6_);fill:#00A6E2;}
+ .st24{clip-path:url(#SVGID_8_);}
+ .st25{clip-path:url(#SVGID_10_);}
+ .st26{fill:none;stroke:#B0C3C6;stroke-width:3;stroke-linejoin:round;stroke-miterlimit:10;}
+ .st27{opacity:0.3;fill:none;stroke:#9FB1B3;stroke-width:3;stroke-miterlimit:10;}
+ .st28{fill:#FFFFFF;stroke:#B0C3C6;stroke-width:3;stroke-linejoin:round;stroke-miterlimit:10;}
+ .st29{clip-path:url(#SVGID_12_);fill:#2F3537;}
+ .st30{clip-path:url(#SVGID_14_);fill:#B0C3C6;}
+ .st31{fill:#33B8E8;}
+ .st32{fill:#238DB4;}
+ .st33{fill:#E2E7E8;}
+ .st34{clip-path:url(#SVGID_16_);}
+ .st35{fill:#FFFFFF;stroke:#B0C3C6;stroke-width:2;stroke-miterlimit:10;}
+ .st36{fill:#B4CBCE;}
+ .st37{fill:#003147;}
+ .st38{fill:#FFD62B;}
+ .st39{fill:#00B78E;}
+ .st40{fill:#FF7824;}
+ .st41{fill:#FF3223;}
+ .st42{fill:#7955DF;}
+ .st43{fill:none;stroke:#FF3223;stroke-width:2;stroke-miterlimit:10;}
+ .st44{fill:none;stroke:#00A6E2;stroke-width:2;stroke-miterlimit:10;}
+ .st45{clip-path:url(#SVGID_18_);fill:#303030;}
+ .st46{fill:#F5C81F;}
+ .st47{fill:#F49F90;}
+ .st48{fill:#F3EEDE;}
+ .st49{fill-rule:evenodd;clip-rule:evenodd;fill:#FFFFFF;}
+ .st50{fill:#00131F;}
+ .st51{clip-path:url(#SVGID_20_);fill:#303030;}
+ .st52{fill:none;stroke:#FFFFFF;stroke-width:2;stroke-miterlimit:10;}
+ .st53{clip-path:url(#SVGID_22_);fill:#303030;}
+ .st54{clip-path:url(#SVGID_24_);fill:#303030;}
+</style>
+<path class="st0" d="M72.3,25.6c0,0-2.3-3.2-6-2.3"/>
+<g>
+ <polygon class="st50" points="79.2,73 20.3,37.9 86.2,19.3 145.1,54.4 "/>
+ <g>
+ <g>
+ <g>
+ <g>
+ <path class="st3" d="M126.2,113.6c-4.4,0-8.2-3-9.3-7.1c2.8,1,5.7,1.6,8.8,1.6c4.4,0,7.9-3.5,7.9-7.9c0-4.4-3.5-7.9-7.9-7.9
+ c-5.3,0-9.9-4.3-9.9-9.6c0-0.7,0-2.1,0-2.1v-6.1c0-19.4-15.7-35.2-35.2-35.2c-19.4,0-35.2,15.7-35.2,35.2v6.1c0,0,0,1.3,0,2.1
+ c0,5.3-4.6,9.6-9.9,9.6c-4.4,0-7.9,3.5-7.9,7.9c0,4.4,3.5,7.9,7.9,7.9c3.5,0,6.8-0.7,9.8-2c-1,4.3-4.8,7.5-9.4,7.5
+ c-4.4,0-7.9,3.5-7.9,7.9c0,4.4,3.5,7.9,7.9,7.9c6.9,0,13.2-2.8,17.8-7.3v10.4c0,4.4,3.5,7.9,7.9,7.9c4.4,0,7.9-3.5,7.9-7.9
+ v-14.8h3.1v18.7c0,4.4,3.5,7.9,7.9,7.9c4.4,0,7.9-3.5,7.9-7.9v-18.7h3.1v14.8c0,4.4,3.5,7.9,7.9,7.9c4.4,0,7.9-3.5,7.9-7.9
+ v-11.4c4.7,5.1,11.3,8.2,18.7,8.2c4.4,0,7.9-3.5,7.9-7.9C134.1,117.1,130.5,113.6,126.2,113.6z"/>
+ <g>
+ <circle class="st13" cx="80" cy="76.9" r="17.5"/>
+ <g>
+ <defs>
+ <circle id="SVGID_19_" cx="80" cy="76.9" r="17.5"/>
+ </defs>
+ <use xlink:href="#SVGID_19_" style="overflow:visible;fill:#FFFFFF;"/>
+ <clipPath id="SVGID_2_">
+ <use xlink:href="#SVGID_19_" style="overflow:visible;"/>
+ </clipPath>
+ <path style="clip-path:url(#SVGID_2_);fill:#303030;" d="M73.3,85.5c-6.7,0-12.2-5.5-12.2-12.2c0-6.7,5.5-12.2,12.2-12.2
+ s12.2,5.5,12.2,12.2C85.5,80,80.1,85.5,73.3,85.5z"/>
+ </g>
+ </g>
+ </g>
+ </g>
+ </g>
+ </g>
+ <g>
+ <path class="st50" d="M46,65.8c0-19.1,15.5-29.7,34.6-29.7s34.6,10.6,34.6,29.7c0,0-9.6-9.8-34.2-9.8S46,65.8,46,65.8z"/>
+ </g>
+ <g>
+ <path class="st0" d="M66.3,23.3c0,0-10.7,2.8-10.2,9.7v20.8"/>
+ <line class="st0" x1="56" y1="53.7" x2="59.3" y2="66"/>
+ <line class="st0" x1="56" y1="53.7" x2="54" y2="64.7"/>
+ <line class="st0" x1="56" y1="53.7" x2="62" y2="59.2"/>
+ <line class="st0" x1="56" y1="53.7" x2="50.8" y2="60.4"/>
+ </g>
+</g>
+</svg>
diff --git a/doc/antora/modules/ROOT/assets/images/networkradius.png b/doc/antora/modules/ROOT/assets/images/networkradius.png
new file mode 100644
index 0000000..bf1ea80
--- /dev/null
+++ b/doc/antora/modules/ROOT/assets/images/networkradius.png
Binary files differ
diff --git a/doc/antora/modules/ROOT/nav.adoc b/doc/antora/modules/ROOT/nav.adoc
new file mode 100644
index 0000000..3d92412
--- /dev/null
+++ b/doc/antora/modules/ROOT/nav.adoc
@@ -0,0 +1 @@
+* xref:index.adoc[Introduction]
diff --git a/doc/antora/modules/ROOT/pages/directories.adoc b/doc/antora/modules/ROOT/pages/directories.adoc
new file mode 100644
index 0000000..9b16249
--- /dev/null
+++ b/doc/antora/modules/ROOT/pages/directories.adoc
@@ -0,0 +1,69 @@
+= Directories
+
+The directories in the server source are laid out ad follows:
+
+== Documentation
+
+[width="100%",cols="50%,50%",options="header",]
+|===
+| Directory | Description
+| `doc/` | Various snippets of documentation.
+| `doc/introduction/` | Concepts and introduction to FreeRADIUS.
+| `doc/raddb/` | HTML versions of the configuration files.
+| `doc/developers/` | Developer documentation for internal APIs
+| `doc/unlang/` | The unlang processing language.
+| `doc/upgrade/` | How to upgrade from version 3 to version 4.
+| `doc/rfc/` | Copies of the RFC’s. If you have Perl, do a `make` in
+ that directory, and look at the HTML output.
+| `doc/antora/` | Metadata and documentation source files to build
+ an Antora based documentation site.
+| `doc/doxygen/` | Files to build a Doxygen site from the source code.
+| `man/` | Unix Manual pages for the server, configuration files,
+ and associated utilities.
+|===
+
+== Utility
+
+[cols=",",options="header",]
+|===
+|Directory | Description
+| `mibs/` | SNMP Mibs for the server.
+| `scripts/` | Sample scripts for startup and maintenance.
+|===
+
+== Configuration
+
+[width="100%",cols="50%,50%",options="header",]
+|===
+| Directory | Description
+| `raddb/` | Sample configuration files for the server.
+| `raddb/mods-available` | Module configuration files.
+| `raddb/mods-enabled` | Directory containing symlinks to `raddb/mods-available`.
+ Controls which modules are enabled.
+| `raddb/sites-available` | Virtual servers.
+| `raddb/sites-enabled` | Directory containing symlinks to `raddb/sites-available`.
+ Control which virtual servers are enabled.
+|===
+
+== Packaging
+
+[cols=",",options="header",]
+|===
+|Directory | Description
+| `debian/` | Files to build a `freeradius` Debian Linux package.
+| `redhat/` | Additional files for a RedHat Linux system.
+| `suse/` | Additional files for a SuSE (UnitedLinux) system.
+|===
+
+== Source
+
+[cols=",",options="header",]
+|===
+|Directory | Description
+| `src/` | Source code.
+| `src/bin/` | Source code for the daemon and associated utilities.
+| `src/lib/` | Source code for various utility libraries.
+| `src/include/` | Header files.
+| `src/protocols/` | Dynamic frontend plug-in modules.
+| `src/modules/` | Dynamic backend plug-in modules.
+|===
diff --git a/doc/antora/modules/ROOT/pages/index.adoc b/doc/antora/modules/ROOT/pages/index.adoc
new file mode 100644
index 0000000..e9bc7a0
--- /dev/null
+++ b/doc/antora/modules/ROOT/pages/index.adoc
@@ -0,0 +1,137 @@
+= Introduction
+
+This is the documentation for FreeRADIUS, version 3. The documentation
+is available under the Creative Commons Non-Commercial license, as given
+in the `LICENSE` file in this directory.
+
+FreeRADIUS is a complex piece of software with many configuration
+options. However, we have taken great care to make the default
+configuration work in most circumstances. The result is that for most
+simple systems, it is trivial to install and configure the server. For
+those situations, this documentation will serve to answer basic
+questions about functionality, configuration, etc.
+
+For more complex requirements, FreeRADIUS can be difficult to
+configure. The reason for this difficulty is that the server can do
+almost anything, which means that there are a near-infinite number of
+ways to configure it. The question for an administrator, then, is what
+piece of the configuration to change, and how to change it.
+
+This documentation will answer those questions. The FreeRADIUS team has
+put substantial effort into writing the documentation for this release.
+Everything in the server is fully documented, and there are many
+`how-to` guides available.
+
+The documentation is split into sections by subject area, oganized by
+desired outcome. At a high level, the subject areas describe:
+
+* xref:concepts:index.adoc[Concepts] and introduction for newcomers.
+* xref:installation:index.adoc[Installing] and xref:installation:upgrade.adoc[upgrading] FreeRADIUS.
+* The syntax of the xref:unlang:index.adoc[unlang] processing language.
+* The xref:raddb:index.adoc[configuration files] located in `/etc/raddb/`, or `/etc/freeradius/`
+* Various xref:howto:index.adoc[how-to] guides.
+* xref:developers:index.adoc[Developer documentation].
+
+This organization means that for example, the `ldap` module will have
+documention located in multiple places. We feel that organizing the
+documentation by desired _goal_ is better than the alternatives.
+
+Within each section, the documentation is split into small pages, which
+are generally no more than a few screens worth of information. We feel
+that having multiple small pages with cross-links is more helpful than
+having a smaller number of enormous pages. This division ensures that
+(for example) the `how-to` guides are split into a series of small
+steps, each of which can be performed quickly.
+
+We hope that this extended documentation will address any lingering
+concerns about the quality of the FreeRADIUS documentation.
+
+== Changes From Earlier Versions
+
+Administrators who have version 2 and wish to upgrade to version 3
+should read the xref:installation:upgrade.adoc[upgrading] documentation.
+That documentation explains the differences between the two versions, and
+how an existing configuration can be reproduced in the latest
+release. We do _not_ recommend using version 2 configuration files
+with version 3. The configuration files are _not_ compatible across a
+major version upgrade.
+
+== Getting Started with FreeRADIUS
+
+FreeRADIUS can be installed using the pre-built packages available
+from http://packages.networkradius.com[Network RADIUS,
+window="_blank"]. That page contains packages for all common OS
+distributions. New packages are available as soon as a new version
+has been released. Packages for older releases are also available for
+historical purposes.
+
+FreeRADIUS can also be installed from the source code. Please see the
+xref:installation:index.adoc[installation guide] for instructions.
+
+WARNING: Many Operating System distributions ship versions of FreeRADIUS
+which are years out of date. Those versions may contain bugs which have
+been fixed in newer releases. We recommend using the
+http://packages.networkradius.com[Network RADIUS, window="_blank"] packages where
+possible.
+
+Administrators who are new to FreeRADIUS should read the
+xref:concepts:index.adoc[concepts section] as it describes the concepts behind
+FreeRADIUS. It is vital for newcomers to understand these concepts, as the rest
+of the documentation assumes familiarity with them.
+
+A detailed xref:unlang:index.adoc[unlang] reference guide is also available.
+This section describes the syntax and functionality of the keywords,
+data types, etc. used in the `unlang` processing language.
+
+All of the xref:raddb:index.adoc[configuration files] are available in
+hypertext format. In can often be easier to read the configuration files
+in a nicely formatted version, instead of as a fixed-width font in a
+text editor.
+
+For specific problem solving, we recommend the xref:howto:index.adoc[how-to]
+guides. These guides give instructions for reaching high-level goals, or
+for configuring and testing individual xref:howto:modules/index.adoc[modules].
+
+There is also xref:developers:index.adoc[developer documentation]. This section
+documents the APIs for developers. Most people can ignore it.
+
+== Debugging
+
+If you have ANY problems, concerns, or surprises when running the
+server, the the server should be run in debugging mode as root, from the
+command line:
+
+```
+# radiusd -X
+```
+
+It will produce a large number of messages. The answers to many
+questions, and the solution to many problems, can usually be found in
+these messages. When run in a terminal window, error messages will be
+shown in red text, and warning messages will be shown in yellow text.
+
+For other use-cases, please look for `ERROR` or `WARNING` in the
+debug output. In many cases, those messages describe exactly what is
+going wrong, and how to fix it.
+
+For further details, about the debug output see the
+http://wiki.freeradius.org/radiusd-X[radiusd-X, window="_blank"] page on the
+http://wiki.freeradius.org[wiki, window="_blank"].
+
+== Getting Help
+
+We also recommend joining the
+http://lists.freeradius.org/mailman/listinfo/freeradius-users[mailing
+list] in order to ask questions and receive answers. The developers are
+not on Stack Overflow, IRC, or other web sites. While the FreeRADIUS
+source is available on
+https://github.com/FreeRADIUS/freeradius-server/[GitHub, window="_blank"], questions
+posted there will not be answered.
+
+Before posting to the list, please read the
+http://wiki.freeradius.org/list-help[list help, window="_blank"] page. That page explains
+how to run the server in debugging mode; how to understand the debug
+output; and what information to post to the list.
+
+Commercial support for FreeRADIUS is available from
+https://networkradius.com/freeradius-support/[Network RADIUS, window="_blank"].
diff --git a/doc/antora/modules/howto/nav.adoc b/doc/antora/modules/howto/nav.adoc
new file mode 100644
index 0000000..351200b
--- /dev/null
+++ b/doc/antora/modules/howto/nav.adoc
@@ -0,0 +1,19 @@
+* xref:index.adoc[Howto Guides]
+** Protocols
+**** xref:protocols/dhcp/index.adoc[DHCP]
+***** xref:protocols/dhcp/prepare.adoc[Preparation]
+***** xref:protocols/dhcp/enable.adoc[Enabling the DHCP service]
+***** xref:protocols/dhcp/test.adoc[Testing the DHCP service]
+***** xref:protocols/dhcp/policy.adoc[Defining the DHCP policy]
+****** xref:protocols/dhcp/policy_ippool_creation.adoc[IP pool creation]
+****** xref:protocols/dhcp/policy_common_options.adoc[Common options]
+****** xref:protocols/dhcp/policy_network_options.adoc[Network options and IP pool selection]
+****** xref:protocols/dhcp/policy_subnet_options.adoc[Subnet options]
+****** xref:protocols/dhcp/policy_device_options.adoc[Device, class and group options]
+****** xref:protocols/dhcp/policy_ippool_access.adoc[IP pool access restriction]
+**** xref:protocols/proxy/index.adoc[PROXY Protocol]
+***** xref:protocols/proxy/enable_radsec.adoc[Enabling RadSec]
+***** xref:protocols/proxy/radsec_client.adoc[Configuring a test RadSec client]
+***** xref:protocols/proxy/radsec_with_haproxy.adoc[Proxying RadSec with HAproxy]
+***** xref:protocols/proxy/radsec_with_traefik.adoc[Proxying RadSec with Traefik]
+***** xref:protocols/proxy/enable_proxy_protocol.adoc[Enabling PROXY Protocol for RadSec]
diff --git a/doc/antora/modules/howto/pages/index.adoc b/doc/antora/modules/howto/pages/index.adoc
new file mode 100644
index 0000000..47a5146
--- /dev/null
+++ b/doc/antora/modules/howto/pages/index.adoc
@@ -0,0 +1,17 @@
+= Howto Guides
+
+The documents in this section describe how to perform various common tasks with
+FreeRADIUS. They also provide worked examples on using the various modules in
+common deployment scenarions.
+
+If you have a topic you'd like to see included in the list of howtos, contact
+the developers on the
+link:http://lists.freeradius.org/mailman/listinfo/freeradius-users[User's
+mailing list].
+
+Some of the documents here started life as pages on
+link:http://wiki.freeradius.org[wiki.freeradius.org]. If you've just been
+through a particularly arduous service configuration and deployment, and would
+like to help your fellow users, then please create a new how to on the wiki.
+If it's popular enough, we'll include it in the official documentation for the
+next release.
diff --git a/doc/antora/modules/howto/pages/protocols/dhcp/enable.adoc b/doc/antora/modules/howto/pages/protocols/dhcp/enable.adoc
new file mode 100644
index 0000000..2824bd0
--- /dev/null
+++ b/doc/antora/modules/howto/pages/protocols/dhcp/enable.adoc
@@ -0,0 +1,213 @@
+== Enabling the DHCP service
+
+A major difference between configuring FreeRADIUS as a DHCP server versus most
+other DHCP software such as ISC DHCP is that other software typically uses a
+single monolithic configuration file whereas FreeRADIUS has a collection of
+configuration files. This reflects the modularity of FreeRADIUS; attempting to
+put the entire configuration in a single file would result in a very difficult
+to read configuration.
+
+The root of the FreeRADIUS configuration may be in a different location on the
+filesystem depending on how FreeRADIUS has been installed. This directory will
+be referred to as `<raddb>` below. The sample configuration files are well
+commented describing what each configuration option does.
+
+FreeRADIUS compiled from source will default to `/usr/local/etc/raddb`.
+Pre-built packages will default to either `/etc/raddb` or
+`/etc/freeradius`.
+
+
+=== Enable the DHCP virtual server
+
+The FreeRADIUS configuration separates each network service that it provides
+into "virtual servers". A number of sample virtual server definitions are
+provided in `<raddb>/sites-available`, one of which is the sample
+configuration for a DHCP service.
+
+Sites may be added to the working configuration by either creating a symlink to
+them or copying them to `<conf>/sites-enabled` depending on how you wish to
+manage future upgrades.
+
+[TIP]
+====
+As with other package-managed configuration files, package upgrades will not
+automatically replace files that you have edited but you will need to resolve
+any local differences. Creating copies avoids the need to resolve conflicts
+during a package upgrade.
+====
+
+Add the DHCP virtual server to the active configuration:
+
+[source,shell]
+----
+cd <raddb>/sites-enabled
+ln -s ../sites-available/dhcp .
+----
+
+or:
+
+[source,shell]
+----
+cd <raddb>/sites-enabled
+cp ../sites-available/dhcp .
+----
+
+The sample configuration has been set up in such a way that it is initially
+safe. It will not actually take over live DHCP serving on the network when it
+is simply enabled until it is configured to do so. Rather is set up for testing
+prior to going live.
+
+The virtual server begins with a `listen` section. In this section your need to
+modify the following configuration items:
+
+`ipaddr`:: The IP address to listen on.
+`src_ipaddr`:: The source IP for unicast packets.
+`port`:: The port to listen on. Setting this to `67` will make the DHCP service live on the network.
+`interface`:: The network interface to listen on.
+`broadcast`:: Allow broadcast packets. For most live systems this will need to be set to `yes`.
+
+Below the `listen` section, there are sections that define how to respond to
+each of the DHCP packet types. Most installations will require that you review
+the settings for `DHCP-Discover` and `DHCP-Request`.
+
+Their contents contain directives in the FreeRADIUS policy language, "unlang".
+Many examples are provided which have been carefully described.
+
+
+=== Enable SQL and IP pool modules
+
+FreeRADIUS has many modules to support different aspects of the functionality
+required for the network protocols it can process. The two of most significance
+for DHCP are `dhcp_sql` and `dhcp_sqlippool`. As with virtual servers, a
+number of example module configurations are available in
+`<raddb>/mods-available`.
+These should be symlinked or copied into `<raddb>/mods-enabled` in order to
+enable them.
+
+
+==== Configure the `dhcp_sql` module
+
+Add the `dhcp_sql` module to the active configuration:
+
+[source,shell]
+----
+cd <raddb>/mods-enabled
+ln -s ../mods-available/dhcp_sql .
+----
+
+or:
+
+[source,shell]
+----
+cd <raddb>/mods-enabled
+cp ../mods-available/dhcp_sql .
+----
+
+The `dhcp_sql` module should be configured with the connection parameters for
+whichever database is to be used. The key configuration items are:
+
+`dialect`:: Which SQL dialect is in use.
+`driver`:: Which driver to use to access the database. For most databases this
+ is `rlm_sql_<dialect>`, however Microsoft SQL Server has a choice of
+ drivers.
+
+Then, there are configuration options that are unique to each database,
+including connection details. For most databases these are:
+
+`server`:: The host name or IP address of the database server.
+`port`:: The port to connect to the database server on.
+`login`:: The user name used to connect to the database.
+`password`:: The password for authenticating to the database.
+`radius_db`:: The name of the database.
+
+[NOTE]
+====
+SQLite does not use these connection options, rather the `filename`
+option within the `sqlite` section is used to determine where the database
+will be stored.
+====
+
+
+==== Configure the `dhcp_sqlippool` module
+
+Add the `dhcp_sqlippool` module to the active configuration:
+
+[source,shell]
+----
+cd <raddb>/mods-enabled
+ln -s ../mods-available/dhcp_sqlippool .
+----
+
+or
+
+[source,shell]
+----
+cd <raddb>/mods-enabled
+cp ../mods-available/dhcp_sqlippool .
+----
+
+The `dhcp_sqlippool` module must be configured. The key configuration
+items are:
+
+`dialect`:: Set this to the same SQL dialect as in the `sql` module.
+`offer_duration`:: How long an IP is offered to the client in a DHCP OFFER.
+`lease_duration`:: How long an IP is leased to the client in a DHCP ACK.
+
+
+=== Provision the database
+
+You should provision your database by creating a user for FreeRADIUS (matching
+the configuration that you have previously provided) and then loading the
+schema. The procedure for doing this will vary according to the database
+server.
+
+The schema, stored procedure definition and any additional setup scripts for
+your database are in `<raddb>/mods-config/sql/ippool-dhcp/{dialect}/`.
+
+=== Test FreeRADIUS startup
+
+Once you have provisioned your schema, created a user account and granted
+access to the user, you should be able to start FreeRADIUS.
+
+If FreeRADIUS has been configured correctly then the output of `ss` will
+contain a line showing that FreeRADIUS is listening for DHCP packets on the
+designated interface on port 67:
+
+.Example of FreeRADIUS listening on `<interface>` for DHCP packets
+==================================================================
+ # ss -lunp
+ Netid Recv-Q Send-Q Local Address:Port ...
+ udp 0 0 0.0.0.0%<interface>:67 ... users:(("radiusd",...))
+==================================================================
+
+Note that if the database is inaccessible then FreeRADIUS will normally refuse
+to start.
+
+The FreeRADIUS wiki contains extensive information about debugging FreeRADIUS
+startup issues that we do not repeat in any detail here.
+
+Essentially, stop your init system from repeatedly trying to launch FreeRADIUS:
+
+[source,shell]
+----
+service radiusd stop
+----
+
+Then start FreeRADIUS manually in debug mode:
+
+[source,shell]
+----
+radiusd -X
+----
+
+Carefully read the output since this will tell you why FreeRADIUS was unable to
+start.
+
+Once you have fixed the issue start FreeRADIUS as normal:
+
+[source,shell]
+----
+service radiusd start
+----
+
+Now xref:protocols/dhcp/test.adoc[test the DHCP service] to ensure that it is responding to requests.
diff --git a/doc/antora/modules/howto/pages/protocols/dhcp/index.adoc b/doc/antora/modules/howto/pages/protocols/dhcp/index.adoc
new file mode 100644
index 0000000..fde2202
--- /dev/null
+++ b/doc/antora/modules/howto/pages/protocols/dhcp/index.adoc
@@ -0,0 +1,35 @@
+= FreeRADIUS DHCP server
+
+This guide describes how FreeRADIUS can be used in place of ISC DHCP or ISC Kea
+to provide a significantly more performant and, above all, more flexible DHCP
+server.
+
+This guide provides a suggested configuration that should be somewhat familiar
+to anyone who has previously implemented DHCP using the most frequently used
+features of other DHCP server software.
+
+The modular design of FreeRADIUS means that there is no one "right" way to
+implement the DHCP service. FreeRADIUS allows you to put together a "mix and
+match" approach.
+
+For example you can manage the leases in an SQL database. You might then hard
+code certain DHCP reply parameters within configuration and then look up
+additional parameters using a datastore such as:
+
+ * a local file such as a structured text file or an SQLite database
+ * an organisational LDAP directory
+ * an SQL or "no SQL" database
+ * a remote endpoint such as a RESTful HTTP API
+
+The policy language and modular configuration of FreeRADIUS is sufficiently
+powerful and that almost any aspect of the server's behaviour can be customised
+to implement even the most sophisticated DHCP configurations.
+
+== Sections in this guide
+
+This guide is organised into four parts that should be read in order:
+
+1. xref:protocols/dhcp/prepare.adoc[Preparation]
+2. xref:protocols/dhcp/enable.adoc[Enabling the DHCP service]
+3. xref:protocols/dhcp/test.adoc[Testing the DHCP service]
+4. xref:protocols/dhcp/policy.adoc[Defining the DHCP policy]
diff --git a/doc/antora/modules/howto/pages/protocols/dhcp/policy.adoc b/doc/antora/modules/howto/pages/protocols/dhcp/policy.adoc
new file mode 100644
index 0000000..d8f1bcb
--- /dev/null
+++ b/doc/antora/modules/howto/pages/protocols/dhcp/policy.adoc
@@ -0,0 +1,14 @@
+== Defining the DHCP policy
+
+Now that FreeRADIUS is successfully running as a DHCP server it is necessary to
+configure a DHCP policy so that it returns correctly formed responses to the DHCP
+requests that it receives.
+
+This involves a number of steps:
+
+ * xref:protocols/dhcp/policy_ippool_creation.adoc[Defining the IP address pools.]
+ * xref:protocols/dhcp/policy_common_options.adoc[Defining the options that are common to all replies.]
+ * xref:protocols/dhcp/policy_network_options.adoc[Defining the options for the network from which the request originates and ensuring that IP addresses are allocated from the correct pool.]
+ * xref:protocols/dhcp/policy_subnet_options.adoc[Defining the options for the subnet to which this issued IP address belongs.]
+ * xref:protocols/dhcp/policy_device_options.adoc[Defining the device, class and group based options specific to the device.]
+ * xref:protocols/dhcp/policy_ippool_access.adoc[Using device properties to restrict access to certain pools.]
diff --git a/doc/antora/modules/howto/pages/protocols/dhcp/policy_common_options.adoc b/doc/antora/modules/howto/pages/protocols/dhcp/policy_common_options.adoc
new file mode 100644
index 0000000..949868d
--- /dev/null
+++ b/doc/antora/modules/howto/pages/protocols/dhcp/policy_common_options.adoc
@@ -0,0 +1,80 @@
+== Configure common reply options
+
+FreeRADIUS includes a powerful xref:unlang/index.adoc[policy language] called
+"unlang".
+
+Statements in unlang may be used to call further policies, update attribute
+lists and invoke modules. There are also control flow statements (if,
+switch, etc.) typical of most imperative languages.
+
+FreeRADIUS has a number attribute lists that it maintains as it processes
+packets within the virtual server sections. Most relevant to DHCP are
+`request`, `control` and `reply`.
+
+The DHCP options from the current request packet are provided in the
+`request` list. This includes fixed DHCP parameters such as
+`DHCP-Client-Hardware-Address`, optional parameters such as
+`DHCP-Requested-IP-Address`, and parameters synthesised by FreeRADIUS such as
+`DHCP-Message-Type` and `DHCP-Network-Subnet`.
+
+DHCP options can be set by updating their value in the `reply` list. This
+forms the basis of the packet returned to the client.
+
+In the default DHCP server configuration, a "policy" (akin to a subroutine) is
+used to set common options for reply packets. The policy is found in
+`<raddb>/policy.d/dhcp`.
+
+Look at the contents of the `dhcp_common` section and set any global options
+applicable to all clients in this policy.
+
+[source,unlang]
+----
+dhcp_common {
+ update reply {
+ &DHCP-Domain-Name-Server := 8.8.8.8
+ &DHCP-Domain-Name-Server += 8.8.4.4
+ &DHCP-Subnet-Mask := 255.255.255.0
+ &DHCP-Router-Address := 192.0.2.1
+ ...
+ }
+}
+----
+
+Note, FreeRADIUS has four main operators for assigning values to attributes:
+
+`=`:: Add the attribute to the list, if and only if an attribute of the same
+ name is not already present in that list.
+`:=`:: Add the attribute to the list. If any attribute of the same name is
+ already present in that list it is replaced with the new one.
+`+=`:: Add the attribute to the tail of the list, even if attributes of the
+ same name are already present in the list.
+`^=`:: Add the attribute to the head of the list, even if attributes of the
+ same name are already present in the list.
+
+These operators allow for attributes to be set to default values and then
+overwritten, e.g. setting a default lease time, but then overwriting it for
+a particular group of clients.
+
+Attributes in the `control` list are not returned in the DHCP reply packets
+but instead govern aspects of server's behaviour.
+
+To use an SQL backend for either static or dynamic IP allocation, un-comment
+the block:
+
+[source,unlang]
+----
+update control {
+ &Pool-Name := "local"
+}
+dhcp_sqlippool
+----
+
+The `Pool-Name` control attribute is used in looking up addresses in the
+database. The line containing `dhcp_sqlippool` is a call to invoke an
+instance of a module with that name. This module is responsible for assigning a
+free IP address into the `DHCP-Your-IP-Address` reply attribute from the pool
+identified by `Pool-Name`.
+
+Here `Pool-Name` is being set to a constant value (`local`) indicating
+that a single pool is to be used. If you have multiple pools, then replace this
+`update` block with logic to map clients to the correct pool, as described below.
diff --git a/doc/antora/modules/howto/pages/protocols/dhcp/policy_device_options.adoc b/doc/antora/modules/howto/pages/protocols/dhcp/policy_device_options.adoc
new file mode 100644
index 0000000..05845ea
--- /dev/null
+++ b/doc/antora/modules/howto/pages/protocols/dhcp/policy_device_options.adoc
@@ -0,0 +1,310 @@
+== Configure "device", "class" and "group" options
+
+Beyond the global, network and subnet options already described, most sites
+will have a number of group or class based options, and have a requirement for
+setting reply parameters against individual devices.
+
+In general, FreeRADIUS does not differentiate between "classes" (memberships
+defined by some attribute of the DHCP request) and "groups" (memberships
+defined by some manually aggregation related devices, typically based on lists
+of MAC address).
+
+The sample DHCP configuration provided with FreeRADIUS makes use of an internal
+attribute `DHCP-Group-Name` to support the setting of different options for
+different groups of devices.
+
+In general the groups to which a device belongs is determined during the
+processing of a request and these are added as instances of the
+`DHCP-Group-Name` attribute. This may be by performing a test on one or more
+request parameters (akin to a "class"), hash-based lookup of up all of part of
+an attribute in a local list (akin to a "subclass"), or doing the same using a
+remote datastore (SQL, LDAP, REST API, etc).
+
+FreeRADIUS can then iterate over `DHCP-Group-Name` to set group-specific
+options.
+
+We describe some of these options in more detail.
+
+=== Directly in Policy
+
+Simple class options can be written directly into policy. This is most
+suited to those options that rarely change and are based on attributes in the
+request such as the `User-Class`.
+
+Consider the ISC DHCP configuration snippet:
+
+[source,iscdhcp]
+----
+filename "undionly.kpxe";
+class "pxeclient" {
+ match option substring(user-class,0,4);
+}
+subclass "pxeclient" "iPXE" {
+ filename "http://my.web.server/boot_script.php";
+}
+----
+
+Or the equivalent Kea configuration:
+
+[source,isckea]
+----
+"Dhcp4": {
+ "option-data": [
+ { "name": "boot-file-name", "data": "undionly.kpxe" }
+ ],
+ "client-classes": [
+ {
+ "name": "pxeclient",
+ "test": "substring(option[77],0,4) == 'iPXE'",
+ "option-data": [
+ {
+ "name": "boot-file-name",
+ "data": "http://my.web.server/boot_script.php"
+ }
+ ]
+ }
+ ]
+ ...
+}
+----
+
+These define the "filename" DHCP option differently based on whether or not the
+supplied "user-class" option begins with "iPXE".
+
+FreeRADIUS provides multiple ways for this to be configured.
+
+For example, the following "unlang" policy implements the class options defined
+above:
+
+[source,unlang]
+----
+if (&DHCP-User-Class && "%{substring:&DHCP-User-Class 0 4}" == "iPXE") {
+ update reply {
+ &DHCP-Boot-Filename := "http://my.web.server/boot_script.php"
+ }
+} else {
+ update reply {
+ &DHCP-Boot-Filename := "undionly.kpxe"
+ }
+}
+----
+
+Policy-based configuration of DHCP options is also useful for complex matching.
+For example, the following Unlang sets the DHCP-Boot-Filename parameter based
+on the request's DHCP-Client-Identifier using regular expression captures,
+provided that it matches the given format:
+
+[source,unlang]
+----
+if (&DHCP-Client-Identifier && \
+ "%{string:DHCP-Client-Identifier}" =~ /^RAS([0-9])-site([A-Z])$/) {
+ update reply {
+ &DHCP-Boot-Filename := "rasboot-%{1}-%{2}.kpxe"
+ }
+}
+----
+
+=== In Text Files
+
+The `files` module that has already been described for global, network and
+subnet options can also be used to apply options to groups of clients.
+
+Firstly we must defined a mapping from a set of clients clients to their
+respective groups. One option for this is to use the `passwd` module, for
+which a sample configuration is included.
+
+Firstly symlink or copy the module configuration
+`<raddb>/mods-available/dhcp_passwd` into `<raddb>/mods-enabled/`. The
+suggested configuration expects the group membership file to be in
+`<raddb>/mods-config/files/dhcp_groups` and take the form of:
+
+[source,config]
+----
+<group1 name>|<hardware address>,<hardware address>,<hardware address>
+<group2 name>|<hardware address>,<hardware address>
+----
+
+i.e. one line for each group starting with the group name followed by a pipe
+character and then a comma-separated list of hardware addresses.
+
+The `allow_multiple_keys` option allows for a host to be a member of
+more than one group.
+
+Sample configuration for looking up group options is contained in
+`<raddb>/policy.d/dhcp` in the `dhcp_group_options` policy and in
+`<raddb>/mods-available/dhcp_files` as the `dhcp_set_group_options` instance.
+
+The same data file `<raddb>/mods-config/files/dhcp` is used to lookup
+group options as was used for global and network options. In this instance,
+add entries with the group name as the key such as:
+
+[source,config]
+----
+group1
+ DHCP-Log-Server := 10.10.0.100,
+ DHCP-LPR-Server := 10.10.0.200
+
+group2
+ DHCP-LPR-Server := 192.168.20.200
+----
+
+=== In the SQL Database
+
+Policy and files are both read during startup and editing them while
+FreeRADIUS is running will not result in any changes in behaviour. If
+you require regular changes to DHCP options, then storing them in
+an SQL database provides greater flexibility since the queries will be run in
+response to each DHCP packet rather than requiring the server to be restarted.
+
+DHCP reply options for devices (including network-specific options) can be
+fetched from SQL using an arbitrary lookup key. This can be performed multiple
+times as necessary using different contexts, for example to first set
+subnet-specific options and then to set group-specific options.
+
+The default schema contains three tables to support this:
+
+"dhcpreply" contains reply options for a given identifier (e.g. MAC Address):
+
+.dhcpreply table
+|===
+|Identifier |Attribute |Op |Value |Context
+
+|`02:01:aa:bb:cc:dd` |`DHCP-Log-Server` |`:=` |`192.0.2.10` |`by-mac`
+|`02:01:aa:bb:cc:dd` |`DHCP-LPR-Server` |`:=` |`192.0.2.11` |`by-mac`
+|`02:01:aa:bb:cc:dd` |`Fall-Through` |`:=` |`Yes` |`by-mac`
+|===
+
+"dhcpgroup" maps identifiers to a group of options that can be shared:
+
+.dhcpgroup table
+|===
+|Identifier |GroupName |Priority |Context
+
+|`02:01:aa:bb:cc:dd` |`salesdept` |`10` |`by-mac`
+|===
+
+"dhcpgroupreply" contains reply options for each group:
+
+.dhcpgroupreply table
+|===
+|GroupName |Attribute |Op |Value |Context
+
+|`salesdept` |`DHCP-NTP-Servers` |`:=` |`192.0.2.20` |`by-mac`
+|`salesdept` |`DHCP-Log-Server` |`+=` |`192.0.2.21` |`by-mac`
+|`salesdept` |`DHCP-LPR-Server` |`^=` |`192.0.2.22` |`by-mac`
+|===
+
+Within the context of assigning options directly to devices, as well as to
+manually-curated groups of devices keyed by their MAC address:
+
+ - Place device-specific options in the "dhcpreply" table.
+ - Add `Fall-Through := Yes` to the options in the "dhcpreply" table in order
+ to trigger group lookups, which are disabled by default.
+ - Place entries in the "dhcpgroup" `identifier = <MAC-Address>, groupname = <group>, priority =
+ <priority>` in the "dhcpgroup" table to map a device to its groups by
+ priority.
+ - Place the grouped options in the "dhcpgroupreply" table.
+ - For each of the above, set `Context` to something by which the option
+ lookup is referred to in the policy, for example `Context = 'by-mac'`.
+
+For the above example you would add the following to the DHCP virtual server to
+perform reply option lookup using the device's MAC address against the `by-mac`
+context:
+
+[source,unlang]
+----
+update control {
+ &DHCP-SQL-Option-Context := "by-mac"
+ &DHCP-SQL-Option-Identifier := &request:DHCP-Client-Hardware-Address
+}
+dhcp_sql.authorize
+----
+
+In the above, the DHCP reply options would be assigned to a device with MAC
+address 02:01:aa:bb:cc:dd as follows:
+
+ - Firstly, the `DHCP-Log-Server` option would be set to `192.0.2.10` and the
+ `DHCP-LPR-Server` option set to `192.0.2.11`.
+ - `Fall-Through` is set, so the group mapping is then queried which
+ determines that the device belongs to a single `salesdept` group.
+ - Finally, the options for the `salesdept` group are now merged, setting a
+ `DHCP-NTP-Servers` option to `192.0.2.20`, appending an additional
+ `DHCP-Log-Server` option set to `192.0.2.21`, and prepending an additional
+ `DHCP-LPR-Server` option set to `192.0.2.22`.
+
+If instead you wanted to perform a "subclass" lookup based on the first three
+octets of the device's MAC address then with tables containing the following
+sample data you could invoke an SQL lookup as shown:
+
+."dhcpreply" table:
+|===
+|Identifier |Attribute |Op |Value |Context
+
+|`000393` |`Fall-Through` |`:=` |`Yes` |`class-vendor`
+|`000a27` |`Fall-Through` |`:=` |`Yes` |`class-vendor`
+|`f40304` |`Fall-Through` |`:=` |`Yes` |`class-vendor`
+|===
+
+."dhcpgroup" table:
+|===
+|Identifier |GroupName |Priority |Context
+
+|`000393` |`apple` |`10` |`class-vendor`
+|`000a27` |`apple` |`10` |`class-vendor`
+|`f40304` |`google` |`10` |`class-vendor`
+|===
+
+."dhcpgroupreply" table:
+|===
+|GroupName |Attribute |Op |Value |Context
+
+|`apple` |`DHCP-Boot-Filename` |`:=` |`apple.efi` |`class-vendor`
+|`google` |`DHCP-Boot-Filename` |`:=` |`google.efi` |`class-vendor`
+|===
+
+
+[source,unlang]
+----
+update control {
+ &DHCP-SQL-Option-Context := "class-vendor"
+ &DHCP-SQL-Option-Identifier := \
+ "%{substring:%{hex:&DHCP-Client-Hardware-Address} 0 6}"
+}
+dhcp_sql.authorize
+----
+
+The file `policy.d/dhcp` contains a policy named `dhcp_policy_sql` which
+provides further worked examples for different types of option lookups.
+
+=== Testing "device", "class" and "group" options
+
+You should now test that any device-related options that you have configured
+using the various methods available are applied successfully by generating
+packets containing those parameters based upon which the reply options are set.
+
+For example, to test the iPXE user class example above you might want to
+generate a request as follows:
+
+[source,shell]
+----
+cat <<EOF > dhcp-packet-ipxe-boot.txt
+DHCP-Message-Type := DHCP-Discover
+DHCP-Client-Hardware-Address := 02:01:aa:bb:cc:dd
+DHCP-User-Class := "iPXE-class-abc"
+EOF
+----
+
+To which you would expect to see a response such as:
+
+.Example output from dhcpclient
+===============================
+ dhcpclient: ...
+ ----------------------------------------------------------------------
+ Waiting for DHCP replies for: 5.000000
+ ----------------------------------------------------------------------
+ ...
+ DHCP-Message-Type = DHCP-Offer
+ DHCP-Your-IP-Address = 1.2.3.4
+ DHCP-Boot-Filename := "http://my.web.server/boot_script.php"
+ ...
+===============================
diff --git a/doc/antora/modules/howto/pages/protocols/dhcp/policy_ippool_access.adoc b/doc/antora/modules/howto/pages/protocols/dhcp/policy_ippool_access.adoc
new file mode 100644
index 0000000..40b8e30
--- /dev/null
+++ b/doc/antora/modules/howto/pages/protocols/dhcp/policy_ippool_access.adoc
@@ -0,0 +1,54 @@
+== Configure access restrictions for pools
+
+We can combine what we have learned in the preceeding sections to provide pools
+whose access is restricted in some way, for example to a particular class.
+
+Consider the ISC DHCP configuration snippet:
+
+[source,iscdhcp]
+----
+subnet 10.99.99.0 netmask 255.255.255.0 {
+ pool {
+ range 10.99.99.200 10.99.99.250;
+ allow members of "printers";
+ }
+ option routers 10.99.99.1;
+}
+----
+
+Or the equivalent Kea configuration:
+
+[source,isckea]
+----
+"Dhcp4": {
+ "subnet4": [{
+ "subnet": "10.99.99.0/24",
+ "pools": [
+ {
+ "pool": "10.99.99.200 - 10.99.99.250",
+ "client-class": "printers"
+ }
+ ],
+ "option-data": [
+ { "name": "routers", "data": "10.10.0.1" }
+ ]
+ }],
+ ...
+}
+----
+
+These define a subnet containing a single pool that is restricted to members of
+the "printers" class. (The definition for this class is omitted.)
+
+In FreeRADIUS, to filter access to this pool entries such as the following
+should included in the `<raddb>/mods-config/files/dhcp` configuration file:
+
+[source,config]
+----
+network DHCP-Network-Subnet < 10.99.99.0/24, \
+ DHCP-Group-Name == "printers", Pool-Name := "printers-pool"
+ DHCP-Router-Address := 10.99.99.1
+----
+
+Note that any number of additional filters can be added to the initial "check"
+line to restrict matches to the network block.
diff --git a/doc/antora/modules/howto/pages/protocols/dhcp/policy_ippool_creation.adoc b/doc/antora/modules/howto/pages/protocols/dhcp/policy_ippool_creation.adoc
new file mode 100644
index 0000000..e976873
--- /dev/null
+++ b/doc/antora/modules/howto/pages/protocols/dhcp/policy_ippool_creation.adoc
@@ -0,0 +1,112 @@
+=== Determine the IP pool plan
+
+Except for cases where all IP allocation is performed using a mapping from the
+device MAC address to a fixed IP address, the DHCP configuration will involve
+the use of one or more IP address pools.
+
+FreeRADIUS stores all the IP addresses in its pools in whichever database has
+been chosen. An instance of the `sqlippools` module is used to manage all pools
+within a single table (normally `dhcpippool`). Each row of this table
+corresponds to an IP address that is a member of some pool. The pools are
+distinguished by name, so the table has a column (`pool_name`) that denotes
+this.
+
+Each pool in this table should be composed of a set of equally valid IP
+addresses for the devices that are designated to be members of the pool.
+
+Firstly, consider the network locations to which distinct ranges of IP
+addresses must be allocated and provisionally assign a pool to each.
+
+Next, consider that many networks support multiple co-existing subnets without
+VLAN separation. We will call this a "shared-network" to use the original ISC
+DHCP parlance. In Microsoft DHCP contexts this is often referred to as a
+"multinet".
+
+Often in a shared-network the policy has no regard for which of the network's
+devices is allocated to which subnet. In this case we must create a single,
+combined pool containing all of the IP addresses from each subnet in that
+network. Since all addresses in a pool are treated equally this will mean that
+any IP address may be allocated to a device that is making a DHCP request from
+that network. The appropriate DHCP parameters for the subnet to which the IP
+address belongs is determined after allocation.
+
+There are sometimes shared-networks (or even single subnets) for which IP
+addresses belonging to any subnet may be technically suitable for any device,
+however some local policy wants to assigning them to a particular subnet, for
+example to provide loose segregation between classes of device. In this case we
+define multiple pools, one for each range of IP addresses whose devices needs to
+be differentiated.
+
+The choice of pool is ordinarily determined based on the network from which the
+request originates using a mapping from Layer 2 networks to the pool name
+provided by the user. The indicator for the originating network can be
+overridden when this alone is insufficient to implement the required pool
+selection policy such as when you need to differentiate the pool's users with
+more granularity that their Layer 2 network, such as by considering device
+attributes ("class" membership in ISC parlance) or Option 82 circuit data.
+
+
+=== Populate the IP Pools
+
+By this stage you should have derived a list of pools, the IP address ranges
+contained therein, and the means of selecting the pool to use based on the
+originating network and/or some additional criteria from the request.
+
+A helper Perl script is provided with FreeRADIUS that can be used to populate
+the pools provide that you are using the default schema.
+
+[source,shell]
+----
+rlm_sqlippool_tool -p <pool_name> -s <range_start> -e <range_end> \
+ -t <table_name> (-d <sql_dialect> | -f <raddb_dir> [ -i <instance> ]) \
+ [ -c <capacity> ] [ -x <existing_ips_file> ]
+----
+
+If, for example, you had a range configured in ISC DHCP as:
+
+[source,iscdhcp]
+----
+range 10.0.0.5 10.0.0.199
+----
+
+and you are using PostgreSQL as your database, and you wish to refer to this pool
+using the name `local`, this could be prepared with:
+
+[source,shell]
+----
+rlm_sqlippool_tool -p local -s 10.0.0.5 -e 10.0.0.199 -t dhcpippool -d postgresql
+----
+
+If the SQL module of FreeRADIUS is already configured then this can
+be referenced so that the tool is able to use the configured connection
+parameters to connect to the database and populate the pool:
+
+[source,shell]
+----
+rlm_sqlippool_tool -p local -s 10.0.0.5 -e 10.0.0.199 -t dhcpippool -f /etc/raddb
+----
+
+For installations that require multiple pools, `rlm_sqlippool_tool` can
+be called referencing a YAML file defining the pools. Comments at the
+head of `rlm_sqlippool_tool` explain the options in more detail.
+
+If static leases are required then these should be set up in the database
+such that the MAC address of the client should be set as the `pool_key`
+against the corresponding address and the `status` column of the row
+representing the address set to `static`. A helper perl script,
+`rlm_iscfixed2ippool` can be used to read an ISC DHCP config file and produce
+SQL to perform these changes or directly update the database:
+
+[source,shell]
+----
+rlm_iscfixed2ippool -c <dhcpd.<raddb> -t <table_name> -k <mac|id> \
+ (-d <sql_dialect> | -f <raddb_dir> [-i <instance>])
+----
+
+For example, to read /etc/dhcp/dhcpd.conf and populate the configured
+FreeRADIUS database, using the mac as the identifier:
+
+[source,shell]
+----
+rlm_iscfixed2ippool -c /etc/dhcp/dhcpd.conf -t dhcpippool -k mac -f /usr/local/etc/raddb
+----
diff --git a/doc/antora/modules/howto/pages/protocols/dhcp/policy_network_options.adoc b/doc/antora/modules/howto/pages/protocols/dhcp/policy_network_options.adoc
new file mode 100644
index 0000000..e2657a8
--- /dev/null
+++ b/doc/antora/modules/howto/pages/protocols/dhcp/policy_network_options.adoc
@@ -0,0 +1,237 @@
+== Configure network-specific options and IP pool selection
+
+In an environment where multiple networks (often VLANs) are in use, it is
+necessary to identify which network a client belongs to in order to assign an
+address from the correct pool.
+
+Consider the ISC DHCP configuration snippet:
+
+[source,iscdhcp]
+----
+option domain-name "example.org";
+
+subnet 10.10.0.0 netmask 255.255.0.0 {
+ range 10.10.1.10 10.10.10.254;
+ range 10.10.100.10 10.10.110.254;
+ option routers 10.10.0.1;
+ option domain-name-servers 10.10.0.2, 10.10.0.3;
+ default-lease-time 7200;
+}
+----
+
+Or the equivalent Kea configuration:
+
+[source,isckea]
+----
+"Dhcp4": {
+ "option-data": [
+ { "name": "domain-name", "data": "example.org" }
+ ],
+ "subnet4": [{
+ "subnet": "10.10.0.0/16",
+ "pools": [ { "pool": "10.10.1.10 - 10.10.10.254" },
+ { "pool": "10.10.100.10 - 10.10.110.254" }
+ ],
+ "option-data": [
+ { "name": "routers", "data": "10.10.0.1" },
+ { "name": "domain-name-servers", "data": "10.10.0.2, 10.10.0.3" }
+ ],
+ "valid-lifetime": 7200
+ }],
+ ...
+}
+----
+
+These define a network consisting of a single subnet 10.10.0.0/16 containing two
+IP address pools 10.10.1.10 - 10.10.10.254 and 10.10.100.10 - 10.10.110.254.
+Requests that are determined to have originated from this network (e.g. because
+their `giaddr` belongs within the subnet) will be assigned the specified DHCP
+parameters and allocated an address from one of its ranges.
+
+To provide equivalent functionality, FreeRADIUS must identify the correct DHCP
+reply parameters as well as the name of the pool to be used for IP address
+assignment, based on the originating network of the request.
+
+The definition for this pool (the addresses contained within it, corresponding
+to the `range` statement in ISC DHCP and Kea) is specified entirely in the
+database: It is precisely the rows in the `dhcpippool` table with a particular
+`pool_name`.
+
+[TIP]
+====
+As described previously, in FreeRADIUS a pool is a set of IP addresses that are
+equally valid with respect to the network policy; therefore, unlike ISC DHCP
+and ISC Kea, FreeRADIUS does not differentiate between the two `range`s.
+Instead we should have previously populated a single pool containing all of the
+IP addresses from both ranges.
+====
+
+FreeRADIUS derives a request attribute called `DHCP-Network-Subnet` which
+honours the standard DHCP process for designating the choice of network, in
+order of preference:
+
+ 1. Link Selection Suboption of Option 82
+ 2. IPv4 Subnet Selection Option
+ 3. Gateway IP Address ("giaddr")
+ 4. Client IP Address ("ciaddr", only set for unicast packets)
+
+If `DHCP-Network-Subnet` contains an IP address then this should be used as
+the basis of choosing a network. When there is no address in this attribute it
+can be assumed that the packet has been received from a client on the local
+LAN.
+
+The `files` module in FreeRADIUS provides a simple method to map
+`DHCP-Network-Subnet` to the corresponding pool based on its network
+membership, setting the appropriate options to return to clients. It can also
+set the global options.
+
+[TIP]
+====
+In the case where an instance of the `files` module is used to get global
+default parameters, the `dhcp_common` policy becomes redundant so the
+statement calling the policy (by name) can be commented out in
+`<raddb>/sites-enabled/dhcp`.
+====
+
+To use the provided example `files` module instance for DHCP, symlink or copy
+`<raddb>/mods-available/dhcp_files` into `<raddb>/mods-enabled/` and then
+uncomment the calls to `dhcp_network` in `<raddb>/sites-enabled/dhcp`.
+
+A template configuration file `<raddb>/mods-config/files/dhcp` is also
+provided which should be adapted to suit your network topology.
+
+For the configuration above you may deduce the following configuration, which
+has been extended to include an initial default section for requests originating
+from directly-connected clients on the local LAN (192.168.20/24):
+
+[source,config]
+----
+network Pool-Name := "local"
+ DHCP-Domain-Name := "example.org",
+ DHCP-Subnet-Mask := 255.255.255.0,
+ DHCP-Router-Address := 192.168.20.1,
+ DHCP-Domain-Name-Server := 192.168.20.2,
+ Fall-Through := yes
+
+network DHCP-Network-Subnet < 10.10.0.0/16, Pool-Name := "remote"
+ DHCP-Subnet-Mask := 255.0.0.0,
+ DHCP-Router-Address := 10.10.0.1,
+ DHCP-Domain-Name-Server := 10.10.0.2,
+ DHCP-Domain-Name-Server += 10.10.0.3,
+ DHCP-IP-Address-Lease-Time := 7200
+----
+
+Each block in the file starts with a line beginning with the key to be matched.
+In this case the keyword of `network` (defined earlier in `dhcp_networks`
+configuration) is used for each block, so each of the above blocks is a
+candidate during the search.
+
+There may be further filtering of the candidates in the form of `<Attribute>
+<op> <Value>`. In the case of the second block we match the
+`DHCP-Network-Subnet` to an enclosing subnet with
+`DHCP-Network-Subnet < <subnet>`. Additional filters could be added as
+required, comma separated.
+
+Following the filters on the first line, attributes in the `control` list can
+be set using the syntax of `<Attribute> := <Value>`. In this example this is
+used to specify the `Pool-Name` for choosing the appropriate IP pool to
+allocate an address from.
+
+Subsequent indented lines are attribute assignments for values in the `reply`
+list. Note that, apart from the last line, they are all terminated with a
+comma.
+
+The special option `Fall-Through` determines whether, following a match,
+other records are checked for a match. All lookups will match the entry
+with a key of `network` and no further filtering, so `Fall-Through`
+is set on that record in order that the other records will be tested
+to find subnet matches.
+
+=== Example packet processing
+
+For our example, we consider a request arriving from a DHCP relay within
+10.10.0.0/16. In the absence of any specific DHCP subnet selection options in
+the request, the `DHCP-Network-Subnet` attribute is calculated to be the
+relay's IP address, say 10.10.0.1.
+
+The request is matched against the first block, setting an initial pool name to
+"local", domain name to "example.org" and setting some additional global
+default parameters. By virtue of `Fall-Through` being set, the next block is
+considered.
+
+Since the network identifier is within the specified subnet (i.e. `10.10.0.1 <
+10.10.0.0/16`) this second block is matched. This block overrides the pool name
+setting it to "remote", overrides some other global defaults and sets the lease
+time to 7200 seconds. `Fall-Through` is not set, so we are now done with
+deriving the pool name and network options.
+
+When the `dhcp_sqlippool` module is called during DHCP DISCOVER processing (in
+`<raddb>/sites-enabled/dhcp`) the `remote` pool will be used for IP address
+allocation.
+
+The assigned IP address and network parameters will subsequently be returned in
+the DHCP reply.
+
+=== Testing the pool operation and network-specific options
+
+Before proceeding further, you should test the operation of the IP pools and
+ensure that any network-specific reply attributes that you have configured are
+correctly set in replies.
+
+For example, if you have a single, flat pool you should test using sample
+packets for devices with different MAC addresses and/or Client Identifiers.
+
+[source,shell]
+----
+cat <<EOF > dhcp-packet-1.txt
+DHCP-Message-Type := DHCP-Discover
+DHCP-Client-Hardware-Address := 02:01:11:11:11:11
+DHCP-Client-Identifier := device1
+EOF
+----
+
+[source,shell]
+----
+cat <<EOF > dhcp-packet-2.txt
+DHCP-Message-Type := DHCP-Discover
+DHCP-Client-Hardware-Address := 02:01:22:22:22:22
+DHCP-Client-Identifier := device2
+EOF
+----
+
+Generate these packets as show previously using the dhcpclient tool and look
+for `DHCP-Your-IP-Address` in the DHCP responses to determine the IP address
+that has been offered.
+
+Ensure that the DHCP Offer responses contain unique IP addresses. Ensure that
+when these requests are resent within the lifetime of the initial offer that
+the reponses to the subsequent replies contain the original IP address that was
+in the initial offer to the device.
+
+Additionally, ensure that the DHCP Offers contain any network-specific
+parameters that you have specified.
+
+In the case that the policy contains multiple IP pools and network definitions
+for clients belonging to different Layer 2 networks (or indeed belonging to the
+same network but segregated according to some local policy) you should ensure
+that the devices are being mapped to the correct definition.
+
+For a typical policy that selects the IP pool and network options based on the
+originating network for the DHCP packet, explicitly specifying a network by
+including a `DHCP-Subnet-Selection-Option` parameter may avoid the need to test
+from a host within each individual network:
+
+[source,shell]
+----
+cat <<EOF > dhcp-packet-network-10.10.10.0.txt
+DHCP-Message-Type := DHCP-Discover
+DHCP-Client-Hardware-Address := 02:01:aa:bb:cc:dd
+DHCP-Client-Identifier := abc123
+DHCP-Subnet-Selection-Option := 10.10.10.0
+EOF
+----
+
+For policies where the IP pool and network option selection is based on some
+custom criteria it is necessary to include different variations for the
+parameters on which the policy makes the decision. The testing example for the
+class-specific options later in this document provides such an example.
diff --git a/doc/antora/modules/howto/pages/protocols/dhcp/policy_subnet_options.adoc b/doc/antora/modules/howto/pages/protocols/dhcp/policy_subnet_options.adoc
new file mode 100644
index 0000000..1980e89
--- /dev/null
+++ b/doc/antora/modules/howto/pages/protocols/dhcp/policy_subnet_options.adoc
@@ -0,0 +1,184 @@
+== Configure subnet-specific options for shared networks
+
+In the case that shared-networks are in use, with the pool containing
+equally-valid IP addresses from multiple subnets, it is necessary to set the
+subnet-specific parameters such as `DHCP-Router-Address`, `DHCP-Subnet-Mask`
+and `DHCP-Broadcast-Address` based on the IP address that has been allocated.
+
+Consider the ISC DHCP configuration snippet:
+
+[source,iscdhcp]
+----
+option domain-name "example.org";
+
+shared-network bigdept {
+
+ option domain-name-servers 10.10.0.2, 10.10.0.3;
+ default-lease-time 7200;
+
+ subnet 10.30.10.0 netmask 255.255.255.0 {
+ option routers 10.30.10.1;
+ }
+ subnet 10.30.20.0 netmask 255.255.255.0 {
+ option routers 10.30.20.1;
+ }
+ range 10.30.10.10 10.30.10.254;
+ range 10.30.20.10 10.30.20.254;
+
+}
+----
+
+Or the equivalent Kea configuration:
+
+[source,kea]
+----
+"Dhcp4": {
+ "option-data": [
+ { "name": "domain-name", "data": "example.org" }
+ ],
+ "shared-networks": [{
+ "name": "bigdept",
+ "option-data": [
+ { "name": "domain-name-servers", "data": "10.10.0.2, 10.10.0.3" }
+ ],
+ "valid-lifetime": 7200,
+ "subnet4": [{
+ "subnet": "10.30.10.0/24",
+ "pools": [ { "pool": "10.30.10.10 - 10.30.10.254" } ],
+ "option-data": [
+ { "name": "routers", "data": "10.30.10.1" }
+ ]
+ }],
+ "subnet4": [{
+ "subnet": "10.30.20.0/24",
+ "pools": [ { "pool": "10.30.20.10 - 10.30.20.254" } ],
+ "option-data": [
+ { "name": "routers", "data": "10.30.20.1" }
+ ]
+ }]
+ }],
+ ...
+}
+----
+
+As with the network to pool lookup, an instance of the `files` modules can be
+employed (this time after the allocation of an IP address) to set the correct
+reply parameters based on the subnet membership of the assigned address.
+
+To do this, we can use this section of `<raddb>/mods-available/dhcp_files`:
+
+[source,config]
+----
+files dhcp_subnets {
+ filename = ${modconfdir}/files/dhcp
+ key = "subnet"
+}
+----
+
+Additionally, uncomment the `dhcp_subnets` policy in `<raddb>/policy.d/dhcp`.
+This policy wraps the call to the `dhcp_subnets` files module with code that
+"tightens" the `DHCP-Network-Subnet` attribute by setting it to the
+just-allocated IP address.
+
+The relevant entries in the `<raddb>/mods-config/files/dhcp` configuration
+file might then look something like this:
+
+[source,config]
+----
+network
+ DHCP-Domain-Name := "example.org",
+ Fall-Through := yes
+
+network DHCP-Network-Subnet < 10.30.0.0/16, Pool-Name := "bigdept"
+ DHCP-Domain-Name-Server := 10.10.0.2,
+ DHCP-Domain-Name-Server += 10.10.0.3,
+ DHCP-IP-Address-Lease-Time := 7200
+
+subnet DHCP-Network-Subnet < 10.30.10.0/24
+ DHCP-Router-Address := 10.30.10.1
+
+subnet DHCP-Network-Subnet < 10.30.20.0/24
+ DHCP-Router-Address := 10.30.20.1
+----
+
+=== Example packet processing
+
+For our example, we consider a request arriving from a DHCP relay within
+10.30.10.0/24. In the absence of any specific DHCP subnet selection options in
+the request, the `DHCP-Network-Subnet` attribute is calculated to be the
+relay's IP address, say 10.30.10.1.
+
+The request is matched against the first "network" block, setting the domain
+name to "example.org". By virtue of `Fall-Through` being set, the next "network"
+block is considered.
+
+Since the network identifier is within the specified subnet (i.e. `10.30.10.1 <
+10.30.0.0/16`) this second "network" block is matched. This block sets the pool
+name to "bigdept", sets some network-specific DNS resolvers and sets the lease
+time to 7200 seconds. `Fall-Through` is not set, so we are now done with
+deriving the pool name and network options.
+
+When the `dhcp_sqlippool` module is called during DHCP DISCOVER processing (in
+`<raddb>/sites-enabled/dhcp`) the `bigdept` pool will be used for IP address
+allocation.
+
+After IP allocation the `dhcp_subnet` policy and files instance are called.
+Before the subnet options are looked up the `DHCP-Network-Subnet`
+attribute is tightened to match the assigned IP address, say 10.30.20.123.
+
+The request does not match the first subnet block since 10.30.20.123 is not
+within 10.30.10.0/24. However, the request does match the second subnet block
+since `10.30.20.123 < 10.30.20.0/24`. This block sets the default gateway
+reply parameter. `Fall-Through` is not set, so we are now done with deriving
+the pool name and network options.
+
+The assigned IP address, network and subnet parameters will subsequently be
+returned in the DHCP reply.
+
+=== Testing the subnet-specific options
+
+If you have set any subnet-specific reply parameters then you should test these
+before proceeding further.
+
+For example, in the case that you have a single, large pool spanning two IP
+subnets you might want to test by repeatedly allocating addresses using sample
+packets with different MAC addresses, each time checking to ensure that the
+DHCP parameters correspond to the IP address that has been offered.
+
+.Example output from dhcpclient showing a response
+==================================================
+ dhcpclient: ...
+ ...
+ ----------------------------------------------------------------------
+ Waiting for DHCP replies for: 5.000000
+ ----------------------------------------------------------------------
+ ...
+ DHCP-Your-IP-Address = 10.0.10.50
+ DHCP-Router-Address = 10.0.10.1
+ DHCP-Broadcast-Address = 10.0.10.255
+ DHCP-Subnet-Mask = 255.255.255.255
+==================================================
+
+
+.Example output from dhcpclient showing a response
+==================================================
+ dhcpclient: ...
+ ...
+ ----------------------------------------------------------------------
+ Waiting for DHCP replies for: 5.000000
+ ----------------------------------------------------------------------
+ ...
+ DHCP-Your-IP-Address = 10.99.99.50
+ DHCP-Router-Address = 10.99.99.1
+ DHCP-Broadcast-Address = 10.99.99.255
+ DHCP-Subnet-Mask = 255.255.255.255
+==================================================
+
+
+[TIP]
+====
+If the subnets are large then you might want to temporarily reduce their
+size by setting the `status` field of the majority of the rows for each subnet
+to "`disabled`" to cause offers to be made more readily with IP addresses in
+different subnets.
+====
diff --git a/doc/antora/modules/howto/pages/protocols/dhcp/prepare.adoc b/doc/antora/modules/howto/pages/protocols/dhcp/prepare.adoc
new file mode 100644
index 0000000..aa43530
--- /dev/null
+++ b/doc/antora/modules/howto/pages/protocols/dhcp/prepare.adoc
@@ -0,0 +1,59 @@
+== Preparation
+
+It is necessary to consider the requirements for the installation in order to
+devise an efficient and manageable set up.
+
+=== Understand the network topology
+
+When multiple networks (VLANs) are in use consideration must be given to how
+the correct "pool" (IP address ranges) from which to allocate addresses is
+identified.
+
+The policy for setting specific DHCP options (e.g. lease time, default gateway,
+time server and vendor-specific parameters) for different groups of hosts,
+based on their network or some device attributes either supplied in the DHCP
+requests or determined by dynamic lookup, should be well defined and
+understood.
+
+Other DHCP servers may implement implicit assumptions about the requirement of
+your network topology and silently define particular behaviours, such as the
+selection of IP address pool for a request based on a relay address. Some of
+these behaviours must be specifed explicitly when using FreeRADIUS.
+
+=== Choose a database backend
+
+FreeRADIUS stores its leases in an SQL database, so one of the key decisions to
+make is which database to use.
+
+FreeRADIUS supports:
+
+ * SQLite
+ * PostgreSQL
+ * MySQL / MariaDB
+ * Microsoft SQL Server
+ * Oracle
+
+In most configurations the SQL database is likely to be the limiting component
+that restricts the IP allocation throughput of the overall system. Each
+database server has its own performance characteristics and unique approach to
+features such as high-availability.
+
+The choice of database should be made carefully based on the performance and
+high-availability requirements of the system, as well as any prior experience.
+
+[TIP]
+====
+SQLite is an in-process database that uses the local file system, is simple to
+configure and is suitable for smaller installations. However, users with larger
+address pools or high availability requirements should choose one of the other
+standalone databases based on criteria such as performance, features,
+familiarity and your need for commercial support.
+====
+
+FreeRADIUS ships with a default database schema and set of queries for each
+supported database. These are sufficient for most DHCP deployments but can be
+reviewed and modified as required to suit a particular situation, for example
+to customise the IP allocation policy such as by disabling address
+"stickiness".
+
+Now xref:protocols/dhcp/enable.adoc[enable the DHCP service].
diff --git a/doc/antora/modules/howto/pages/protocols/dhcp/test.adoc b/doc/antora/modules/howto/pages/protocols/dhcp/test.adoc
new file mode 100644
index 0000000..322de08
--- /dev/null
+++ b/doc/antora/modules/howto/pages/protocols/dhcp/test.adoc
@@ -0,0 +1,143 @@
+== Testing the DHCP service
+
+We can verify that FreeRADIUS is providing a DHCP service using the
+`dhcpclient` tool that is included with the FreeRADIUS distribution.
+
+Temporarily configure FreeRADIUS to issue a single static IP address to all
+clients by updating the `dhcp DHCP-Discover` section in the `dhcp` virtual
+server to include the following:
+
+[source,unlang]
+----
+update reply {
+ &DHCP-Your-IP-Address := 1.2.3.4
+}
+----
+
+Define a sample DHCP packet as follows:
+
+[source,shell]
+----
+cat <<EOF > dhcp-packet.txt
+DHCP-Message-Type := DHCP-Discover
+DHCP-Client-Hardware-Address := 02:01:aa:bb:cc:dd
+DHCP-Client-Identifier := abc123
+EOF
+----
+
+We can now generate this packet by invoking one of the following commands based
+on the current circumstances...
+
+From the host that is running the FreeRADIUS DHCP server:
+
+[source,shell]
+----
+dhcpclient -i lo 255.255.255.255 -f dhcp-packet.txt -x auto
+----
+
+From a different host with an interface (eth0) in the same broadcast domain
+as the FreeRADIUS DHCP server:
+
+[source,shell]
+----
+dhcpclient -i eth0 255.255.255.255 -f dhcp-packet.txt -x auto
+----
+
+If all of the DHCP broadcast traffic in other Layer 2 networks is converted to
+unicast by DHCP relay agents then it is not necessary for FreeRADIUS to listen
+on a broadcast address. In this case you can test DHCP using a unicast request:
+
+[source,shell]
+----
+dhcpclient 192.0.2.10 -f dhcp-packet.txt -x auto
+----
+
+[NOTE]
+====
+In order for the returned, unicast DHCP OFFER to be received it is necessary to
+ensure that the `DHCP-Your-IP-Address` parameter set by FreeRADIUS matches an
+address on the interface used by the dhcpclient tool to send the Discover
+packet.
+====
+
+When one of the above commands is run, the tool with generate output such as
+the following which shows that the packet was sent and that it is now waiting
+for replies:
+
+.Example output from dhcpclient showing the request
+===================================================
+ dhcpclient: ...
+ ----------------------------------------------------------------------
+ DHCP-Opcode = 0x01
+ DHCP-Hardware-Type = 0x01
+ DHCP-Hardware-Address-Length = 0x06
+ DHCP-Hop-Count = 0x00
+ DHCP-Transaction-Id = 0x5e0bbfab
+ DHCP-Number-of-Seconds = 0x0000
+ DHCP-Flags = 0x0000
+ DHCP-Client-IP-Address = 0x00000000
+ DHCP-Your-IP-Address = 0x00000000
+ DHCP-Server-IP-Address = 0x00000000
+ DHCP-Gateway-IP-Address = 0x00000000
+ ...
+ ----------------------------------------------------------------------
+ Waiting for DHCP replies for: 5.000000
+ ----------------------------------------------------------------------
+===================================================
+
+
+Each received DHCP response will generate output such as the following:
+
+.Example output from dhcpclient showing a response
+==================================================
+ ...
+ ----------------------------------------------------------------------
+ DHCP-Opcode = Server-Message
+ DHCP-Hardware-Type = Ethernet
+ DHCP-Hardware-Address-Length = 6
+ DHCP-Hop-Count = 0
+ DHCP-Transaction-Id = 1577828267
+ DHCP-Number-of-Seconds = 0
+ DHCP-Flags = 0
+ DHCP-Client-IP-Address = 0.0.0.0
+ DHCP-Your-IP-Address = 1.2.3.4
+ DHCP-Server-IP-Address = 192.0.2.10
+ DHCP-Gateway-IP-Address = 0.0.0.0
+ DHCP-Client-Hardware-Address = 02:42:0a:00:00:0b
+ DHCP-Message-Type = DHCP-Offer
+ DHCP-Client-Identifier = 0x616263313233
+ Waiting for additional DHCP replies for: 4.999429
+ ...
+==================================================
+
+Examine the DHCP response to ensure that it has the correct message type
+(`DHCP-Offer`, in this case), contains the temporary IP address that you
+configured earlier, i.e. `DHCP-Your-IP-Address = 1.2.3.4`, and any other
+expected reply parameters (which we configure later). You should also carefully
+examine the output of a FreeRADIUS debug session (`radius -X`) to ensure that
+the policy is being executed in the way that you expect and that no warnings
+are being generated.
+
+You can now change the content of the sample DHCP request by editing the
+`dhcp-packet.txt` file and re-run the above command to see the server's reply.
+You should examine the DHCP dictionary distrubuted with FreeRADIUS (usually
+`/usr/share/freeradius/dictionary.dhcp`) which provides the list of all of the
+DHCP parameters ("attributes") understood by FreeRADIUS.
+
+[WARNING]
+====
+When you are done **remember** to remove the temporary edit that was made to
+the `dhcp` virtual server that provides the static IP assignment.
+====
+
+=== Testing the DHCP policy
+
+The remainder of this guide describes how to configure the IP address plan,
+setup the IP pools and define a DHCP policy. You should develop your policy by
+making small, incremental changes to the provided configuration and then test
+those changes with the approach described above, using `dhcpclient` and `radius -X`,
+modifying the sample DHCP packet as required. If you break the policy then
+revert the last change, attempt to understand what went wrong, and try
+something else.
+
+Now xref:protocols/dhcp/policy.adoc[define the DHCP policy].
diff --git a/doc/antora/modules/howto/pages/protocols/proxy/enable_proxy_protocol.adoc b/doc/antora/modules/howto/pages/protocols/proxy/enable_proxy_protocol.adoc
new file mode 100644
index 0000000..b689824
--- /dev/null
+++ b/doc/antora/modules/howto/pages/protocols/proxy/enable_proxy_protocol.adoc
@@ -0,0 +1,114 @@
+== Enabling PROXY Protocol
+
+Now that we have a working configuration which used RadSec and HAproxy
+or Traefik, we are finally ready to enable PROXY Protocol.
+
+Configure FreeRADIUS on the `radsecsvr` host to expect the PROXY
+Protocol for RadSec connections. This is done by editing the `listen
+{}` section of the `tls` virtual server to include a reference to the
+proxy protocol:
+
+.Enabling PROXY Protocol in a FreeRADIUS virtual server
+=======================================================
+
+ listen {
+ ...
+ proxy_protocol = true
+ ...
+ }
+
+=======================================================
+
+Now restart the debugging session:
+[source,shell]
+----
+radiusd -fxxl /dev/stdout
+----
+
+
+For HAproxy, you should enable the PROXY Protocol on connections to
+the RadSec backend, by editing the `backend` definition to add a
+`send-proxy` argument:
+
+.Example HAproxy backend configuration with PROXY Protocol
+==========================================================
+
+ backend radsec_be
+ mode tcp
+ balance roundrobin
+ server radsecsvr 172.23.0.3:2083 send-proxy
+
+==========================================================
+
+Note the `send-proxy` argument in the `server` definition.
+
+Now reload the HAproxy service:
+
+[source,shell]
+----
+service haproxy reload
+---
+
+
+For Traefik, enable the PROXY Protocol on connections to the RadSec
+backend by editing the `radsec-service` definition to add a reference
+to the proxy protocol"
+
+.Example Traefik service configuration with PROXY Protocol
+==========================================================
+
+ radsec-service:
+ loadBalancer:
+ servers:
+ - address: "172.23.0.3:2083"
+ proxyProtocol:
+ version: 1
+
+==========================================================
+
+Note the `proxyProtocol` and `version: 1` directives.
+
+Traefik should automatically detect the updates and reconfigure the
+service.
+
+
+=== Testing RadSec connectivity via a proxy using PROXY Protocol
+
+Finally, with your test client configured to use the proxy, perform a
+test authentication:
+
+[source,shell]
+----
+ echo "User-Name = bob" | radclient 127.0.0.1 auth testing123
+----
+
+You should expect to see the familiar output:
+
+.Example output from radclient
+==============================
+
+ Sent Access-Request Id 252 from 0.0.0.0:50118 to 127.0.0.1:1812 length 27
+ Received Access-Accept Id 252 from 127.0.0.1:1812 to 127.0.0.1:50118 length 39
+
+==============================
+
+Now examine the FreeRADIUS debug output on the RadSec server:
+
+.Expected output from `radiusd -X` with PROXY Protocol
+======================================================
+
+ ...
+ (0) (TLS) Received PROXY protocol connection from client \
+ 172.23.0.2:55343 -> 172.23.0.4:2083, via proxy 172.23.0.4:40268 -> 0.0.0.0:2083
+ ...
+ (0) Received Access-Request Id 227 from 172.23.0.2:55343 to 172.23.0.4:2083 length 49
+ (0) Sent Access-Accept Id 227 from 172.23.0.4:2083 to 172.23.0.2:55343 length 0
+ ...
+
+======================================================
+
+The output indicates that FreeRADIUS is receiving the originating
+connection information from the PROXY Protocol. FreeRADIUS then
+handles the RadSec requests as though they have been received directly
+from the originating client.
+
diff --git a/doc/antora/modules/howto/pages/protocols/proxy/enable_radsec.adoc b/doc/antora/modules/howto/pages/protocols/proxy/enable_radsec.adoc
new file mode 100644
index 0000000..f5e7603
--- /dev/null
+++ b/doc/antora/modules/howto/pages/protocols/proxy/enable_radsec.adoc
@@ -0,0 +1,188 @@
+== Enabling RadSec with FreeRADIUS
+
+Our first task is to set up a RadSec server by configuring an instance of
+FreeRADIUS to accept RADIUS over TLS requests.
+
+The following steps should be performed on the host which will be the
+RadSec server, we will call it `radsecsvr`.
+
+You can install FreeRADIUS using the NetworkRADIUS packages by
+following the instructions provided here:
+
+<https://networkradius.com/packages/>
+
+Before making any configuration changes, you should stop the radiusd
+service:
+
+[source,shell]
+----
+ service radiusd stop
+----
+
+Then, enable the `tls` virtual server:
+
+[source,shell]
+----
+cd /etc/raddb/sites-enabled
+ln -s ../sites-available/tls
+----
+
+The FreeRADIUS distribution contains an example Certificate Authority
+that will have generated the necessary CA, server and client
+certificates and keys during package installation. You can use this
+CA, or you can use your own CA and certificates.
+
+[TIP]
+====
+If the example certificates are not present (for example if FreeRADIUS was
+installed from source) then FreeRADIUS will fail to start. The files can be
+regenerated by running `make` in the `/etc/raddb/certs` directory.
+====
+
+Edit the `tls` virtual server configuration, in order to add
+definitions for the clients by extending the `clients radsec {}` section:
+
+.Example radsec client definitions in `/etc/raddb/sites-available/tls`
+====
+
+ clients radsec {
+ ...
+ # Direct connections from the test client
+ client radseccli {
+ ipaddr = 172.23.0.2
+ proto = tls
+ virtual_server = default
+ }
+ # Connections via HAproxy
+ client haproxy {
+ ipaddr = 172.23.0.4
+ proto = tls
+ virtual_server = default
+ }
+ # Connections via Traefik
+ client traefik {
+ ipaddr = 172.23.0.5
+ proto = tls
+ virtual_server = default
+ }
+ }
+
+====
+
+The client `ipaddr` configuration item is used to match the source IP
+address of incoming connections. You must add client definitions for
+each of the clients which will connect.
+
+For RadSec, you can just list the IP address of the RadSec client.
+This client definition is used for processing RADIUS packets from the
+RadSec client.
+
+[NOTE]
+====
+A `secret` does not have to be specified for RadSec clients, as the
+default is `radsec`. If you specify a secret, then that will be used
+instead of `radsec`.
+====
+
+When the PROXY protocol is used, you must _also_ define a client which
+matches the IP address of the proxy (haproxy, etc). This client is
+only used to check that the source IP is permitted to connect to the
+server. Fields other than `ipaddr` can be specified (and in some
+cases may be required). However, all other fields will be ignored.
+
+For testing purposes, we want to amend the `default` virtual server so
+that it accepts all authentication reqeusts and immediately responds
+to accounting requests.
+
+Edit the `/etc/raddb/sites-enabled/default` file so that the beginning of
+the `authorize` and `preacct` sections looks as follows:
+
+.Example default virtual server modification to unconditionally accept Access-Requests
+====
+
+ authorize {
+ accept
+ ...
+ }
+ ...
+ preacct {
+ handled
+ ...
+ }
+
+====
+
+This change makes the `authorize` section always "accept" the user,
+and makes the `preacct` section always say "we handled the accounting
+request". These changes are only for testing, and should never be
+used in production.
+
+Start the FreeRADIUS service in the foreground with debugging enabled:
+
+[source,shell]
+----
+radiusd -fxxl /dev/stdout
+----
+
+Examine the output from FreeRADIUS to ensure that it is now listening for
+RadSec connection on TCP/2083:
+
+.Example output from running `radiusd -fxxl /dev/stdout`
+====
+
+ FreeRADIUS Version 3.0.24
+ Copyright (C) 1999-2021 The FreeRADIUS server project and contributors
+ ...
+ ... : Debug: Listening on auth+acct proto tcp address * port 2083 (TLS) bound to server default
+ ... : Debug: Listening on auth address * port 1812 bound to server default
+ ... : Debug: Listening on acct address * port 1813 bound to server default
+ ... : Debug: Listening on auth address :: port 1812 bound to server default
+ ... : Debug: Listening on acct address :: port 1813 bound to server default
+ ...
+ ... : Info: Ready to process requests
+
+====
+
+FreeRADIUS is now ready to process RadSec traffic.
+
+For testing, we first test normal RADIUS over UDP functionality, then
+the RadSec connection using a test client, then introduce a proxy
+server, and finally we enable PROXY Protocol. Doing the tests in this
+way ensures that we know that all previous steps work before trying
+the next step. This process allows us to quickly narrow down
+problems, and gets us to the final goal _faster_ than just "doing
+everything all at once".
+
+=== Testing the RADIUS policy
+
+Before moving on, verify that the FreeRADIUS policy is able to
+authenticate a local test RADIUS Access-Request over UDP:
+
+[source,shell]
+----
+echo "User-Name = terry" | radclient 127.0.0.1 auth testing123
+----
+
+Due to the `accept` we added in the `authorize` section, the expected
+output should be an Access-Accept:
+
+.Expected output from radclient
+===============================
+
+ Sent Access-Request Id 157 from 0.0.0.0:36850 to 127.0.0.1:1812 length 27
+ Received Access-Accept Id 157 from 127.0.0.1:1812 to 127.0.0.1:36850 length 20
+
+===============================
+
+Any other output indicates that there is a problem with the FreeRADIUS
+configuration which *must* be solved before testing RadSec. Carefully verify that
+you have carried out each of the above steps correctly and examine the debug
+output from FreeRADIUS, which will usually tell you what is wrong.
+
+See [how to read the debug
+output](http://wiki.freeradius.org/radiusd-X) for instructions on
+reading amd understanding the debug output.
+
+The next step is to xref:protocols/proxy/radsec_client.adoc[configure
+FreeRADIUS as a RadSec test client] so that we can verify that our
+RadSec server is working.
diff --git a/doc/antora/modules/howto/pages/protocols/proxy/index.adoc b/doc/antora/modules/howto/pages/protocols/proxy/index.adoc
new file mode 100644
index 0000000..5100635
--- /dev/null
+++ b/doc/antora/modules/howto/pages/protocols/proxy/index.adoc
@@ -0,0 +1,126 @@
+= Proxying RadSec and enabling PROXY Protocol
+
+This guide shows how to set up FreeRADIUS to serve RadSec connections, fronted
+by either HAproxy or Traefik as Layer 4 proxies that pass on the original
+client connection information using PROXY Protocol.
+
+It is not a comprehensive guide to using RadSec with FreeRADIUS. It presents a
+basic configuration that uses an example CA and does not validate certificate
+attributes or perform revokation status.
+
+
+== Introduction
+
+FreeRADIUS supports receiving RADIUS requests over TLS-enabled TCP connections
+and supports proxying of requests over TCP connections to another TLS-enabled
+homeserver. The protocol for RADIUS over TLS is called "RadSec" and is defined
+in RFC 6614.
+
+FreeRADIUS is a capable and performant application-aware ("Layer 7") proxy /
+load-balancer for RadSec and other forms of RADIUS traffic.
+
+
+=== Layer 4 proxying
+
+Rather than use an application-aware proxy it is sometimes better to reduce the
+performance impact incurred by re-encoding an application protocol by using a
+"Layer 4" proxy that operates at the level of individual connections without
+regard for the application protocol. Such a proxy is more of a "bump in the
+wire" than a request buffer and minimises the latency incurred due to proxying.
+
+It is common to see software such as HAproxy and Traefik used in Layer 4 mode
+in place of FreeRADIUS for purposes such as connection load balancing. In
+addition to improved performance, these tools have the benefit that they
+typically support dynamic service discovery and "hitless" reloads to
+automatically adapt their connection routing based on changes to backend
+services such as the introduction of new nodes with even a momentary loss of
+service.
+
+
+=== Loss of connection information
+
+When TCP connections are relayed through Layer 4 proxies the information
+about the originating source of the connection is no longer known to the
+backend service, unless it is otherwise made available. Identifying the
+originator of connections is often necessary for security purposes and for
+request processing.
+
+Whilst many application protcols support headers that allow proxies to preserve
+connection information these are not helpful in the context of Layer 4
+proxying: The process of populating headers requires knowledge of the
+application protocol to re-encode requests as they are transmitted between the
+frontend and backend connections.
+
+
+=== PROXY Protocol
+
+PROXY Protocol overcomes this limitation by allowing the original connection
+information to be provided to the backend at the start of the TCP connection.
+After this initial data is encoded the remainder of the conversation then
+proceeds as normal. However now that the connection information is known to the
+backend server it is able to process requests made on the connection as though
+the connection were being made directly by the client and not via the proxy.
+
+PROXY Protocol is specified in this document:
+http://www.haproxy.org/download/1.8/doc/proxy-protocol.txt
+
+
+== Requirements
+
+PROXY Protocol Version 1 is supported by FreeRADIUS v3.0.24 and later versions.
+
+You will require the following set of VMs or containers, each with their own
+IP address:
+
+[cols="1,1,1"]
+|===
+|Hostname|IP address|Purpose
+
+|radseccli
+|172.23.0.2
+|FreeRADIUS configured to provide a RadSec test client
+
+|radsecsvr
+|172.23.0.3
+|FreeRADIUS configured as a RadSec server
+
+|haproxy
+|172.23.0.4
+|HAproxy in Layer 4 mode to the FreeRADIUS RadSec backend
+|===
+
+Optionally you may want to configure a host to run Traefik within a Docker
+container using host mode networking, perhaps configured by Docker Compose,
+however the installation is beyond the scope of this guide:
+
+[cols="1,1,1"]
+|===
+|traefik
+|172.23.0.5
+|Traefik configured as a TCP router with TLS passthrough to the FreeRADIUS RadSec backend
+|===
+
+The hostnames and IP addresses provided above are for examples purposes and are
+used throughout the remainder of this guide. This guide provides commands and
+output for CentOS. Other distributions will have minor differences, including
+the location of the FreeRADIUS configuration (the "raddb").
+
+[NOTE]
+====
+You can choose to use your own hostname, IP addresses and OS distribution. You
+could also use official Docker images provided by the respecitive projects,
+however these prescribe methods for configuring and managing the services
+that are not typical for a normal package installation which would provide a
+distraction if used for by guide.
+====
+
+
+== Sections in this guide
+
+This guide is organised into four parts that should be read in order:
+
+1. xref:protocols/proxy/enable_radsec.adoc[Enabling RadSec]
+2. xref:protocols/proxy/radsec_client.adoc[Configuring a test RadSec client]
+3. xref:protocols/proxy/radsec_with_haproxy.adoc[Proxying RadSec with HAproxy]
+4. xref:protocols/proxy/radsec_with_traefik.adoc[Proxying RadSec with Traefik]
+5. xref:protocols/proxy/enable_proxy_protocol.adoc[Enabling PROXY Protocol for RadSec]
diff --git a/doc/antora/modules/howto/pages/protocols/proxy/radsec_client.adoc b/doc/antora/modules/howto/pages/protocols/proxy/radsec_client.adoc
new file mode 100644
index 0000000..d92345e
--- /dev/null
+++ b/doc/antora/modules/howto/pages/protocols/proxy/radsec_client.adoc
@@ -0,0 +1,181 @@
+== Configuring FreeRADIUS as a RadSec test client
+
+Unfortunately, the `radclient` program does not support RadSec. We
+must therefore configure an instance of FreeRADIUS as a "transport
+converter" which proxies UDP-based RADIUS requests to a RadSec
+destination of our choice.
+
+The following steps should be performed on a client system, which we
+will call `radseccli`. This system should be a new system, with a
+different IP address. That is, you shoudl not edit the configuration
+on the `radsecsvr` host. Doing so will break the RadSec configuration.
+
+Install FreeRADIUS using the NetworkRADIUS packages by following the
+instructions provided here:
+
+<https://networkradius.com/packages/>
+
+Before making any configuration changes, you should stop the radiusd
+service:
+
+[source,shell]
+----
+ service radiusd stop
+----
+
+Add a new `tls` home server definition, which will point to the RadSec
+server. We do this by creating a file
+`/etc/raddb/sites-enabled/radsec-homeserver` with the following
+contents:
+
+.Example homeserver, pool and realm definitions for the RadSec service
+====
+
+ home_server tls {
+ ipaddr = 172.23.0.3 # IP address of our RadSec server
+ port = 2083
+ type = auth+acct
+ proto = tcp
+ tls {
+ private_key_password = whatever
+ private_key_file = ${certdir}/client.pem
+ certificate_file = ${certdir}/client.pem
+ ca_file = ${cadir}/ca.pem
+ }
+ }
+ home_server_pool tls {
+ type = fail-over
+ home_server = tls
+ }
+ realm tls {
+ auth_pool = tls
+ acct_pool = tls
+ }
+
+====
+
+[TIP]
+====
+Complete descriptions of each of the above configuration items can be found in the
+`[raddb]/sites-available/tls` example configuration file. For simple tests, however,
+we can omit all of the comments from the file.
+====
+
+To use this `tls` home server, we change the `default` virtual server to proxy
+all authentication and accounting requests to it.
+
+Edit the `/etc/raddb/sites-enabled/default` file so that the beginning of
+the `authorize` and `preacct` sections looks as follows:
+
+.Example default virtual server modification to proxy requests to a RadSec proxy server
+====
+
+ authorize {
+ update control {
+ &Proxy-To-Realm := tls
+ }
+ handled
+ ...
+ }
+ ...
+ preacct {
+ update control {
+ &Proxy-To-Realm := tls
+ }
+ handled
+ ...
+ }
+
+====
+
+These changes make the `tls` virtual server always proxy packets.
+These changes are only for testing, and should never be used in
+production.
+
+We must now copy the example CA certificate as well as the client
+certificate and key files which are on the `radsecsrv` host to this
+test client.
+
+Replace the following files on `radseccli` with the equivalent files from
+`radsecsrv`:
+
+[cols="1,1,1"]
+|===
+|File|Corresponding configuration item|Purpose
+
+|/etc/raddb/certs/ca.pem
+|`ca_file`
+|CA certificate which is used to authenticate the server certificate presented by the RadSec server to the client.
+
+|/etc/raddb/certs/client.pem
+|`certificate_file`
+|Client certificate (signed by the CA certificate) that is presented by the test client to the RadSec server.
+
+|/etc/raddb/certs/client.pem
+|`private_key_file` and `private_key_password`
+|Private key corresponding to the client certificate
+|===
+
+Note that the client certificate and key are typically bundled into a single file.
+
+[CAUTION]
+====
+If you do not correctly replace the CA, client certificate, and key
+material on the test client then the RadSec client and RadSec server
+will fail to mutually authenticate each other as they do not share a
+trusted CA. If you see messages like `unknown CA`, then you know that
+the certificates have not been set up correctly.
+====
+
+Start the FreeRADIUS service in debug mode:
+
+[source,shell]
+----
+radiusd -X
+----
+
+
+=== Testing RadSec connectivity
+
+At this stage you should be able to cause the test client to send RadSec
+requests directly to the RadSec server.
+
+Run the following to send a RADUS (UDP) Access-Request to the local FreeRADIUS
+instance. It should then proxy the request over RadSec connection to
+the remote RadSec server:
+
+[source,shell]
+----
+ echo "User-Name = bob" | radclient 127.0.0.1 auth testing123
+----
+
+If the test client is able to successfully establish the RadSec
+connection, and the RadSec server replies with an Access-Accept
+response, then the output will be as follows:
+
+.Expected output from radclient
+===============================
+
+ Sent Access-Request Id 252 from 0.0.0.0:50118 to 127.0.0.1:1812 length 27
+ Received Access-Accept Id 252 from 127.0.0.1:1812 to 127.0.0.1:50118 length 39
+
+===============================
+
+Lack of response or an Access-Reject response indicates that the RadSec
+connection is not being established successfully.
+
+There may be serveral reasons for broken connectivity including:
+
+ * The client not accepting the certificate presented by the server.
+ * The server not accepting the certificate presented by the client.
+
+Look at the debug output generated by both the test client and the RadSec
+server. In many cases it will tell you exactly what the problem is.
+
+Do not proceed with any further steps until direct connections between the
+RadSec client and Radsec Server are working properly.
+
+Once things are working we are ready to
+xref:protocols/proxy/radsec_with_haproxy.adoc[configure HAproxy to proxy RadSec
+connections] or to xref:protocols/proxy/radsec_with_traefik.adoc[configure
+Traefik to proxy RadSec connections].
diff --git a/doc/antora/modules/howto/pages/protocols/proxy/radsec_with_haproxy.adoc b/doc/antora/modules/howto/pages/protocols/proxy/radsec_with_haproxy.adoc
new file mode 100644
index 0000000..e58abfe
--- /dev/null
+++ b/doc/antora/modules/howto/pages/protocols/proxy/radsec_with_haproxy.adoc
@@ -0,0 +1,134 @@
+== Proxying RadSec with HAproxy
+
+This section shows how to configure HAproxy to proxy RadSec connections.
+
+The following steps should be performed on the `haproxy` host, unless otherwise
+stated.
+
+Install the HAproxy package supplied with the OS distribution:
+
+[source,shell]
+----
+ yum install haproxy
+----
+
+Stop the haproxy service:
+
+[source,shell]
+----
+ service haproxy stop
+----
+
+Modify the haproxy configuration (typically `/etc/haproxy/haproxy.conf`) so
+that it includes new frontend and backend configuration for the radsec service:
+
+.Example minimal HAproxy configuration
+======================================
+
+ global
+ maxconn 100
+ defaults
+ mode tcp
+ timeout connect 10s
+ timeout client 30s
+ timeout server 30s
+ frontend radsec_fe
+ bind *:2083
+ default_backend radsec_be
+ backend radsec_be
+ balance roundrobin
+ server radsecsvr 172.23.0.3:2083
+
+======================================
+
+Note the `mode tcp` directive which tells HAproxy to act as a Layer 4
+proxy, so that it doesn't attempt to perform SSL termination or
+decode the RADIUS protocol.
+
+[NOTE]
+====
+The above example is a minimal configuration. In practise you will want to
+retain many of the HAproxy configuration items already present in the
+configuration (e.g. `log`, `chroot`, `user`, `group`), but these vary across
+distributions. Other HTTP-related options that may already exist in the
+configuration will conflict with `mode tcp` (Layer 4 proxying) and should be
+removed if HAproxy complains about them.
+
+However, you should first get things working with the minimal
+configuration which is known to work, and then make customisations.
+If you start off with a complex configuration, then there may be a
+large number of things which are broken, and debugging them all will
+be difficult. Start simple, and then add complexity!
+====
+
+Restart the haproxy service in foreground mode for debugging purposes:
+
+[source,shell]
+----
+haproxy -f /etc/haproxy/haproxy.cfg -db
+----
+
+
+=== Testing RadSec connectivity via HAproxy
+
+Now edit the test RadSec client, so that instead of making connections directly
+to the RadSec server it makes connections to the HAproxy server.
+
+On `radseccli` edit the `/etc/raddb/sites-enabled/tls` file, and set
+the IP address to the address of the `haproxy` host.
+
+.Example updated test client homeserver configuration
+=====================================================
+
+ home_server tls {
+ ipaddr = 172.23.0.4 # Updated from radsecsvr to haproxy
+ ...
+ }
+
+=====================================================
+
+Restart the debug mode session:
+
+[source,shell]
+----
+radiusd -X
+----
+
+Perform a test authentication:
+
+[source,shell]
+----
+ echo "User-Name = bob" | radclient 127.0.0.1 auth testing123
+----
+
+If the test client is able to successfully establish the RadSec
+connection via HAproxy, and the RadSec server replies with an
+Access-Accept response, then the output will be as follows:
+
+.Expected output from radclient
+===============================
+
+ Sent Access-Request Id 252 from 0.0.0.0:50118 to 127.0.0.1:1812 length 27
+ Received Access-Accept Id 252 from 127.0.0.1:1812 to 127.0.0.1:50118 length 39
+
+===============================
+
+HAproxy should also log a message that indicates that the connection was
+proxied, such as the following:
+
+.Expected output from HAproxy
+=============================
+
+ <150>...: Connect from 172.23.0.2:50087 to 172.23.0.4:2083 (radius_fr/TCP)
+
+=============================
+
+Any other output from radclient or HAproxy indicates that there is a
+problem with the HAproxy configuration, or that FreeRADIUS is not
+accepting connection from the `haproxy` host, which must be solved
+before continuing.
+
+Once proxied connections are working we are ready to
+xref:protocols/proxy/enable_proxy_protocol.adoc[enable the PROXY
+Protocol] on both HAproxy and the RadSec server.
+
diff --git a/doc/antora/modules/howto/pages/protocols/proxy/radsec_with_traefik.adoc b/doc/antora/modules/howto/pages/protocols/proxy/radsec_with_traefik.adoc
new file mode 100644
index 0000000..11030e9
--- /dev/null
+++ b/doc/antora/modules/howto/pages/protocols/proxy/radsec_with_traefik.adoc
@@ -0,0 +1,128 @@
+== Proxying RadSec with Traefik
+
+This section shows how to configure Traefik to proxy RadSec connections. You
+should skip this section if you are not using Traefik as your proxy.
+
+Installing Traefik is beyond the scope of this guide. It is typically installed
+as a service mesh router within a Docker or Kubernetes environment using
+offical Docker images.
+
+Traefik configuration has two components of interest:
+
+ * Static configuration: Defines "entrypoints" on which Traefik listens for connections.
+ * Dynamic configuration: Defines backend service components and the routing policy.
+
+Traefik supports a number of providers of dynamic configuration data for the
+router and service definitions. For demonstration purposes the files provider
+is used here, however you can switch to another provide once you have things
+working using this method.
+
+The static configuration can be provided by starting Traefik with the following
+arguments:
+
+.Example Traefik static configuration
+=====================================
+
+ traefik \
+ --log.level=DEBUG \
+ --providers.file.filename=/etc/traefik/dynamic_config.yml
+ --providers.file.watch=true
+ --entryPoints.radsec.address=:2083
+
+=====================================
+
+Note that a `radsec` entrypoint is defined to listen on port 2083 and that a
+static `file` provider is used to defined the dynamic services.
+
+The backend for RadSec should be defined in this file as follows:
+
+.Example Traefik dynamic configuration
+======================================
+
+ tcp:
+ routers:
+ radsec-router:
+ entryPoints:
+ - radsec
+ rule: "HostSNI(`*`)"
+ service: "radsec-service"
+ tls:
+ passthrough: true
+ services:
+ radsec-service:
+ loadBalancer:
+ servers:
+ - address: "172.23.0.3:2083"
+
+======================================
+
+Note the `passthrough: true` directive under `tls:` which tells Treafik not to
+attempt TLS termination which it would otherwise perform for all incoming TLS
+connections. We require that the connection is passed through from the RadSec
+client to the RadSec server without being reterminated since the end client's
+certificate is authenticated by the RadSec server and many be used for
+policy decisions.
+
+
+=== Testing RadSec connectivity via Traefik
+
+Now amend the test RadSec client so that instead of making connections directly
+to the RadSec server it makes them via Traefik.
+
+On `radseccli` amend `/etc/raddb/sites-enabled/tls` and set the IP address to
+that of the `traefik` host.
+
+.Example updated test client homeserver configuration
+=====================================================
+
+ home_server tls {
+ ipaddr = 172.23.0.5 # Updated from radsecsvr to traefik
+ ...
+ }
+
+=====================================================
+
+Restart the debug mode session:
+
+[source,shell]
+----
+radiusd -X
+----
+
+Perform a test authentication:
+
+[source,shell]
+----
+ echo "User-Name = bob" | radclient 127.0.0.1 auth testing123
+----
+
+If the test client is able to successfully establish the RadSec connection via
+Traefik and the RadSec server replies with an Access-Accept response then the
+output will be as follows:
+
+.Example output from radclient
+==============================
+
+ Sent Access-Request Id 252 from 0.0.0.0:50118 to 127.0.0.1:1812 length 27
+ Received Access-Accept Id 252 from 127.0.0.1:1812 to 127.0.0.1:50118 length 39
+
+==============================
+
+Traefik should also log a message that indicates that the connection was
+proxied, such as the following:
+
+.Example output from Traefik
+============================
+
+ time="..." level=debug msg="Handling connection from 172.23.0.2:57367"
+
+============================
+
+Any other output from radclient or Traefik indicates that there is a problem
+with the Traefik configuration or that FreeRADIUS is not accepting connection
+from the `traefik` host, which must be solved before continuing.
+
+Once proxied connections are working we are ready to
+xref:protocols/proxy/enable_proxy_protocol.adoc[enable the PROXY Protocol] on
+both Traefik and the RadSec server.
+
diff --git a/doc/antora/modules/installation/nav.adoc b/doc/antora/modules/installation/nav.adoc
new file mode 100644
index 0000000..26ce32e
--- /dev/null
+++ b/doc/antora/modules/installation/nav.adoc
@@ -0,0 +1,5 @@
+* xref:index.adoc[Installing and upgrading]
+** xref:packages.adoc[Install from packages]
+** xref:dependencies.adoc[Dependencies]
+** xref:source.adoc[Build from source]
+** xref:upgrade.adoc[Upgrading to v3]
diff --git a/doc/antora/modules/installation/pages/dependencies.adoc b/doc/antora/modules/installation/pages/dependencies.adoc
new file mode 100644
index 0000000..e910e76
--- /dev/null
+++ b/doc/antora/modules/installation/pages/dependencies.adoc
@@ -0,0 +1,58 @@
+= FreeRADIUS Dependencies
+
+Some external dependencies must be installed before building or
+running FreeRADIUS. The core depends on two mandatory libraries:
+`libtalloc` for memory management and `libkqueue` for event
+handling.
+
+Many of the modules also have optional dependencies. For example,
+the LDAP module requires LDAP client libraries to be installed
+and database modules need their respective database client
+libraries.
+
+If building from source code, the configure stage will check for
+the optional dependencies. Any missing libraries will cause that
+particular module to be skipped.
+
+== Libraries
+
+=== libtalloc
+
+Talloc is a memory allocation library available at
+https://talloc.samba.org/talloc/doc/html/index.html
+
+*OSX*
+
+`# brew install talloc`
+
+*Debian, Ubuntu and `dpkg`-based systems*
+
+`# apt-get install libtalloc-dev`
+
+*RedHat or CentOS*
+
+```
+# subscription-manager repos --enable rhel-7-server-optional-rpms
+# yum install libtalloc-dev
+```
+
+=== kqueue
+
+Kqueue is an event / timer API originally written for BSD systems.
+It is _much_ simpler to use than third-party event libraries. A
+library, `libkqueue`, is available for Linux systems.
+
+*OSX*
+
+_kqueue is already available, there is nothing to install._
+
+*Debian, Ubuntu and `dpkg`-based systems*
+
+`# apt-get install libkqueue-dev`
+
+*RedHat or CentOS*
+
+```
+# subscription-manager repos --enable rhel-7-server-optional-rpms
+# yum install libkqueue-dev
+```
diff --git a/doc/antora/modules/installation/pages/index.adoc b/doc/antora/modules/installation/pages/index.adoc
new file mode 100644
index 0000000..b810078
--- /dev/null
+++ b/doc/antora/modules/installation/pages/index.adoc
@@ -0,0 +1,15 @@
+== Installation
+
+FreeRADIUS is available from multiple sources:
+
+* Official xref:packages.adoc[Network RADIUS packages]
+* xref:source.adoc[Source code]
+* Many Operating System distributions
+
+We highly recommend using the official packages from Network
+RADIUS, where available.
+
+The documents in this section cover details of the above
+installation methods, as well as instructions on building
+packages locally.
+
diff --git a/doc/antora/modules/installation/pages/packages.adoc b/doc/antora/modules/installation/pages/packages.adoc
new file mode 100644
index 0000000..ffc52cd
--- /dev/null
+++ b/doc/antora/modules/installation/pages/packages.adoc
@@ -0,0 +1,22 @@
+== Install from packages
+
+Network RADIUS provide pre-built binary packages of FreeRADIUS for
+common Linux distributions. This is the recommended installation
+method when packages are available for your system.
+
+The official http://packages.networkradius.com[Network RADIUS
+packages] page contains recent FreeRADIUS packages and
+installation instructions.
+
+=== Distribution-supplied packages
+
+While many Operating System distributions ship FreeRADIUS
+packages, the versions they include are often years out of date.
+As well as missing out on the latest bug fixes and features, this
+also means that it is very hard to know if an issue encountered is
+still a problem or if it is fixed in the latest release.
+
+Therefore, whilst the distribution-supplied packages can often be
+the most convenient to install, we do not usually recommend using
+them.
+
diff --git a/doc/antora/modules/installation/pages/source.adoc b/doc/antora/modules/installation/pages/source.adoc
new file mode 100644
index 0000000..cf40a79
--- /dev/null
+++ b/doc/antora/modules/installation/pages/source.adoc
@@ -0,0 +1,199 @@
+== Building from Source
+
+We recommend xref:packages.adoc[installing from packages] if
+possible. Full instructions on building and installing from source
+code follow.
+
+The mandatory xref:installation:dependencies.adoc[dependencies]
+must be installed before FreeRADIUS can be built. These dependencies
+are `libtalloc` and `libkqueue`, which FreeRADIUS uses for memory
+management, and platform-independent event handling.
+
+Per-module dependencies that enable support for external services
+such as LDAP, SQL, etc, are optional. They must be installed for
+any modules that are to be used. The FreeRADIUS `./configure` step
+will automatically detect if each module has its dependencies met
+and automatically enable support for them. If the features you
+require are not enabled you should inspect the configure script
+output to figure out which additional development libraries need
+to be installed.
+
+The FreeRADIUS source may be obtained from a number of locations:
+
+* Download the latest version of the FreeRADIUS source from
+ https://www.freeradius.org/releases/[the FreeRADIUS web site]; or
+* download directly from the
+ ftp://ftp.freeradius.org/pub/freeradius/[FreeRADIUS FTP site]; or
+* download from
+ https://github.com/FreeRADIUS/freeradius-server/[GitHub].
+
+The file wil be name something like: `freeradius-server-3.0.22.tar.gz`.
+Later versions will be `3.0.23`, or `4.0.0`, etc. PGP signatures are
+also provided for official releases from the FTP site; these are
+named e.g. `freeradius-server-3.0.22.tar.gz.sig`.
+
+Un-tar the file, and change to the FreeRADIUS directory (where
+`VERSION` below is the version of the server that you have
+downloaded).
+
+[source,shell]
+----
+tar -zxf freeradius-server-VERSION.tar.gz
+cd freeradius-server-VERSION
+----
+
+Take the following steps to build and install the server from source:
+
+[source,shell]
+----
+./configure
+make
+sudo make install
+----
+
+=== Custom build
+
+FreeRADIUS has GNU autoconf support. This means you have to run
+`./configure`, and then run `make`. To see which configuration
+options are supported, run `./configure --help`, and read its output.
+
+The `make install` stage will install the binaries, the "man" pages,
+and _may_ install the configuration files. If you have not installed a
+RADIUS server before, then the configuration files for FreeRADIUS will
+be installed.
+
+If you already have a RADIUS server installed, then *FreeRADIUS
+WILL NOT over-write your current configuration.*
+
+The `make install` process will warn you about the files it could not
+install.
+
+If you see a warning message about files that could not be
+installed, then you *must* ensure that the new server is using the
+new configuration files and not the old configuration files, as
+this may cause undesired behavior and failure to operate correctly.
+
+The initial output from running in debugging mode (`radiusd -X`)
+will tell you which configuration files are being used. See
+xref:installation:upgrade.adoc[Upgrading] for information about
+upgrading from older versions. There _may_ be changes in the
+dictionary files which are required for a new version of the
+software. These files will not be installed over your current
+configuration, so you *must* verify and install any problem files by
+hand, for example using `diff(1)` to check for changes.
+
+When installing from source, it is _extremely_ helpful to read the
+output of `./configure`, `make`, and `make install`. If a
+particular module you expected to be installed was not installed,
+then the output will tell you why that module was not installed.
+The most likely reason is that required libraries (including their
+development header files) are not available.
+
+Please do _not_ post questions to the FreeRADIUS users list
+without first carefully reading the output of this process as it
+often contains the information needed to resolve a problem.
+
+== Upgrading To A New Minor Release
+
+The installation process will not over-write your existing configuration
+files. It will, however, warn you about the files it did not install.
+These will require manual integration with the existing files.
+
+It is not possible to re-use configurations between different major
+versions of the server.
+
+For details on what has changed between the version, see the
+xref:installation:upgrade.adoc[upgrade] guide.
+
+We _strongly_ recommend that new major versions be installed in a
+different location than any existing installations. Any local policies
+can then be migrated gradually to the configuration format of the new
+major version. The number of differences in the new configuration mean
+that is is both simpler and safer to migrate your configurations rather
+than to try and just get the old configuration to work.
+
+== Running the server
+
+If the server builds and installs, but doesn’t run correctly, then
+you should first use debugging mode (`radiusd -X`) to figure out
+the problem.
+
+This is your best hope for understanding the problem. Read _all_
+of the messages which are printed to the screen, the answer to
+your problem will often be in a warning or error message.
+
+We really cannot emphasize that last sentence enough. Configuring
+a RADIUS server for complex local authentication isn’t a trivial
+task. Your _best_ and _only_ method for debugging it is to read
+the debug messages, where the server will tell you exactly what
+it’s doing, and why. You should then compare its behaviour to what
+you intended, and edit the configuration files as appropriate.
+
+If you don’t use debugging mode, and ask questions on the mailing
+list, then the responses will all tell you to use debugging mode.
+The server prints out a lot of information in this mode, including
+suggestions for fixes to common problems. Look especially for
+`WARNING` and `ERROR` messages in the output, and read the related
+messages.
+
+Since the main developers of FreeRADIUS use debugging mode to
+track down their configuration problems with the server, it’s a
+good idea for you to use it, too. If you don’t, there is little
+hope for you to solve any configuration problem related to the
+server.
+
+To start the server in debugging mode, do:
+
+[source,shell]
+----
+radiusd -X
+----
+
+You should see a lot of text printed on the screen as it starts up. If
+you don’t, or if you see error messages, please read the FAQ:
+
+https://wiki.freeradius.org/guide/FAQ
+
+If the server says `Ready to process requests.`, then it is running
+properly. From another shell (or another window), type
+
+[source,shell]
+----
+radtest test test localhost 0 testing123
+----
+
+You should see the server print out more messages as it receives the
+request, and responds to it. The `radtest` program should receive the
+response within a few seconds. It doesn’t matter if the authentication
+request is accepted or rejected, what matters is that the server
+received the request, and responded to it.
+
+You can now edit the configuration files for your local system. You will
+usually want to start with `sites-enabled/default` for main
+configurations. To set which NASes (clients) can communicate with this
+server, edit `raddb/clients.conf`. Please read the configuration files
+carefully, as many configuration options are only documented in comments
+in the file.
+
+Note that is is _highly_ recommended that you use some sort of version
+control system to manage your configuration, such as git or Subversion.
+You should then make small changes to the configuration, checking in and
+testing as you go. When a config change causes the server to stop
+working, you will be able to easily step back and find out what update
+broke the configuration.
+
+It is also considered a best practice to maintain a staging or
+development environment. This allows you to test and integrate your
+changes without impacting your active production environment. You should
+make the appropirate investment in order to properly support a critical
+resource such as your authentication servers.
+
+Configuring and running the server MAY be complicated. Many modules have
+`man` pages. See `man rlm_pap`, or `man rlm_*` for information.
+Please read the documentation in the doc/ directory. The comments in the
+configuration files also contain a lot of documentation.
+
+If you have any additional issues, the FAQ is also a good place to
+start.
+
+https://wiki.freeradius.org/guide/FAQ
diff --git a/doc/antora/modules/installation/pages/upgrade.adoc b/doc/antora/modules/installation/pages/upgrade.adoc
new file mode 100644
index 0000000..67874c8
--- /dev/null
+++ b/doc/antora/modules/installation/pages/upgrade.adoc
@@ -0,0 +1,737 @@
+= Upgrading from v2 to v3
+
+The configuration for 3.0 is *largely* compatible with the 2.x.x
+configuration. However, it is NOT possible to simply use the 2.x.x
+configuration as-is. Instead, you should re-create it.
+
+== Security
+
+A number of configuration items have moved into the "security" subsection of
+radiusd.conf. If you use these, you should move them. Otherwise, they can
+be ignored.
+
+The list of moved options is:
+
+* chroot
+* user
+* group
+* allow_core_dumps
+* reject_delay
+* status_server
+
+These entries should be moved from "radiusd.conf" to the "security"
+subsection of that file.
+
+== Naming
+
+Many names used by configuration items were inconsistent in earlier
+versions of the server. These names have been unified in version 3.0.
+
+If a file is being referenced or created the config item `filename`
+is used.
+
+If a file is being created, the initial permissions are set by the
+`permissions` config item.
+
+If a directory hierarchy needs to be created, the permissions are set
+by `dir_permissions`.
+
+If an external host is referenced in the context of a module the
+`server` config item is used.
+
+Unless the config item is a well recognised portmanteau
+(as `filename` is for example), it must be written as multiple
+distinct words separated by underscores `_`.
+
+The configuration items `file`, `script_file`, `module`,
+`detail`, `detailfile`, `attrsfile`, `perm`, `dirperm`,
+`detailperm`, and `hostname` are deprecated. As well as any false
+portmanteaus, and configuration items that used hyphens as word
+delimiters. e.g. `foo-bar` has been changed to `foo_bar`. Please
+update your module configuration to use the new syntax.
+
+In most cases the server will tell you the replacement config item to
+use. As always, run the server in debugging mode to see these
+messages.
+
+== Modules Directory
+
+As of version 3.0, the `modules/` directory no longer exists.
+
+Instead, all "example" modules have been put into the
+`mods-available/` directory. Modules which can be loaded by the
+server are placed in the `mods-enabled/` directory. All of the
+modules in that directory will be loaded. This means that the
+`instantiate` section of radiusd.conf is less important. The only
+reason to list a module in the `instantiate` section is to force
+ordering when the modules are loaded.
+
+Modules can be enabled by creating a soft link. For module `foo`, do:
+
+[source,shell]
+----
+cd raddb/mods-enabled
+ln -s ../mods-available/foo
+----
+
+To create "local" versions of the modules, we suggest copying the file
+instead. This leaves the original file (with documentation) in the
+`mods-available/` directory. Local changes should go into the
+`mods-enabled/` directory.
+
+Module-specific configuration files are now in the `mods-config/`
+directory. This change allows for better organization, and means that
+there are fewer files in the main `raddb` directory. See
+`mods-config/README.rst` for more details.
+
+== Changed Modules
+
+The following modules have been changed in this version.
+
+=== rlm_sql
+
+The SQL configuration has been moved from `sql.conf` to
+`mods-available/sql`. The `sqlippool.conf` file has also been
+moved to `mods-available/sqlippool`.
+
+The SQL module configuration has been changed. The old connection
+pool options are no longer accepted:
+
+----
+num_sql_socks
+connect_failure_retry_delay
+lifetime
+max_queries
+----
+
+Instead, a connection pool configuration is used. This configuration
+contains all of the functionality of the previous configuration, but
+in a more generic form. It also is used in multiple modules, meaning
+that there are fewer different configuration items. The mapping
+between the configuration items is:
+
+----
+num_sql_socks -> pool { max }
+connect_failure_retry_delay -> pool { retry_delay }
+lifetime -> pool { lifetime }
+max_queries -> pool { uses }
+----
+
+The pool configuration adds a number of new configuration options,
+which allow the administrator to better control how FreeRADIUS uses
+SQL connection pools.
+
+The following parameters have been changed:
+
+----
+trace -> removed
+tracefile -> logfile
+----
+
+The logfile is intended to log SQL queries performed. If you need to
+debug the server, use debugging mode. If `logfile` is set, then
+*all* SQL queries will go to `logfile`.
+
+You can now use a NULL SQL database:
+
+.Example
+----
+driver = rlm_sql_null
+----
+
+This is an empty driver which will always return "success". It is
+intended to be used to replace the `sql_log` module, and to work in
+conjunction with the `radsqlrelay` program. Simply take your normal
+configuration for raddb/mods-enabled/sql, and set:
+
+.Example
+----
+driver = rlm_sql_null
+...
+logfile = ${radacctdir}/sql.log
+----
+
+All of the SQL queries will be logged to that file. The connection
+pool does not need to be configured for the `null` SQL driver. It
+can be left as-is, or deleted from the SQL configuration file.
+
+
+=== rlm_sql_sybase
+
+The `rlm_sql_sybase` module has been renamed to `rlm_sql_freetds`
+and the old `rlm_sql_freetds` module has been removed.
+
+`rlm_sql_sybase` used the newer ct-lib API, and `rlm_sql_freetds`
+used an older API and was incomplete.
+
+The new `rlm_sql_freetds` module now also supports database
+selection on connection startup so `use` statements no longer
+have to be included in queries.
+
+
+=== sql/dialup.conf
+
+Queries for post-auth and accounting calls have been re-arranged. The
+SQL module will now expand the 'reference' configuration item in the
+appropriate sub-section, and resolve this to a configuration
+item. This behaviour is similar to rlm_linelog. This dynamic
+expansion allows for a dynamic mapping between accounting types and
+SQL queries. Previously, the mapping was fixed. Any "new" accounting
+type was ignored by the module. Now, support for any accounting type
+can be added by just adding a new target, as below.
+
+Queries from v2.x.x may be manually copied to the new v3.0
+`dialup.conf` file (`raddb/sql/main/<dialect>/queries.conf`).
+When doing this you may also need to update references to the
+accounting tables, as their definitions will now be outside of
+the subsection containing the query.
+
+The mapping from old "fixed" query to new "dynamic" query is as follows:
+
+----
+accounting_onoff_query -> accounting.type.accounting-on.query
+accounting_update_query -> accounting.type.interim-update.query
+accounting_update_query_alt +> accounting.type.interim-update.query
+accounting_start_query -> accounting.type.start.query
+accounting_start_query_alt +> accounting.type.start.query
+accounting_stop_query -> accounting.type.stop.query
+accounting_stop_query_alt +> accounting.type.stop.query
+postauth_query -> post-auth.query
+----
+
+Alternatively a 2.x.x config may be patched to work with the
+3.0 module by adding the following:
+
+.Example
+[source,unlang]
+----
+ accounting {
+ reference = "%{tolower:type.%{Acct-Status-Type}.query}"
+ type {
+ accounting-on {
+ query = "${....accounting_onoff_query}"
+ }
+ accounting-off {
+ query = "${....accounting_onoff_query}"
+ }
+ start {
+ query = "${....accounting_start_query}"
+ query = "${....accounting_start_query_alt}"
+ }
+ interim-update {
+ query = "${....accounting_update_query}"
+ query = "${....accounting_update_query_alt}"
+ }
+ stop {
+ query = "${....accounting_stop_query}"
+ query = "${....accounting_stop_query_alt}"
+ }
+ }
+ }
+ post-auth {
+ query = "${..postauth_query}"
+ }
+----
+
+In general, it is safer to migrate the configuration rather than
+trying to "patch" it, to make it look like a v2 configuration.
+
+Note that the sub-sections holding the queries are labelled
+`accounting-on`, and not `accounting_on`. The reason is that the
+names of these sections are taken directly from the
+`Accounting-Request` packet, and the `Acct-Status-Type` field.
+The `sql` module looks at the value of that field, and then looks
+for a section of that name, in order to find the query to use.
+
+That process means that the server can be extended to support any new
+value of `Acct-Status-Type`, simply by adding a named sub-section,
+and a query. This behavior is preferable to that of v2, which had
+hard-coded queries for certain `Acct-Status-Type` values, and was
+ignored all other values.
+
+=== rlm_ldap
+
+The LDAP module configuration has been substantially changed. Please
+read `raddb/mods-available/ldap`. It now uses a connection pool,
+just like the SQL module.
+
+Many of the configuration items remain the same, but they have been
+moved into subsections. This change is largely cosmetic, but it makes
+the configuration clearer. Instead of having a large set of random
+configuration items, they are now organized into logical groups.
+
+You will need to read your old LDAP configuration, and migrate it
+manually to the new configuration. Simply copying the old
+configuration WILL NOT WORK.
+
+Users upgrading from 2.x.x who used to call the ldap module in
+`post-auth` should now set `edir_autz = yes`, and remove the `ldap`
+module from the `post-auth` section.
+
+=== rlm_ldap and LDAP-Group
+
+In 2.x.x the registration of the `LDAP-Group` pair comparison was done
+by the last instance of rlm_ldap to be instantiated. In 3.0 this has
+changed so that only the default `ldap {}` instance registers
+`LDAP-Group`.
+
+If `<instance>-LDAP-Group` is already used throughout your configuration
+no changes will be needed.
+
+=== rlm_ldap authentication
+
+In 2.x.x the LDAP module had a `set_auth_type` configuration item,
+which forced `Auth-Type := ldap`. This was removed in 3.x.x as it
+often did not work, and was not consistent with the rest of the
+server. We generally recommend that LDAP should be used as a
+database, and that FreeRADIUS should do authentication.
+
+The only reason to use `Auth-Type := ldap` is when the LDAP server
+will not supply the "known good" password to FreeRADIUS, *and* where
+the Access-Request contains User-Password. This situation happens
+only for Active Directory. If you think you need to force `Auth-Type
+:= ldap` in other situations, you are very likely to be wrong.
+
+The following is an example of what should be inserted into the
+`authorize {}` and `authenticate {}` sections of the relevant
+virtual-servers, to get functionality equivalent to v2.x:
+
+.Example
+[source,unlang]
+----
+authorize {
+ ...
+ ldap
+ if ((ok || updated) && User-Password) {
+ update control {
+ Auth-Type := ldap
+ }
+...
+}
+authenticate {
+ ...
+ Auth-Type ldap {
+ ldap
+ }
+...
+}
+----
+
+=== rlm_eap
+
+The EAP configuration has been moved from `eap.conf` to
+`mods-available/eap`. A new `pwd` subsection has been added for
+EAP-PWD.
+
+
+=== rlm_expiration & rlm_logintime
+
+The rlm_expiration and rlm_logintime modules no longer add a `Reply-Message`,
+the same behaviour can be achieved checking the return code of the module and
+adding the `Reply-Message` with unlang:
+
+.Example
+[source,unlang]
+----
+expiration
+if (userlock) {
+ update reply {
+ Reply-Message := "Your account has expired"
+ }
+}
+----
+
+
+=== rlm_unix
+
+The `unix` module does not have an `authenticate` section. So you
+cannot set `Auth-Type := System`. The `unix` module has also been
+deleted from the examples in `sites-available/`. Listing it there
+has been deprecated for many years.
+
+The PAP module can do crypt authentication. It should be used instead
+of Unix authentication.
+
+The Unix module still can pull the passwords from `/etc/passwd`, or
+`/etc/shadow`. This is done by listing it in the `authorize`
+section, as is done in the examples in `sites-available/`. However,
+some systems using NIS or NSS will not supply passwords to the
+`unix` module. For those systems, we recommend putting users and
+passwords into a database, instead of relying on `/etc/passwd`.
+
+
+=== rlm_preprocess
+
+In 2.x.x `huntroups` and `users` files were loaded from default locations
+without being configured explicitly. Since 3.x.x you need to set
+`huntgroups` and `users` configuration item(s) in module section in order
+to get them being processed.
+
+
+== New Modules
+
+=== rlm_date
+
+Instances of rlm_date register an xlat method which can translate
+integer and date values to an arbitrarily formatted date time
+string, or an arbitrarily formated time string to an integer,
+depending on the attribute type passed.
+
+
+=== rlm_rest
+
+The `rest` module is used to translate RADIUS requests into
+RESTfull HTTP requests. Currently supported body types are JSON
+and POST.
+
+
+=== rlm_unpack
+
+The `unpack` module is used to turn data buried inside of binary
+attributes. e.g. if we have `Class = 0x00000001020304` then:
+
+.Example
+[source,unlang]
+----
+Tmp-Integer-0 := "%{unpack:&Class 4 short}"
+----
+
+will unpack octets 4 and 5 as a "short", which has value 0x0304.
+All integers are assumed to be in network byte order.
+
+
+=== rlm_yubikey
+
+The `yubikey` module can be used to forward yubikey OTP token
+values to a Yubico validation server, or decrypt the token
+using a PSK.
+
+
+== Deleted Modules
+
+The following modules have been deleted, and are no longer supported
+in Version 3. If you are using one of these modules, your
+configuration can probably be changed to not need it. Otherwise email
+the freeradius-devel list, and ask about the module.
+
+
+=== rlm_acct_unique
+
+This module has been replaced by the "acct_unique" policy. See
+raddb/policy.d/accounting.
+
+The method for calculating the value of acct_unique has changed.
+However, as this method was configurable, this change should not
+matter. The only issue is in having a v2 and v3 server writing to the
+same database at the same time. They will calculate different values
+for Acct-Unique-Id.
+
+
+=== rlm_acctlog
+
+You should use rlm_linelog instead. That module has a superset of the
+acctlog functionality.
+
+
+=== rlm_attr_rewrite
+
+The attr_rewrite module looked for an attribute, and then re-wrote it,
+or created a new attribute. All of that can be done in "unlang".
+
+A sample configuration in "unlang" is:
+
+.Example
+[source,unlang]
+----
+if (request:Calling-Station-Id) {
+ update request {
+ Calling-Station-Id := "...."
+ }
+}
+----
+
+We suggest updating all uses of attr_rewrite to use unlang instead.
+
+
+=== rlm_checkval
+
+The checkval module compared two attributes. All of that can be done in "unlang":
+
+.Example
+[source,unlang]
+----
+if (&request:Calling-Station-Id == &control:Calling-Station-Id) {
+ ok
+}
+----
+
+We suggest updating all uses of checkval to use unlang instead.
+
+
+=== rlm_dbm
+
+No one seems to use it. There is no sample configuration for it.
+There is no speed advantage to using it over the "files" module.
+Modern systems are fast enough that 10K entries can be read from the
+"users" file in about 10ms. If you need more users than that, use a
+real database such as SQL.
+
+
+=== rlm_fastusers
+
+No one seems to use it. It has been deprecated since Version 2.0.0.
+The "files" module was rewritten so that the "fastusers" module was no
+longer necessary.
+
+
+=== rlm_policy
+
+No one seems to use it. Almost all of its functionality is available
+via `unlang`.
+
+
+=== rlm_sim_files
+
+The rlm_sim_files module has been deleted. It was never marked "stable",
+and was never used in a production environment. There are better ways
+to test EAP.
+
+If you want similar functionality, see rlm_passwd. It can read CSV
+files, and create attributes from them.
+
+
+=== rlm_sql_log
+
+This has been replaced with the "null" sql driver. See
+`raddb/mods-available/sql` for an example configuration.
+
+The main SQL module has more functionality than rlm_sql_log, and
+results in less code in the server.
+
+== Other Functionality
+
+The following is a list of new / changed functionality.
+
+=== RadSec
+
+RadSec (or RADIUS over TLS) is now supported. RADIUS over bare TCP
+is also supported, but is recommended only for secure networks.
+
+See `sites-available/tls` for complete details on using TLS. The server
+can both receive incoming TLS connections, and also originate outgoing
+TLS connections.
+
+The TLS configuration is taken from the old EAP-TLS configuration. It
+is largely identical to the old EAP-TLS configuration, so it should be
+simple to use and configure. It re-uses much of the EAP-TLS code,
+so it is well-tested and reliable.
+
+Once RadSec is enabled, normal debugging mode will not work. This is
+because the TLS code requires threading to work properly. Instead of doing:
+
+.Example
+[source,shell]
+----
+radiusd -X
+----
+
+you will need to do:
+
+.Example
+[source,shell]
+----
+radiusd -fxx -l stdout
+----
+
+That's the price to pay for using RadSec. This limitation may be
+lifted in a future version of the server.
+
+
+=== PAP and User-Password
+
+From version 3.0 onwards the server no longer supports authenticating
+against a cleartext password in the 'User-Password' attribute. Any
+occurences of this (for instance, in the users file) should now be changed
+to 'Cleartext-Password' instead.
+
+e.g. change entries like this:
+
+----
+bob User-Password == "hello"
+----
+
+to ones like this:
+
+----
+bob Cleartext-Password := "hello"
+----
+
+If this is not done, authentication will likely fail. The server will
+also print a helpful message in debugging mode.
+
+If it really is impossible to do this, the following unlang inserted above
+the call to the pap module may be used to copy User-Password to the correct
+attribute:
+
+.Example
+[source,unlang]
+----
+if (!control:Cleartext-Password && control:User-Password) {
+ update control {
+ Cleartext-Password := "%{control:User-Password}"
+ }
+}
+----
+
+However, this should only be seen as a temporary, not permanent, fix.
+It is better to fix your databases to use the correct configuration.
+
+
+== Unlang
+
+
+The unlang policy language is compatible with v2, but has a number of
+new features. See `man unlang` for complete documentation.
+
+
+=== Errors
+
+Many more errors are caught when the server is starting up. Syntax
+errors in `unlang` are caught, and a helpful error message is
+printed. The error message points to the exact place where the error
+occurred:
+
+----
+ ./raddb/sites-enabled/default[230]: Parse error in condition
+ ERROR: if (User-Name ! "bob") {
+ ERROR: ^ Invalid operator
+----
+
+`update` sections are more generic. Instead of doing `update
+reply`, you can do the following:
+
+.Example
+[source,unlang]
+----
+update {
+ reply:Class := 0x0000
+ control:Cleartext-Password := "hello"
+}
+----
+
+This change means that you need fewer `update` sections.
+
+
+=== Comparisons
+
+Attribute comparisons can be done via the `&` operator. When you
+needed to compare two attributes, the old comparison style was:
+
+.Example
+[source,unlang]
+----
+if (User-Name == "%{control:Tmp-String-0}") {
+----
+
+This syntax is inefficient, as the `Tmp-String-0` attribute would be
+printed to an intermediate string, causing unnecessary work. You can
+now instead compare the two attributes directly:
+
+.Example
+[source,unlang]
+----
+if (&User-Name == &control:Tmp-String-0) {
+----
+
+See `man unlang` for more details.
+
+=== Casts
+
+Casts are now permitted. This allows you to force type-specific
+comparisons:
+
+.Example
+[source,unlang]
+----
+if (<ipaddr>"%{sql: SELECT...}" == 127.0.0.1) {
+----
+
+This forces the string returned by the SELECT to be treated as an IP
+address, and compare to `127.0.0.1`. Previously, the comparison
+would have been done as a simple string comparison.
+
+
+=== Networks
+
+IP networks are now supported:
+
+ if (127.0.0.1/32 == 127.0.0.1) {
+
+Will be `true`. The various comparison operators can be used to
+check IP network membership::
+
+.Example
+[source,unlang]
+----
+if (127/8 > 127.0.0.1) {
+----
+
+Returns `true`, because `127.0.0.1` is within the `127/8`
+network. However, the following comparison will return `false`::
+
+.Example
+[source,unlang]
+----
+if (127/8 > 192.168.0.1) {
+----
+
+because `192.168.0.1` is outside of the `127/8` network.
+
+
+=== Optimization
+
+As `unlang` is now pre-compiled, many compile-time optimizations are
+done. This means that the debug output may not be exactly the same as
+what is in the configuration files:
+
+ if (0 && (User-Name == "bob')) {
+
+The result will always be `false`, as the `if 0` prevents the
+following `&& ...` from being evaluated.
+
+Not only that, but the entire contents of that section will be ignored
+entirely:
+
+.Example
+[source,unlang]
+----
+if (0) {
+ this_module_does_not_exist
+ and_this_one_does_not_exist_either
+}
+----
+
+In v2, that configuration would result in a parse error, as there is
+no module called `this_module_does_not_exist`. In v3, that text is
+ignored. This ability allows you to have dynamic configurations where
+certain parts are used (or not) depending on compile-time configuration.
+
+Similarly, conditions which always evaluate to `true` will be
+optimized away:
+
+
+.Example
+[source,unlang]
+----
+if (1) {
+ files
+}
+----
+
+That configuration will never show the `if (1)` output in debugging mode.
+
+=== Dialup_admin
+
+The dialup_admin directory has been removed. No one stepped forward
+to maintain it, and the code had not been changed in many years.
+
diff --git a/doc/antora/modules/unlang/.gitignore b/doc/antora/modules/unlang/.gitignore
new file mode 100644
index 0000000..c5722d7
--- /dev/null
+++ b/doc/antora/modules/unlang/.gitignore
@@ -0,0 +1 @@
+!*.adoc
diff --git a/doc/antora/modules/unlang/nav.adoc b/doc/antora/modules/unlang/nav.adoc
new file mode 100644
index 0000000..77be328
--- /dev/null
+++ b/doc/antora/modules/unlang/nav.adoc
@@ -0,0 +1,51 @@
+* xref:index.adoc[Unlang Policy Language]
+
+** xref:list.adoc[Attribute Lists]
+** xref:attr.adoc[Attribute References]
+** xref:return_codes.adoc[Return Codes]
+
+** xref:keywords.adoc[Keywords]
+*** xref:break.adoc[break]
+*** xref:case.adoc[case]
+*** xref:else.adoc[else]
+*** xref:elsif.adoc[elsif]
+*** xref:foreach.adoc[foreach]
+*** xref:group.adoc[group]
+*** xref:if.adoc[if]
+*** xref:load-balance.adoc[load-balance]
+*** xref:redundant-load-balance.adoc[redundant-load-balance]
+*** xref:redundant.adoc[redundant]
+*** xref:return.adoc[return]
+*** xref:switch.adoc[switch]
+*** xref:update.adoc[update]
+
+** xref:module.adoc[Modules]
+*** xref:module_method.adoc[Module Methods]
+*** xref:module_builtin.adoc[Built-in Modules]
+
+** xref:type/index.adoc[Data Types]
+*** xref:type/index.adoc[List of Data Types]
+*** xref:type/ip.adoc[IP Addresses]
+*** xref:type/numb.adoc[Numbers]
+*** xref:type/string/single.adoc[Single Quoted Strings]
+*** xref:type/string/double.adoc[Double Quoted Strings]
+*** xref:type/string/backticks.adoc[Backtick-quoted string]
+*** xref:type/string/unquoted.adoc[Unquoted Strings]
+
+** xref:condition/index.adoc[Conditional Expressions]
+*** xref:condition/cmp.adoc[Comparisons]
+*** xref:condition/operands.adoc[Operands]
+*** xref:condition/return_code.adoc[The Return Code Operator]
+*** xref:condition/eq.adoc[The '==' Operator]
+*** xref:condition/and.adoc[The '&&' Operator]
+*** xref:condition/or.adoc[The '||' Operator]
+*** xref:condition/not.adoc[The '!' Operator]
+*** xref:condition/para.adoc[The '( )' Operator]
+*** xref:condition/regex.adoc[Regular Expressions]
+
+** xref:xlat/index.adoc[String Expansion]
+*** xref:xlat/alternation.adoc[Alternation Syntax]
+*** xref:xlat/builtin.adoc[Built-in Expansions]
+*** xref:xlat/character.adoc[Single Letter Expansions]
+*** xref:xlat/attribute.adoc[Attribute References]
+*** xref:xlat/module.adoc[Module References]
diff --git a/doc/antora/modules/unlang/pages/attr.adoc b/doc/antora/modules/unlang/pages/attr.adoc
new file mode 100644
index 0000000..70afce4
--- /dev/null
+++ b/doc/antora/modules/unlang/pages/attr.adoc
@@ -0,0 +1,77 @@
+= &Attribute References
+
+.Syntax
+[source,unlang]
+----
+[&]Attribute-Name
+----
+
+The `&Attribute-Name` operator returns a reference to the named
+attribute.
+
+When used as an existence check in a condition, the condition
+evaluates to `true` if the attribute exists. Otherwise, the condition
+evaluates to `false`.
+
+When used elsewhere, such as in xref:switch.adoc[switch], it returns
+the value of the named attribute.
+
+.Examples
+[source,unlang]
+----
+&User-Name
+&NAS-IP-Address
+----
+
+== Lists
+
+The attribute reference can also be qualified with a
+xref:list.adoc[list] reference. When no list is given, the server
+looks in the input packet list for the named attribute.
+
+.Examples
+
+[source,unlang]
+----
+&request:User-Name
+&reply:NAS-IP-Address
+----
+
+== Array References
+
+.Syntax
+[source,unlang]
+----
+&Attribute-Name[<integer>]
+----
+
+When an attribute appears multiple times in a list, this syntax allows
+you to address the attributes as if they were array entries. The
+`<integer>` value defines which attribute to address. The `[0]` value
+refers to the first attributes, `[1]` refers to the second attribute,
+etc.
+
+.Examples
+[source,unlang]
+----
+&EAP-Message[1]
+&reply:NAS-IP-Address[2]
+----
+
+== Removing ambuguity from the configuration files
+
+The server does not use the `&` character to distinguish attribute names
+from other strings.
+
+Without the `&`, it is more difficult to parse the configuration file
+clearly. You could interpret a string as `hello-there`
+either as a literal string "hello-there", or as a reference to an
+attribute named `hello-there`.
+
+Adding the leading `&` character means that attribute references are
+now easily distinguishable from literal strings. The use of the leading
+`&` character is highly recommended.
+
+
+// Copyright (C) 2020 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// Development of this documentation was sponsored by Network RADIUS SAS.
diff --git a/doc/antora/modules/unlang/pages/break.adoc b/doc/antora/modules/unlang/pages/break.adoc
new file mode 100644
index 0000000..01783ea
--- /dev/null
+++ b/doc/antora/modules/unlang/pages/break.adoc
@@ -0,0 +1,28 @@
+= The break statement
+
+.Syntax
+[source,unlang]
+----
+break
+----
+
+The `break` statement is used to exit an enclosing
+xref:foreach.adoc[foreach] loop. The `break` statement only be used
+inside of a xref:foreach.adoc[foreach] loop.
+
+.Example
+[source,unlang]
+----
+foreach &Class {
+ if (&Foreach-Variable-0 == 0xabcdef) {
+ break
+ }
+
+ update reply {
+ Reply-Message += "Contains %{Foreach-Variable-0}"
+ }
+}
+----
+
+// Copyright (C) 2020 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// Development of this documentation was sponsored by Network RADIUS SAS.
diff --git a/doc/antora/modules/unlang/pages/case.adoc b/doc/antora/modules/unlang/pages/case.adoc
new file mode 100644
index 0000000..ba2b5fe
--- /dev/null
+++ b/doc/antora/modules/unlang/pages/case.adoc
@@ -0,0 +1,44 @@
+= The case Statement
+
+.Syntax
+[source,unlang]
+----
+case [ <match> ] {
+ [ statements ]
+}
+----
+
+The `case` statement is used to match data inside of a
+xref:switch.adoc[switch] statement. The `case` statement cannot be used
+outside of a xref:switch.adoc[switch] statement.
+
+
+The `<match>` text can be an attribute reference such as `&User-Name`,
+or it can be a xref:type/string/index.adoc[string]. If the match
+text is a dynamically expanded string, then the match is performed on
+the output of the string expansion.
+
+If no `<match>` text is given, it means that the `case` statement is
+the "default" and will match all which is not matched by another
+`case` statement inside of the same xref:switch.adoc[switch].
+
+.Example
+[source,unlang]
+----
+switch &User-Name {
+ case "bob" {
+ reject
+ }
+
+ case &Filter-Id {
+ reject
+ }
+
+ case {
+ ok
+ }
+}
+----
+
+// Copyright (C) 2020 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// Development of this documentation was sponsored by Network RADIUS SAS.
diff --git a/doc/antora/modules/unlang/pages/condition/and.adoc b/doc/antora/modules/unlang/pages/condition/and.adoc
new file mode 100644
index 0000000..50b3deb
--- /dev/null
+++ b/doc/antora/modules/unlang/pages/condition/and.adoc
@@ -0,0 +1,21 @@
+= The && Operator
+
+.Syntax
+[source,unlang]
+----
+(condition-1 && condition-2)
+----
+
+The `&&` operator performs a short-circuit "and" evaluation of the
+two conditions. This operator evaluates _condition-1_ and returns
+`false` if _condition-1_ returns `false`. Only if _condition-1_
+returns `true` is _condition-2_ evaluated and its result returned.
+
+.Examples
+[source,unlang]
+----
+if (&User-Name && &EAP-Message) { ...
+----
+
+// Copyright (C) 2020 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// Development of this documentation was sponsored by Network RADIUS SAS.
diff --git a/doc/antora/modules/unlang/pages/condition/cmp.adoc b/doc/antora/modules/unlang/pages/condition/cmp.adoc
new file mode 100644
index 0000000..4138b86
--- /dev/null
+++ b/doc/antora/modules/unlang/pages/condition/cmp.adoc
@@ -0,0 +1,104 @@
+= Comparisons
+
+.Syntax
+[source,unlang]
+----
+lhs OP rhs
+----
+
+The most common use-case for conditions is to perform comparisons.
+The `lhs` and `rhs` of a conditional comparison can be
+xref:attr.adoc[&Attribute-Name] or xref:type/index.adoc[data]. The
+the `OP` is an operator, commonly `==` or `\<=`. It is used to
+control how the two other portions of the condition are compared.
+
+== The Comparison Operators
+
+The comparison operators are given below.
+
+[options="header"]
+|=====
+| Operator | Description
+| < | less than
+| \<= | less than or equals
+| == | equals
+| != | not equals
+| >= | greater than or equals
+| > | greater than
+| xref:condition/regex.adoc[=~] | regular expression matches
+| xref:condition/regex.adoc[!~] | regular expression does not match
+|=====
+
+The comparison operators perform _type-specific_ comparisons. The
+only exceptions are the xref:condition/regex.adoc[regular expression] operators,
+which interpret the `lhs` as a printable string, and the `rhs` as a
+regular expression.
+
+== IP Address Comparisons
+
+The type-specific comparisons operate as expected for most data types.
+The only exception is data types that are IP addresses or IP address
+prefixes. For those data types, the comparisons are done via the
+following rules:
+
+* Any unqualified IP address is assumed to have a /32 prefix (IPv4)
+ or a /128 prefix (IPv6).
+
+* If the prefixes of the left and right sides are equal, then the comparisons
+ are performed on the IP address portion.
+
+* If the prefixes of the left and right sides are not equal, then the
+ comparisons are performed as _set membership checks_.
+
+The syntax allows conditions such as `192.0.2.1 < 192.0.2/24`. This
+condition will return `true`, as the IP address `192.0.2.1' is within
+the network `192.0.2/24`.
+
+== Casting
+
+In some situations, it is useful to force the left side to be
+interpreted as a particular data type.
+
+[NOTE]
+The data types used by the cast *must* be a type taken from the RADIUS
+dictionaries, e.g., `ipaddr`, `integer`, etc. These types are not the
+same as the xref:type/index.adoc[data types] used in the
+configuration files.
+
+.Syntax
+[source,unlang]
+----
+<cast>lhs OP rhs
+----
+
+The `cast` text can be any one of the standard RADIUS dictionary data
+types, as with the following example:
+
+.Example
+[source,unlang]
+----
+<ipaddr>&Class == 127.0.0.1
+----
+
+In this example, the `Class` attribute is treated as if it was an IPv4
+address and is compared to the address `127.0.0.1`
+
+Casting is most useful when the left side of a comparison is a
+dynamically expanded string. The cast ensures that the comparison is
+done in a type-safe manner, instead of performing a string comparison.
+
+.Example
+[source,unlang]
+----
+<integer>`/bin/echo 00` == 0
+----
+
+In this example, the string output of the `echo` program is interpreted as an
+integer. It is then compared to the right side via integer
+comparisons. Since the integer `00` is equivalent to the integer `0`,
+the comparison will match. If the comparison had been performed via
+string equality checks, then the comparison would fail, because the
+strings `00` and `0` are different.
+
+// Copyright (C) 2020 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// Development of this documentation was sponsored by Network RADIUS SAS.
diff --git a/doc/antora/modules/unlang/pages/condition/eq.adoc b/doc/antora/modules/unlang/pages/condition/eq.adoc
new file mode 100644
index 0000000..d9e51f3
--- /dev/null
+++ b/doc/antora/modules/unlang/pages/condition/eq.adoc
@@ -0,0 +1,30 @@
+= The == Operator
+
+.Syntax
+`(data-1 == data-2)`
+
+The `==` operator compares the result of evaluating `data-1` and
+`data-2`. As discussed in xref:type/index.adoc[Data Types], the `data-1`
+field may be interpreted as a reference to an attribute.
+
+The `data-2` field is interpreted in a type-specific manner. For
+example, if `data-1` refers to an attribute of type `ipaddr`, then
+`data-2` is evaluated as an IP address. If `data-1` refers to an
+attribute of type `integer`, then `data-2` is evaluated as an integer
+or as a named enumeration defined by a `VALUE` statement in a
+dictionary. Similarly, if `data-1` refers to an attribute of type
+`date`, then `data-2` will be interpreted as a date string.
+
+If the resulting data evaluates to be the same, then the operator
+returns `true`; otherwise, it returns `false`.
+
+.Example
+[source,unlang]
+----
+if (User-Name == "bob") {
+ ...
+}
+----
+
+// Copyright (C) 2020 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// Development of this documentation was sponsored by Network RADIUS SAS.
diff --git a/doc/antora/modules/unlang/pages/condition/index.adoc b/doc/antora/modules/unlang/pages/condition/index.adoc
new file mode 100644
index 0000000..b9d9d5f
--- /dev/null
+++ b/doc/antora/modules/unlang/pages/condition/index.adoc
@@ -0,0 +1,85 @@
+= Conditional Expressions
+
+Conditions are evaluated when parsing xref:if.adoc[if] and
+xref:elsif.adoc[elsif] statements. These conditions allow the server to
+make complex decisions based on one of a number of possible criteria.
+
+.Syntax
+[source,unlang]
+----
+if ( condition ) { ...
+
+elsif ( condition ) { ...
+----
+
+Conditions are expressed using the following syntax:
+
+[options="header"]
+|=====
+| Syntax | Description
+| xref:attr.adoc[&Attribute-Name] | Check for attribute existence.
+| xref:condition/return_code.adoc[rcode] | Check return code of a previous module.
+| xref:condition/operands.adoc[data] | Check value of data.
+| xref:condition/cmp.adoc[lhs OP rhs] | Compare two kinds of data.
+| xref:condition/para.adoc[( condition )] | Check sub-condition
+| xref:condition/not.adoc[! condition] | Negate a conditional check
+| xref:condition/and.adoc[( condition ) && ...] | Check a condition AND the next one
+| xref:condition/or.adoc[( condition ) \|\| ...] | Check a condition OR the next one
+|=====
+
+
+.Examples
+[source,unlang]
+----
+if ( &User-Name == "bob" ) {
+ ...
+}
+
+if ( &Framed-IP-Address == 127.0.0.1 ) {
+ ...
+}
+
+if ( &Calling-Station-Id == "%{sql:SELECT ...}" ) {
+ ...
+}
+----
+
+== Load-time Syntax Checks
+
+The server performs a number of checks when it loads the configuration
+files. Unlike version 2, all of the conditions are syntax checked
+when the server loads. This checking greatly aids in creating
+configurations that are correct. Where the configuration is
+incorrect, a descriptive error is produced.
+
+This error contains the filename and line number of the syntax error.
+In addition, it will print out a portion of the line that caused the
+error and will point to the exact character where the error was seen.
+These descriptive messages mean that most errors are easy to find and fix.
+
+== Load-time Optimizations
+
+The server performs a number of optimizations when it loads the
+configuration files. Conditions that have static values are
+evaluated and replaced with the result of the conditional comparison.
+
+.Example
+[source,unlang]
+----
+if ( 0 == 1 ) {
+ ...
+}
+----
+
+The condition `0 == 1` is static and will evaluate to `false`. Since
+it evaluates to `false`, the configuration inside of the `if`
+statement is ignored. Any modules referenced inside of the `if`
+statement will not be loaded.
+
+This optimization is most useful for creating configurations that
+selectively load (or not) certain policies. If the condition above
+was used in version 2, then the configuration inside of the `if` statement
+would be loaded, even though it would never be used.
+
+// Copyright (C) 2020 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// Development of this documentation was sponsored by Network RADIUS SAS.
diff --git a/doc/antora/modules/unlang/pages/condition/not.adoc b/doc/antora/modules/unlang/pages/condition/not.adoc
new file mode 100644
index 0000000..bde038e
--- /dev/null
+++ b/doc/antora/modules/unlang/pages/condition/not.adoc
@@ -0,0 +1,19 @@
+= The ! Operator
+
+.Syntax
+[source,unlang]
+----
+! condition
+----
+
+The `!` operator negates the result of the following condition. It
+returns `true` when _condition_ returns `false`. It returns `false`
+when _condition_ returns `true`.
+
+.Examples
+
+`(! (foo == bar))` +
+`! &User-Name`
+
+// Copyright (C) 2020 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// Development of this documentation was sponsored by Network RADIUS SAS.
diff --git a/doc/antora/modules/unlang/pages/condition/operands.adoc b/doc/antora/modules/unlang/pages/condition/operands.adoc
new file mode 100644
index 0000000..4a2d00b
--- /dev/null
+++ b/doc/antora/modules/unlang/pages/condition/operands.adoc
@@ -0,0 +1,37 @@
+= Operands
+
+.Syntax
+[source,unlang]
+----
+string
+integer
+"double-quoted string"
+'single-quoted string'
+`back-quoted string`
+----
+
+Any text not matching xref:attr.adoc[&Attribute-Name] or
+xref:condition/return_code.adoc[Return Code] is interpreted as a value for a
+particular xref:type/index.adoc[data type].
+
+Double-quoted strings and back-quoted strings are dynamically expanded
+before the condition is evaluated. Single-quoted strings are static
+literals and are not dynamically expanded.
+
+When used as an existence check, the condition evaluates to `true` if
+the data is non-zero. Otherwise, the condition evaluates to `false`.
+
+For integer existence checks, `0` is `false`; all other values are `true`.
+
+For string existence checks, an empty string is `false`. All other
+strings are `true`.
+
+All other data types are disallowed in existence checks.
+
+.Examples
+
+`"hello there"` +
+`5`
+
+// Copyright (C) 2020 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// Development of this documentation was sponsored by Network RADIUS SAS.
diff --git a/doc/antora/modules/unlang/pages/condition/or.adoc b/doc/antora/modules/unlang/pages/condition/or.adoc
new file mode 100644
index 0000000..80c2cb4
--- /dev/null
+++ b/doc/antora/modules/unlang/pages/condition/or.adoc
@@ -0,0 +1,21 @@
+= The || Operator
+
+.Syntax
+[source,unlang]
+----
+(expression-1 || expression-2)
+----
+
+The `||` operator performs a short-circuit "or" evaluation of the two
+expressions. This operator evaluates _condition-1_ and returns `true`
+if _condition-1_ returns true. Only if _condition-1_ returns `false`
+is _condition-2_ evaluated and its result returned.
+
+.Examples
+[source,unlang]
+----
+if (&User-Name || &NAS-IP-Address) { ...
+----
+
+// Copyright (C) 2020 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// Development of this documentation was sponsored by Network RADIUS SAS.
diff --git a/doc/antora/modules/unlang/pages/condition/para.adoc b/doc/antora/modules/unlang/pages/condition/para.adoc
new file mode 100644
index 0000000..bdb3f01
--- /dev/null
+++ b/doc/antora/modules/unlang/pages/condition/para.adoc
@@ -0,0 +1,19 @@
+= The ( ) Operator
+
+.Syntax
+[source,unlang]
+----
+( condition )
+----
+
+The `( )` operator returns the result of evaluating the given
+`condition`. It is used to clarify policies or to explicitly define
+conditional precedence.
+
+.Examples
+
+`(foo)` +
+`(bar || (baz && dub))`
+
+// Copyright (C) 2020 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// Development of this documentation was sponsored by Network RADIUS SAS.
diff --git a/doc/antora/modules/unlang/pages/condition/regex.adoc b/doc/antora/modules/unlang/pages/condition/regex.adoc
new file mode 100644
index 0000000..038faa6
--- /dev/null
+++ b/doc/antora/modules/unlang/pages/condition/regex.adoc
@@ -0,0 +1,180 @@
+= Regular Expressions
+
+.Syntax
+====
+[source,unlang]
+----
+(<subject> =~ /<pattern>/)
+(<subject> =~ /<pattern>/[imsux])
+
+(<subject> !~ /<pattern>/)
+(<subject> !~ /<pattern>/[imsux])
+----
+====
+
+== Matching
+The regular expression operators perform regular expression matching
+on the data. The `<subject>` field can be an attribute reference or data,
+as with the other xref:condition/cmp.adoc[comparison] operators. The `/<pattern>/`
+field must be a valid regular expression.
+
+The `=~` operator evaluates to `true` when `data` matches the
+`/<pattern>/`. Otherwise, it evaluates to `false`.
+
+The `!~` operator evaluates to `true` when `data` does not match the
+`/<pattern>/`. Otherwise, it evaluates to `true`.
+
+The regular expression comparison is performed on the _string representation_
+of the left side of the comparison. That is, if the left side is an
+xref:type/numb.adoc[integer], the regular expression will behave is if the
+value `0` was the literal string `"0"`. Similarly, if the left side is an
+xref:attr.adoc[&Attribute-Name], then the regular expression will behave is if
+the attribute was printed to a string, and the match was performed on the
+resulting string.
+
+.Checking if the `User-Name` attribute contains a realm of example.com
+====
+[source,unlang]
+----
+if (&User-Name =~ /@example\.com$/) {
+ ...
+}
+----
+====
+
+== Dialects
+
+The syntax of the regular expression is defined by the regular
+expression library available on the local system.
+
+FreeRADIUS currently supports:
+
+* link:https://www.pcre.org/original/doc/html/[libpcre] and
+link:https://www.pcre.org/current/doc/html/[libpcre2] both of which
+provide
+link:https://en.wikipedia.org/wiki/Perl_Compatible_Regular_Expressions[Perl
+Compatible Regular expressions].
+* Regex support provided by the local libc implementation, usually
+link:http://en.wikipedia.org/wiki/Regular_expression#POSIX_basic_and_extended[
+Posix regular expressions].
+
+[TIP]
+====
+Use the output of `radiusd -Xxv` to determine which regular expression library is in use.
+
+....
+...
+Debug : regex-pcre : no
+Debug : regex-pcre2 : yes
+Debug : regex-posix : no
+Debug : regex-posix-extended : no
+Debug : regex-binsafe : yes
+...
+Debug : pcre2 : 10.33 (2019-04-16) - retrieved at build time
+....
+====
+
+[WARNING]
+====
+Depending on the regular expression library or libc implementation the server
+was built against, the pattern matching function available may not be binary
+safe (see `regex-binsafe` in the output of `radiusd -Xxv`).
+
+If a binary safe regex match function is not available, and a match is
+attempted against a subject that contains one or more `NUL` ('\0') bytes, the
+match will be aborted, any condition that uses the result will evaluate to false,
+and a warning will be emitted.
+====
+
+== Flags
+
+The regular expression `/<pattern>/` may be followed by one or more flag
+characters. Again, which flags are available depends on the regular expression
+library the server was built with. Multiple flags may be specified per
+`/pattern/`.
+
+.Flags and their uses
+
+[options="header"]
+|=====
+| Flag Character | Available with | Effect
+| `i` | All | Enable case-insensitive matching.
+| `m` | All | '^' and '$' match newlines within the subject.
+| `s` | libpcre[2] | '.' matches anything, including newlines.
+| `u` | libpcre[2] | Treats subjects as UTF8. Invalid UTF8
+ sequences will result in the match failing.
+ |`x` | libpcre[2] | Allows comments in expressions by ignoring
+ whitespace, and text between '#' and the next
+ newline character.
+|=====
+
+== Subcapture groups
+
+When the `=~` or `!~` operators are used, then parentheses in the regular
+expression will sub capture groups, which contain part of the subject string.
+
+The special expansion `%{0}` expands to the portion of the subject that
+matched. The expansions +
+`%{1}`..`%{32}` expand to the contents of any subcapture groups.
+
+When using libpcre[2], named capture groups may also be accessed using the
+built-in expansion +
+`%{regex:<named capture group>}`.
+
+Please see the xref:xlat/builtin.adoc#_0_32[xlat documentation] for
+more information on regular expression matching.
+
+.Extracting the 'user' portion of a realm qualified string
+====
+[source,unlang]
+----
+if (&User-Name =~ /^(.*)@example\.com$/) {
+ update reply {
+ Reply-Message := "Hello %{1}"
+ }
+}
+----
+====
+
+== Pre-Compiled vs Runtime Compiled
+
+When the server starts any regular expressions comparisons it finds will be
+pre-compiled, and if support is available, JIT'd (converted to machine code)
+to ensure fast execution.
+
+If a pattern contains a xref:xlat/index.adoc[string expansion], the pattern
+cannot be compiled on startup, and will be compiled at runtime each time the
+expression is evaluated. The server will also turn off JITing for runtime
+compiled expressions, as the overhead is greater than the time that would be
+saved during evaluation.
+
+.A runtime compiled regular expression
+====
+[source,unlang]
+----
+if (&User-Name =~ /^@%{Tmp-String-0}$/) {
+ ...
+}
+----
+====
+
+To ensure optimal performance you should limit the number of patterns
+containing xref:xlat/index.adoc[string expansions], and if using PCRE, combine
+multiple expressions operating on the same subject into a single expression
+using the PCRE alternation '|' operator.
+
+.Using multiple string expansions and the PCRE alternation operator
+====
+[source,unlang]
+----
+if (&User-Name =~ /^@(%{Tmp-String-0}|%{Tmp-String-1})$/) {
+ ...
+}
+----
+====
+
+
+// Licenced under CC-by-NC 4.0.
+// Copyright (C) 2020 Network RADIUS SAS.
+// Copyright (C) 2019 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+// Development of this documentation was sponsored by Network RADIUS SAS.
diff --git a/doc/antora/modules/unlang/pages/condition/return_codes.adoc b/doc/antora/modules/unlang/pages/condition/return_codes.adoc
new file mode 100644
index 0000000..ebc49ed
--- /dev/null
+++ b/doc/antora/modules/unlang/pages/condition/return_codes.adoc
@@ -0,0 +1,35 @@
+= The return code Operator
+
+.Syntax
+[source,unlang]
+----
+rcode
+----
+
+The Unlang interpreter tracks the return code of any module, string expansion
+or keyword that has been called.
+
+This return code can be checked in any condition. If the saved return code
+matches the `code` given here, then the condition evaluates to `true`.
+Otherwise, it evaluates to `false`.
+
+rcodes cannot be set in a condition. rcodes cannot be compared with anything else.
+
+The list of valid return codes is as follows:
+
+.Return Codes
+
+include::partial$rcode_table.adoc[]
+
+.Examples
+
+[source,unlang]
+----
+sql
+if (notfound) {
+ ...
+}
+----
+
+// Copyright (C) 2020 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// Development of this documentation was sponsored by Network RADIUS SAS.
diff --git a/doc/antora/modules/unlang/pages/default.adoc b/doc/antora/modules/unlang/pages/default.adoc
new file mode 100644
index 0000000..3b298f6
--- /dev/null
+++ b/doc/antora/modules/unlang/pages/default.adoc
@@ -0,0 +1,47 @@
+= The case Statement
+
+.Syntax
+[source,unlang]
+----
+case [ <match> ] {
+ [ statements ]
+}
+----
+
+The `case` statement is used to match data inside of a
+xref:switch.adoc[switch] statement. The `case` statement cannot be used
+outside of a xref:switch.adoc[switch] statement.
+
+
+The `<match>` text can be an attribute reference such as `&User-Name`,
+or it can be a xref:type/string/index.adoc[string]. If the match
+text is a dynamically expanded string, then the match is performed on
+the output of the string expansion.
+
+The keyword `default` can be used to specify the default action to
+take inside of a xref:switch.adoc[switch] statement.
+
+If no `<match>` text is given, it means that the `case` statement is
+the "default" and will match all which is not matched by another
+`case` statement inside of the same xref:switch.adoc[switch].
+
+.Example
+[source,unlang]
+----
+switch &User-Name {
+ case "bob" {
+ reject
+ }
+
+ case &Filter-Id {
+ reject
+ }
+
+ default {
+ ok
+ }
+}
+----
+
+// Copyright (C) 2020 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// Development of this documentation was sponsored by Network RADIUS SAS.
diff --git a/doc/antora/modules/unlang/pages/else.adoc b/doc/antora/modules/unlang/pages/else.adoc
new file mode 100644
index 0000000..a795d0e
--- /dev/null
+++ b/doc/antora/modules/unlang/pages/else.adoc
@@ -0,0 +1,30 @@
+= The else Statement
+
+.Syntax
+[source,unlang]
+----
+if (condition) {
+ [ statements ]
+}
+else {
+ [ statements ]
+}
+----
+
+An xref:if.adoc[if] statement can have an `else` clause. If _condition_
+evaluates to `false`, the statements in the xref:if.adoc[if] subsection are skipped
+and the statements within the `else` subsection are executed.
+
+.Example
+[source,unlang]
+----
+if (&User-Name == "bob") {
+ reject
+}
+else {
+ ok
+}
+----
+
+// Copyright (C) 2020 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// Development of this documentation was sponsored by Network RADIUS SAS.
diff --git a/doc/antora/modules/unlang/pages/elsif.adoc b/doc/antora/modules/unlang/pages/elsif.adoc
new file mode 100644
index 0000000..ff5799c
--- /dev/null
+++ b/doc/antora/modules/unlang/pages/elsif.adoc
@@ -0,0 +1,43 @@
+= The elsif Statement
+
+.Syntax
+[source,unlang]
+----
+if (condition-1) {
+ [ statements-1 ]
+}
+elsif (condition-2) {
+ [ statements-2 ]
+}
+else {
+ [ statements-3 ]
+}
+----
+
+An `elsif` statement is used to evaluate a subsequent
+xref:condition/index.adoc[condition] after a preceding xref:if.adoc[if] statement
+evaluates to `false`. In the example above, when _condition-1_
+evaluates to false, then _statements-1_ are skipped and _condition-2_
+is checked. When _condition-2_ evaluates true, then _statements-2_
+are executed. When _condition-2_ evaluates false, then
+_statements-2_ are skipped and _statements-3_ are executed.
+
+As with xref:if.adoc[if], an `elsif` clause does not need to be followed by
+an xref:else.adoc[else] statement. However, any xref:else.adoc[else] statement
+must be the last statement in an `elsif` chain. An arbitrary number of
+`elsif` statements can be chained together to create a series of
+conditional checks and statements.
+
+.Example
+[source,unlang]
+----
+if (&User-Name == "bob") {
+ reject
+}
+elsif (&User-Name == "doug") {
+ ok
+}
+----
+
+// Copyright (C) 2020 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// Development of this documentation was sponsored by Network RADIUS SAS.
diff --git a/doc/antora/modules/unlang/pages/foreach.adoc b/doc/antora/modules/unlang/pages/foreach.adoc
new file mode 100644
index 0000000..6ed3ddf
--- /dev/null
+++ b/doc/antora/modules/unlang/pages/foreach.adoc
@@ -0,0 +1,40 @@
+= The foreach Statement
+
+.Syntax
+[source,unlang]
+----
+foreach <attribute-reference> {
+ [ statements ]
+}
+----
+
+The `foreach` statement loops over a set of attributes as given by
+`<attribute-reference>`. The loop can be exited early by using the
+xref:break.adoc[break] keyword.
+
+<attribute-reference>::
+
+The xref:attr.adoc[attribute reference] which will will be looped
+over. The reference can be to one attribute, to an array, a child, or
+be a subset.
+
+Inside of the `foreach` block, the attribute that is being looped over
+can be referenced as `Foreach-Variable-0`, through
+`Foreach-Variable-9`. The last digit is the depth of the loop,
+starting at "0". The loops can be nested up to eight (8) deep, though
+this is not recommended.
+
+The attributes being looped over cannot be modified or deleted.
+
+.Example
+[source,unlang]
+----
+foreach &Class {
+ update reply {
+ Reply-Message += "Contains %{Foreach-Variable-0}"
+ }
+}
+----
+
+// Copyright (C) 2020 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// Development of this documentation was sponsored by Network RADIUS SAS.
diff --git a/doc/antora/modules/unlang/pages/group.adoc b/doc/antora/modules/unlang/pages/group.adoc
new file mode 100644
index 0000000..98801fd
--- /dev/null
+++ b/doc/antora/modules/unlang/pages/group.adoc
@@ -0,0 +1,39 @@
+= The group Statement
+
+.Syntax
+[source,unlang]
+----
+group {
+ [ statements ]
+}
+----
+
+The `group` statement collects a series of statements into a list.
+The default processing sections of the server (`authorize`,
+`accounting`, etc.) are also `group` statements. Those sections are
+given different name for management reasons, but they behave
+internally exactly like a `group`.
+
+[ statements ]:: The `unlang` commands which will be executed.
+
+All of the statements inside of the `group` are executed in sequence.
+The `group` statement is not normally used, as the statements within
+it can just be placed inside of the enclosing section. However, the
+`group` statement is included in the `unlang` syntax for completeness.
+
+.Examples
+
+[source,unlang]
+----
+group {
+ sql
+ ldap
+ file
+ if (updated) {
+ ...
+ }
+}
+----
+
+// Copyright (C) 2020 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// Development of this documentation was sponsored by Network RADIUS SAS.
diff --git a/doc/antora/modules/unlang/pages/if.adoc b/doc/antora/modules/unlang/pages/if.adoc
new file mode 100644
index 0000000..ea549ef
--- /dev/null
+++ b/doc/antora/modules/unlang/pages/if.adoc
@@ -0,0 +1,29 @@
+= The if Statement
+
+.Syntax
+[source,unlang]
+----
+if (condition) {
+ [ statements ]
+}
+----
+
+.Description
+The `if` statement evaluates a xref:condition/index.adoc[condition]. When the
+_condition_ evaluates to `true`, the statements within the subsection
+are executed. When the _condition_ evaluates to `false`, those
+statements are skipped.
+
+An `if` statement can optionally be followed by an xref:else.adoc[else] or
+an xref:elsif.adoc[elsif] statement.
+
+.Example
+[source,unlang]
+----
+if (&User-Name == "bob") {
+ reject
+}
+----
+
+// Copyright (C) 2020 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// Development of this documentation was sponsored by Network RADIUS SAS.
diff --git a/doc/antora/modules/unlang/pages/index.adoc b/doc/antora/modules/unlang/pages/index.adoc
new file mode 100644
index 0000000..fc812f8
--- /dev/null
+++ b/doc/antora/modules/unlang/pages/index.adoc
@@ -0,0 +1,162 @@
+= Unlang Policy Language
+
+The server supports a simple processing language called "Unlang",
+which is short for "un-language". The original intention of using an
+"un-language" was to avoid creating yet another programming language.
+Instead, the `unlang` syntax allows for simple _if / then / else_
+checks, and attribute editing. It does not support recursion,
+subroutines, or more complex flow controls.
+
+Where more complicated functionality is required, we recommend using
+the `lua`, `perl` or `python` modules. Those modules allow the insertion of
+full-featured scripts at any point in the packet processing.
+
+NOTE: The documentation is this directory is _reference_
+documentation. That is, it describes the syntax of `unlang` keywords,
+using minimal examples. The reference documentation does not,
+however, describe _when_ to use the keywords, or _how_ to create
+policies. Please see the xref:howto:index.adoc[howto] directory for
+more in-depth "how to" guides.
+
+The documentation is organized so that each item is on its own page.
+The page beings with a description of the item, followed by some text
+explaining what the item does. The page concludes with one or more
+examples of using the item in `unlang` policies.
+
+The `unlang` processing can be split into some high-level concepts.
+
+== Keywords
+
+xref:keywords.adoc[Keywords], which are the basic statements of the
+language, e.g., xref:load-balance.adoc[load-balance],
+xref:if.adoc[if], xref:else.adoc[else], etc.
+
+.Example
+[source,unlang]
+----
+load-balance {
+ sql1
+ sql2
+ sql3
+}
+----
+
+== Conditional Expressions
+
+xref:condition/index.adoc[Conditional expressions], which are used to check
+if conditions evaluate to _true_ or _false_. Conditional expressions
+can be used to control the flow of processing.
+
+.Example
+[source,unlang]
+----
+if ((&User-Name == "bob") && (&Calling-Station-Id == "00:01:03:04:05")) {
+ ...
+}
+----
+
+== Update Statements
+
+xref:update.adoc[update] statements are used to edit attributes and
+lists of attributes.
+
+Most request packets will result in reply packets that contain
+additional information for the requestor. The `update` section allows
+policies to add attributes to requests, replies, or to other places.
+
+.Example
+[source,unlang]
+----
+update reply {
+ &Session-Timeout := 3600
+ &Framed-IP-Address := 192.0.2.4
+}
+----
+
+== String Expansions
+
+xref:xlat/index.adoc[String expansion] Using `%{...}` to perform dynamic
+string expansions. (also known as xref:xlat/index.adoc[xlat])
+
+String expansions are usually performed in order to get additional
+information which is not immediately available to the policy. This
+information can be taken from almost any source, including other
+attributes, databases, and scripts.
+
+.Example
+[source,unlang]
+----
+update reply {
+ &Framed-IP-Address := "%{sql:SELECT static_ip from table WHERE user = '%{User-Name}'}"
+}
+----
+
+== Data Types
+
+Each attribute used by the server has an associated
+xref:type/index.adoc[data type]. The `unlang` interpreter enforces
+restrictions on assignments, so that only valid data types can be
+assigned to an attribute. Invalid assignments result in a run-time
+error.
+
+.Example
+[source,unlang]
+----
+update reply {
+ &Framed-IP-Address := 192.0.2.4
+ &Session-Timeout := 5
+ &Reply-Message := "hello"
+}
+----
+
+== Design Goals of Unlang
+
+The goal of `unlang` is to allow simple policies to be written with
+minimal effort. Conditional checks can be performed by the policies,
+which can then update the request or response attributes based on the
+results of those checks. `unlang` can only be used in a processing
+section, it cannot be used anywhere else, including in configuration
+sections for a client or a module. The reason for this limitation is
+that the language is intended to perform specific actions on requests
+and responses. The client and module sections contain definitions for
+a client or module; they do not define how a request is processed.
+
+`unlang` uses the same the basic syntax as the configuration files.
+The syntax of the configuration file for lines, comments, sections,
+sub-section, etc., all apply to `unlang`.
+
+Where `unlang` differs from the basic configuration file format is in
+complexity and operation. The normal configuration files are
+_declarative_ and they are _static_. That is, they declare variables
+and values for those variables. Those values do not change when the
+server is running.
+
+In contrast, `unlang` performs run-time processing of requests.
+Conditional statements such as xref:if.adoc[if] are evaluated for every
+packet that is received. Attribute editing statements such as
+xref:update.adoc[update] can be used to edit attribute contents or lists
+of attributes.
+
+.Example
+[source,unlang]
+----
+# First, the keyword 'if'
+
+# followed by condition which checks that the User-Name
+# attribute has value "bob"
+
+if (&User-Name == "bob") {
+ # keyword "update"
+
+ # followed by instructions to add the Reply-Message
+ # attribute to the "reply" list, with contents
+ # "Hello, bob"
+
+ update reply {
+ Reply-Message := "Hello, bob"
+ }
+}
+----
+
+// Copyright (C) 2020 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// Development of this documentation was sponsored by Network RADIUS SAS.
diff --git a/doc/antora/modules/unlang/pages/keywords.adoc b/doc/antora/modules/unlang/pages/keywords.adoc
new file mode 100644
index 0000000..e6411ea
--- /dev/null
+++ b/doc/antora/modules/unlang/pages/keywords.adoc
@@ -0,0 +1,78 @@
+= Keywords
+
+The following tables list the keywords used in `Unlang`. These keywords
+implement the "flow control" of the policies.
+
+== Flow Control Keywords
+
+The _flow control_ keywords allow _if / then / else_ checks, simple
+looping, etc.
+
+.Flow Control
+[options="header"]
+[cols="30%,70%"]
+|=====
+| Keyword | Description
+| xref:break.adoc[break] | Exit early from a `foreach` loop.
+| xref:case.adoc[case] | Match inside of a `switch`.
+| xref:else.adoc[else] | Do something when an `if` does not match.
+| xref:elsif.adoc[elsif] | Check for condition when a previous `if` does not match.
+| xref:foreach.adoc[foreach] | Loop over a list of attributes.
+| xref:if.adoc[if] | Check for a condition, and execute a sub-policy if it matches.
+| xref:return.adoc[return] | Immediately stop processing a section.
+| xref:switch.adoc[switch] | Check for multiple values.
+|=====
+
+== Attribute Editing Keywords
+
+The _attribute editing_ keywords allow policies to add, delete, and
+modify attributes in any list or packet.
+
+.Attribute Editing
+[options="header"]
+[cols="30%,70%"]
+|=====
+| Keyword | Description
+| xref:update.adoc[update] | Add or filter attributes to a list
+|=====
+
+== Grouping Keywords
+
+The _grouping_ keywords allow policies to be organized into groups,
+including load-balancing.
+
+.Grouping
+[options="header"]
+[cols="30%,70%"]
+|=====
+| Keyword | Description
+| xref:group.adoc[group] | Group a series of statements.
+| xref:load-balance.adoc[load-balance] | Define a load balancing group without fail-over.
+| xref:redundant.adoc[redundant] | Define a redundant group with fail-over.
+| xref:redundant-load-balance.adoc[redundant-load-balance] | Define a redundant group with fail-over and load balancing.
+|=====
+
+== Module Keywords
+
+The _module_ keywords refer pre-packaged libraries that implement
+specific functionality, such as connecting to SQL, LDAP, etc. The
+name used here is not the literal string `module`. Instead, it is the
+name of an instance of a pre-packaged module such as `sql`, or `ldap`, or
+`eap`.
+
+The documentation below describes how to reference modules. That is,
+how to use `sql`, etc. in the policies. Please see
+`raddb/mods-available/` for configuration examples for each module.
+
+.Modules
+[options="header"]
+[cols="30%,70%"]
+|=====
+| Keyword | Description
+| xref:module.adoc[<module>] | Execute a named module, e.g., `sql`.
+| xref:module_method.adoc[<module>.<method>] | Execute a particular method of a named module, e.g., `pap.authorize`
+| xref:module_builtin.adoc[reject] | Built-in modules, e.g., `reject`, or `ok`, etc.
+|=====
+
+// Copyright (C) 2020 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// Development of this documentation was sponsored by Network RADIUS SAS.
diff --git a/doc/antora/modules/unlang/pages/list.adoc b/doc/antora/modules/unlang/pages/list.adoc
new file mode 100644
index 0000000..a55a54f
--- /dev/null
+++ b/doc/antora/modules/unlang/pages/list.adoc
@@ -0,0 +1,72 @@
+= Attribute Lists
+
+An attribute list contains a set of attributes. The allowed lists
+are:
+
+`request`:: Attributes in the incoming request packet.
+
+`reply`:: Attributes in the outgoing reply packet.
+
+`control`:: Attributes in the internal "control" list that is
+associated with the request.
++
+The `control` attributes are used to manage how the request is
+processed. These attributes are never sent in any packet.
+
+`session-state`:: Attributes which are maintained across multi-packet
+exchanges.
+
+`proxy-request`:: Attributes in the proxied request packet to a home server.
+
+`proxy-reply`:: Attributes in the reply packet from the home server.
+
+`coa`:: Attributes in a CoA-Request packet which is sent to a home server.
+
+`disconnect`:: Attributes in a Disconnect-Request packet which is sent to a home server.
+
+There must be a colon `:` after the list name and before the attribute name.
+This syntax helps the server to distinguish between list names and attribute
+names.
+
+With the exception of `session-state`, all of the above lists are
+ephemeral. That is, they exist for one packet exchange, and only one
+packet exchange. When a reply is sent for a request, the above lists
+and all attributes are deleted. There is no way to reference an
+attribute from a previous packet. We recommend using a database to
+track complex state.
+
+The `coa` and `disconnect` lists can only be used when the server
+receives an Access-Request or Accounting-Request. Use `request` and
+`reply` instead of `coa` when the server receives a CoA-Request or
+Disconnect-Request packet.
+
+Adding one or more attributes to either of the `coa` or `disconnect`
+list causes server to originate a CoA-Request or Disconnect-Request
+packet. That packet is sent when the current Access-Request or
+Accounting-Request has been finished, and a reply sent to the NAS.
+See `raddb/sites-available/originate-coa` for additional information.
+
+In some cases, requests are associated a multi-packet exchange. For
+those situations, the `session-state` list is automatically saved when
+a reply is sent, and it is automatically restored when the next packet
+in sequence comes in. Once the packet exchange has been finished, the
+`session-state` list is deleted.
+
+In some cases, there is a parent-child relationship between requests.
+In those situations, it is possible for the policy rules in the child
+to refer to attributes in the parent. This reference can be made by
+prefixing the _<list>_ name with the `parent` qualifier. The key word
+`outer` is also a synonym for `parent`. If there are multiple
+parent-child relationships, the `parent` qualifier can be repeated.
+
+There is, however, no way for the parent to refer to the child. When
+the child is running, the parent is suspended. Once the child
+finishes, it is deleted, and is no longer accessible to the parent.
+
+.Examples
+`&parent.request.User-Name` +
+`&parent.reply.Reply-Message` +
+`&parent.parent.session-state.Filter-Id`
+
+// Copyright (C) 2020 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// Development of this documentation was sponsored by Network RADIUS SAS.
diff --git a/doc/antora/modules/unlang/pages/load-balance.adoc b/doc/antora/modules/unlang/pages/load-balance.adoc
new file mode 100644
index 0000000..d64b161
--- /dev/null
+++ b/doc/antora/modules/unlang/pages/load-balance.adoc
@@ -0,0 +1,32 @@
+= The load-balance Statement
+
+.Syntax
+[source,unlang]
+----
+load-balance {
+ [ statements ]
+}
+----
+
+The `load-balance` section is similar to the `redundant` section
+except that only one module in the subsection is ever called.
+
+In general, the
+xref:redundant-load-balance.adoc[redundant-load-balance] statement is
+more useful than this one.
+
+[ statements ]:: One or more `unlang` commands. Only one of the
+statements is executed.
+
+.Examples
+
+[source,unlang]
+----
+load-balance &User-Name {
+ sql1
+ sql2
+}
+----
+
+// Copyright (C) 2020 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// Development of this documentation was sponsored by Network RADIUS SAS.
diff --git a/doc/antora/modules/unlang/pages/module.adoc b/doc/antora/modules/unlang/pages/module.adoc
new file mode 100644
index 0000000..fd18f2f
--- /dev/null
+++ b/doc/antora/modules/unlang/pages/module.adoc
@@ -0,0 +1,86 @@
+= Modules
+
+.Syntax
+[source,unlang]
+----
+<module>
+----
+
+The `<module>` statement is a reference to the named module. Common
+module names include `pap`, `chap`, `files`, `eap`, and `sql`. The
+`modules { ... }` subsection of `radiusd.conf` contains all of the
+valid modules.
+
+When processing reaches a named module, the pre-compiled module is
+called. The module may succeed or fail and will return a status code
+to the `unlang` interpreter detailing success or failure.
+
+.Example
+[source,unlang]
+----
+chap
+sql
+----
+
+== Module Return Codes
+
+When a module is called, it returns one of the following codes to
+the interpreter; the meaning of each code is detailed to the right of
+the source, below:
+
+.Module Return Codes
+
+The below table describes the purpose of the rcodes that may be returned
+by a module call. In this case the 'operation' referenced in the table is
+the current module call.
+
+include::partial$rcode_table.adoc[]
+
+These return codes can be used in a subsequent
+xref:condition/index.adoc[conditional expression] thus allowing policies to
+perform different actions based on the behaviour of the modules.
+
+.Example
+[source,unlang]
+----
+sql
+if (notfound) {
+ update reply {
+ Reply-Message = "We don't know who you are"
+ }
+ reject
+}
+----
+
+== Module Return Code priority overrides
+
+In the case of modules, rcodes can be modified on a per-call basis.
+
+Module priority overrides are specified in a block inline with the module call.
+The format of an override is `<rcode> = (0+|<rcode>|return)` - That is,
+a number greater than or equal to 0, the priority of another rcode, or the special
+priority `return` which causes the current section to immediately exit.
+
+[source, unlang]
+----
+ldap { <1>
+ fail = 1 <2>
+ ok = handled <3>
+ reject = return <4>
+}
+----
+
+<1> Call to the `ldap` module.
+<2> Sets the priority of the `fail` rcode to be `1`. If the priority
+ of the rcode for the request is `0`, then the request request rcode
+ will be set to `fail` if the module returns `fail`.
+<3> Sets the priority of the `ok` rcode to be whatever the default is for
+ `handled` in this section. As the default for `handled` is usually
+ `return`. If `ok` is returned, the current section will immediately
+ exit.
+<4> Sets the priority of `reject` to be `return`. If the module returns
+ `reject`, the current section will immediately exit.
+
+
+// Copyright (C) 2020 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// Development of this documentation was sponsored by Network RADIUS SAS.
diff --git a/doc/antora/modules/unlang/pages/module_builtin.adoc b/doc/antora/modules/unlang/pages/module_builtin.adoc
new file mode 100644
index 0000000..f21a128
--- /dev/null
+++ b/doc/antora/modules/unlang/pages/module_builtin.adoc
@@ -0,0 +1,42 @@
+= Built-in Modules
+
+In some cases, it is useful to reject a request immediately or perform another
+action on it. The built-in modules can be used to perform these actions. These
+modules are named for the return codes given in the xref:module.adoc[module]
+section.
+
+In practice, these modules are implemented by the `always` module and
+exist so that a success or failure can be forced during the processing
+of a policy.
+
+The names and behaviours of these modules are given below:
+
+`fail`::
+Causes the request to be treated as if a database failure had
+occurred.
+
+`noop`::
+Do nothing. This also serves as an instruction to the
+configurable failover tracking that nothing was done in the current
+section.
+
+`ok`::
+Instructs the server that the request was processed properly. This keyword can be used to over-ride earlier failures if the local
+administrator determines that the failures are not catastrophic.
+
+`reject`::
+Causes the request to be immediately rejected.
+
+.Example
+[source,unlang]
+----
+if (!&User-Name) {
+ update reply {
+ Reply-Message := "We don't know who you are"
+ }
+ reject
+}
+----
+
+// Copyright (C) 2020 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// Development of this documentation was sponsored by Network RADIUS SAS.
diff --git a/doc/antora/modules/unlang/pages/module_method.adoc b/doc/antora/modules/unlang/pages/module_method.adoc
new file mode 100644
index 0000000..98cd375
--- /dev/null
+++ b/doc/antora/modules/unlang/pages/module_method.adoc
@@ -0,0 +1,27 @@
+= Module methods
+
+.Syntax
+[source,unlang]
+----
+<module>.<method>
+----
+
+This variant of xref:module.adoc[<module>] is used in one processing
+section. It calls a module using the method of another processing
+section. For example, it can be used to call a module's `authorize`
+method while processing the `post-auth` section.
+
+The `<module>` portion must refer to an existing module; the
+`<method>` portion must refer to processing method supported by that
+module. Typically, the names of the processing method will be the
+same as the processing sections.
+
+.Example
+[source,unlang]
+----
+sql.recv.Accounting-Request
+files.recv.Access-Request
+----
+
+// Copyright (C) 2020 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// Development of this documentation was sponsored by Network RADIUS SAS.
diff --git a/doc/antora/modules/unlang/pages/redundant-load-balance.adoc b/doc/antora/modules/unlang/pages/redundant-load-balance.adoc
new file mode 100644
index 0000000..2322f72
--- /dev/null
+++ b/doc/antora/modules/unlang/pages/redundant-load-balance.adoc
@@ -0,0 +1,39 @@
+= The redundant-load-balance Statement
+
+.Syntax
+[source,unlang]
+----
+redundant-load-balance {
+ [ statements ]
+}
+----
+
+The `redundant-load-balance` section operates as a combination of the
+xref:redundant.adoc[redundant] and xref:load-balance.adoc[load-balance]
+sections.
+
+[ statements ]:: One or more `unlang` commands.
++
+If the selected statement succeeds, then the server stops processing
+the `redundant-load-balance` section. If, however, that statement fails,
+then the next statement in the list is chosen (wrapping around to the
+top). This process continues until either one statement succeeds or all
+of the statements have failed.
++
+All of the statements in the list should be modules, and of the same
+type (e.g., `ldap` or `sql`). All of the statements in the list should
+behave identically, otherwise different requests will be processed
+through different modules and will give different results.
+
+.Example
+[source,unlang]
+----
+redundant-load-balance &User-Name {
+ sql1
+ sql2
+ sql3
+}
+----
+
+// Copyright (C) 2020 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// Development of this documentation was sponsored by Network RADIUS SAS.
diff --git a/doc/antora/modules/unlang/pages/redundant.adoc b/doc/antora/modules/unlang/pages/redundant.adoc
new file mode 100644
index 0000000..e837d1f
--- /dev/null
+++ b/doc/antora/modules/unlang/pages/redundant.adoc
@@ -0,0 +1,42 @@
+= The redundant Statement
+
+.Syntax
+[source,unlang]
+----
+redundant {
+ [ statements ]
+}
+----
+
+The `redundant` section executes a series of statements in sequence.
+As soon as one statement succeeds, the rest of the section is skipped.
+
+[ statements ]:: One or more `unlang` commands. Processing starts
+from the first statement in the list.
++
+If the selected statement succeeds, then the server stops processing
+the `redundant` section. If, however, that statement fails, then the
+next statement in the list is chosen. This process continues until
+either one statement succeeds or all of the statements have failed.
++
+All of the statements in the list should be modules, and of the same
+type (e.g., `ldap` or `sql`). All of the statements in the list should
+behave identically, otherwise different requests will be processed
+through different modules and will give different results.
+
+In general, we recommend using the
+xref:redundant-load-balance.adoc[redundant-load-balance] statement
+instead of `redundant`.
+
+.Example
+[source,unlang]
+----
+redundant {
+ sql1
+ sql2
+ sql3
+}
+----
+
+// Copyright (C) 2020 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// Development of this documentation was sponsored by Network RADIUS SAS.
diff --git a/doc/antora/modules/unlang/pages/return.adoc b/doc/antora/modules/unlang/pages/return.adoc
new file mode 100644
index 0000000..aea1bc2
--- /dev/null
+++ b/doc/antora/modules/unlang/pages/return.adoc
@@ -0,0 +1,36 @@
+= The return Statement
+
+.Syntax
+[source,unlang]
+----
+return
+----
+
+The `return` statement is used to exit a processing section such as
+`authorize`. It behaves similarly to the
+xref:break.adoc[break] statement, except that it is not limited to
+being used inside of a xref:foreach.adoc[foreach] loop.
+
+The `return` statement is not strictly necessary. It is mainly used
+to simplify the layout of `unlang` policies. If the `return`
+statement did not exist, then every xref:if.adoc[if] statement might need
+to have a matching xref:else.adoc[else] statement.
+
+The `return` statement will also exit a policy which is defined in the
+`policy { ... } ` subsection. This behavior allows policies to be
+treated as a function call. Any `return` inside of the policy section
+will only return from that policy. The `return` will _not_ return
+from the enclosing processing section which called the policy.
+
+.Example
+[source,unlang]
+----
+sql
+if (&reply.Filter-Id == "hello") {
+ return
+}
+...
+----
+
+// Copyright (C) 2020 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// Development of this documentation was sponsored by Network RADIUS SAS.
diff --git a/doc/antora/modules/unlang/pages/return_codes.adoc b/doc/antora/modules/unlang/pages/return_codes.adoc
new file mode 100644
index 0000000..3b09c2d
--- /dev/null
+++ b/doc/antora/modules/unlang/pages/return_codes.adoc
@@ -0,0 +1,17 @@
+= Return codes
+
+Many operations in the server produce a return code (rcode).
+The different rcodes give a course indication of whether a particular operation
+(a module call, string expansion, or keyword) was successful.
+
+Unlike return values in other languages, FreeRADIUS' rcodes are are always taken
+from a fixed compiled-in set.
+
+include::partial$rcode_table.adoc[]
+
+Return codes propagate through nested unlang sections based on their priority.
+If a rcode returned by an operation has a higher priority than the current rcode
+associated with the request, then the request rcode is overwritten.
+
+Return code priorities are assigned by the section the module call, expansion or
+keyword was used in.
diff --git a/doc/antora/modules/unlang/pages/switch.adoc b/doc/antora/modules/unlang/pages/switch.adoc
new file mode 100644
index 0000000..deff703
--- /dev/null
+++ b/doc/antora/modules/unlang/pages/switch.adoc
@@ -0,0 +1,83 @@
+= The switch Statement
+
+.Syntax
+[source,unlang]
+----
+switch <expansion> {
+ case <match-1> {
+ [ statements-1 ]
+ }
+ case <match-2> {
+ [ statements-2 ]
+ }
+ case {
+ [ statements-3 ]
+ }
+}
+----
+
+A `switch` statement causes the server to evaluate _expansion_, which
+can be an xref:attr.adoc[&Attribute-Name] or
+xref:condition/operands.adoc[data]. The result is compared against _match-1_
+and _match-2_ to find a match. If no string matches, then the server
+looks for the default xref:case.adoc[case] statement, which has no
+associated match.
+
+The matching is done via equality. The `switch` statement is mostly
+syntactic sugar and is used to simplify the visual form of the
+configuration. It is mostly equivalent to the following use of
+xref:if.adoc[if] statements:
+
+.Nearly equivalent syntax
+[source,unlang]
+----
+if (<expansion> == <match-1>) {
+ [ statements-1 ]
+}
+elsif (<expansion> == <match-2>) {
+ [ statements-2 ]
+}
+else {
+ [ statements-3 ]
+}
+----
+
+The only difference between the two forms is that for a `switch`
+statement, the _expansion_ is evaluated only once. For the equivalent
+xref:if.adoc[if] statement, the _expansion_ is evaluated again for every
+xref:if.adoc[if].
+
+If a matching xref:case.adoc[case] is found, the statements within
+that xref:case.adoc[case] are evaluated. If no matching
+xref:case.adoc[case] is found, the `case` section with no "match" is
+evaluated. If there is no such `case { ...}` subsection, then the
+`switch` statement behaves as if the `case {...}` section was empty.
+
+////
+For compatibility with version 3, and empty `case` statement can also
+be used instead of `default`.
+////
+
+The _match_ text for the xref:case.adoc[case] statement can be an
+xref:attr.adoc[&Attribute-Name] or xref:type/index.adoc[data].
+
+No statement other than xref:case.adoc[case] can appear in a `switch`
+statement, and the xref:case.adoc[case] statement cannot appear outside of a
+`switch` statement.
+
+.Example
+[source,unlang]
+----
+switch &User-Name {
+ case "bob" {
+ reject
+ }
+
+ case {
+ ok
+ }
+}
+----
+
+// Copyright (C) 2020 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// Development of this documentation was sponsored by Network RADIUS SAS.
diff --git a/doc/antora/modules/unlang/pages/type/all_types.adoc b/doc/antora/modules/unlang/pages/type/all_types.adoc
new file mode 100644
index 0000000..0bace01
--- /dev/null
+++ b/doc/antora/modules/unlang/pages/type/all_types.adoc
@@ -0,0 +1,80 @@
+= List of Data Types
+
+The server support a wide range of data types, both in `unlang` and in
+the dictionaries. This page outlines the names and functionality of
+those data types.
+
+== Basic Data Types
+
+There are a number of "basic" data types. These data types are
+fixed-size, and encapsulate simple concepts such as "integer" or "IP
+address".
+
+Basic data types can be used in `unlang`, as they contain simple
+values which can be compared, or assigned to one attribute. In most
+cases, it is not necessary to know the name of the data type. It is
+possible to write values in the format you expect, The server will do
+"the right thing" when interpreting the values.
+
+.Basic Data Types
+[options="header"]
+[cols="15%,85%"]
+|=====
+| Data Type | Description
+| bool | boolean
+| date | calendar date
+| ethernet | Ethernet address
+| float32 | 32-bit floating point number
+| float64 | 64-bit floating point number
+| ifid | interface ID
+| int8 | 8-bit signed integer
+| int16 | 16-bit signed integer
+| int32 | 32-bit signed integer
+| int64 | 64-bit signed integer
+| ipaddr | IPv4 address
+| ipv6addr | IPv6 address
+| ipv4prefix | IPv4 network with address and prefix length
+| ipv6prefix | IPv6 network with address and prefix length
+| octets | raw binary, printed as hex strings
+| string | printable strings
+| time_delta | difference between two calendar dates
+| uint8 | 8-bit unsigned integer
+| uint16 | 16-bit unsigned integer
+| uint32 | 32-bit unsigned integer
+| uint64 | 64-bit unsigned integer
+|=====
+
+=== Structural Data Types
+
+The following data types are "structural", in that they form
+parent-child relationships between attributes. These data types can
+only be used in the dictionaries. They cannot be used in `unlang`
+statements.
+
+.Structural Data Types
+[options="header"]
+[cols="15%,85%"]
+|=====
+| Data Type | Description
+| struct | structure which contains fixed-width fields
+| tlv | type-length-value which contains other attributes
+| vsa | Encapsulation of vendor-specific attributes
+|=====
+
+=== Protocol-Specific Data Types
+
+The following data types are used only in certain protocols. These
+data types can be used only in the dictionaries. They cannot be used
+in `unlang` statements.
+
+.Protocol Specific Data Types
+[options="header"]
+[cols="15%,15%,70%"]
+|=====
+| Data Type | Protocol | Description
+| abinary | RADIUS | Ascend binary filters
+| extended | RADIUS | attributes which "extend" the number space
+|=====
+
+// Copyright (C) 2020 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// Development of this documentation was sponsored by Network RADIUS SAS
diff --git a/doc/antora/modules/unlang/pages/type/double.adoc b/doc/antora/modules/unlang/pages/type/double.adoc
new file mode 100644
index 0000000..6c3e708
--- /dev/null
+++ b/doc/antora/modules/unlang/pages/type/double.adoc
@@ -0,0 +1,39 @@
+= Double-Quoted Strings
+
+.Syntax
+`"string"`
+
+A double-quoted string is interpreted via the usual rules in
+programming languages for double quoted strings. The double-quote
+character can be placed in a string by escaping it with a backslash.
+Carriage returns and line-feeds can also be used via the usual `\r` and
+`\n` syntax.
+
+The main difference between the single and double quoted strings is
+that the double quoted strings can be dynamically expanded. The syntax
+`${...}` is used for parse-time expansion and `%{...}` is used for
+run-time expansion. The difference between the two methods is that the
+`${...}` form is expanded when the server loads the configuration
+files and is valid anywhere in the configuration files. The `%{...}`
+link:xlat.adoc[string expansion] form is valid only in conditional
+expressions and attribute assignments.
+
+The output of the dynamic expansion can be interpreted as a string,
+a number, or an IP address, depending on its context.
+
+Note that the interpretation of text _strongly_ depends on the
+context. The text `"0000"` can be interpreted as a data type
+"integer", having value zero, or a data type "string", having value
+`"0000"`. In general when a particular piece of text is used, it is
+used with the context of a known attribute. That attribute has a
+link:data.adoc[data type], and the text will be interpreted as that
+data type.
+
+.Examples
+
+`"word"` +
+`"a string"` +
+`"this has embedded\ncharacters"`
+
+// Copyright (C) 2020 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// Development of this documentation was sponsored by Network RADIUS SAS.
diff --git a/doc/antora/modules/unlang/pages/type/index.adoc b/doc/antora/modules/unlang/pages/type/index.adoc
new file mode 100644
index 0000000..7d0d70f
--- /dev/null
+++ b/doc/antora/modules/unlang/pages/type/index.adoc
@@ -0,0 +1,117 @@
+= Data Types
+
+Unlang supports a number of data types. These data types are used in
+conditional expressions or when assigning a value to an attribute.
+
+== Using Data Types
+
+The server support a wide range of data types, as given in the
+xref:unlang/type/all_types.adoc[list of data types] page. The choice
+of which data type applies is determined by the context in which that
+data type is used. This context is usually taken from an attribute
+which is being assigned a value.
+
+The `unlang` interpreter uses pre-defined attributes which are defined
+in dictionaries. The dictionaries define both a name, and a data type
+for the attributes. In the interpreter, then, attributes can be
+assigned a value or compared to a value, without specifying the data
+type. The interpreter knows how to parse the value by using the data
+type assigned to the attribute.
+
+The result is that in most cases, it is not necessary to know the name
+of the data types. It is possible to write values in the format you
+expect, and he server will do "the right thing" when interpreting the
+values.
+
+.Attributes with Different Data Types
+[source,unlang]
+----
+Framed-IP-Address = 192.0.2.1
+Framed-IPv6-Address = 2001:db8::
+Reply-Message = "This is a reply"
+Port-Limit = 5
+Boolean = true
+Octets-Thing = 0xabcdef0102030405
+MAC-Address = 00:01:02:03:04:05
+----
+
+== Parsing Data Types
+
+The interpreter is flexible when parsing data types. So long as the
+value can be parsed as the given data type without error, the value
+will be accepted.
+
+For example, a particular attribute may be of data type `ipaddr` in
+order to store IPv4 addresses. The interpreter will then accept the
+following strings as valid IPv4 addresses:
+
+`192.168.0.2`:: xref:type/string/unquoted.adoc[Unquoted text], interpreted as the data type
+
+`'192.168.0.2'`:: xref:type/string/single.adoc[Single-quoted string], the contents of the string are parsed as the data type.
++
+The single-quoted string form is most useful when the data type
+contains special characters that may otherwise confuse the parser.
+
+`"192.168.0.2"`:: xref:type/string/double.adoc[Double-quoted string].
++
+The contents of the string are dynamically expanded as described in
+the xref:unlang/xlat/index.adoc[dynamic expansion] page. The
+resulting output is then interpreted as the given data type.
+
+`{backtick}/bin/echo 192.168.0.2{backtick}`:: xref:type/string/backticks.adoc[backtick-quoted string].
+Run a script, and parse the resulting string as the data type.
+
+Similar processing rules are applied when parsing assignments and
+comparisons, for all attributes and data types.
+
+=== Casting Data Types
+
+In some cases, it is necessary to parse values which do not refer to
+attributes. This situation usually occurs when two values need to be
+compared, as in the following example:
+
+[source,unlang]
+----
+if ("%{sql:SELECT ipaddress FROM table WHERE user=%{User-Name}}" == 192.0.2.1) }
+ ....
+}
+----
+
+Since there is no attribute on either side of the `==` operator, the
+interpreter has no way of knowing that the string `192.0.2.1` is an IP
+address. There is unfortunately no way of automatically parsing
+strings in order to determine the data type to use. Any such
+automatic parsing would work most of the time, but it would have
+error cases where the parsing was incorrect.
+
+The solution is to resolve these ambiguities by allowing the values to
+be cast to a particular type. Casting a value to a type tells the
+interpreter how that value should be parsed. Casting is done by
+prefixing a value with the type name, surrounded by angle brackets;
+`<...>`.
+
+.Syntax
+----
+<...>value
+----
+
+We can add a cast to the above example, as follows:
+
+[source,unlang]
+----
+if ("%{sql:SELECT ipaddress FROM table WHERE user=%{User-Name}}" == <ipaddr>192.0.2.1) }
+ ....
+}
+----
+
+In this example, we prefix the IP address with the string `<ipaddr>`.
+The interpreter then knows that the value `192.0.2.` should be
+interpreted as the data type `ipaddr`, and not as the literal string
+`"192.0.2."`.
+
+For a full list of data types which can be used in a cast, please see
+the xref:unlang/type/all_types.adoc[list of data types] page, and the
+"Basic Type Types" section.
+
+// Copyright (C) 2020 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// Development of this documentation was sponsored by Network RADIUS SAS.
diff --git a/doc/antora/modules/unlang/pages/type/ip.adoc b/doc/antora/modules/unlang/pages/type/ip.adoc
new file mode 100644
index 0000000..fc25ae8
--- /dev/null
+++ b/doc/antora/modules/unlang/pages/type/ip.adoc
@@ -0,0 +1,15 @@
+= IP Addresses
+
+.Examples
+
+`192.0.2.16` +
+`::1` +
+`example.com`
+
+Depending on the context, a "simple word", as above, may be
+interpreted as an IPv4 or an IPv6 address. This interpretation is
+usually done when the string is used in the context of an attribute,
+or to compare two addresses or assign an address to an attribute.
+
+// Copyright (C) 2020 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// Development of this documentation was sponsored by Network RADIUS SAS.
diff --git a/doc/antora/modules/unlang/pages/type/numb.adoc b/doc/antora/modules/unlang/pages/type/numb.adoc
new file mode 100644
index 0000000..284cf81
--- /dev/null
+++ b/doc/antora/modules/unlang/pages/type/numb.adoc
@@ -0,0 +1,11 @@
+= Numbers
+
+.Examples
+
+`0` +
+`563`
+
+Numbers are unsigned integers that are composed of decimal digits.
+
+// Copyright (C) 2020 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// Development of this documentation was sponsored by Network RADIUS SAS.
diff --git a/doc/antora/modules/unlang/pages/type/string/backticks.adoc b/doc/antora/modules/unlang/pages/type/string/backticks.adoc
new file mode 100644
index 0000000..9372b4c
--- /dev/null
+++ b/doc/antora/modules/unlang/pages/type/string/backticks.adoc
@@ -0,0 +1,38 @@
+= Backtick-quoted string
+
+.Syntax
+`{backtick}string{backtick}`
+
+The backtick operator is used to perform a run-time expansion
+similar to what is done with the Unix shell. The contents of the string
+are split into one or more sub-strings, based on intermediate
+whitespace. Each substring is then expanded as described above for
+double quoted strings. The resulting set of strings is used to execute a
+program with the associated arguments.
+
+The output of the program is recorded, and the resulting data is
+used in place of the input string value. Where the output is composed of
+multiple lines, any carriage returns and line feeds are replaced by
+spaces.
+
+For safety reasons, the full path to the executed program should be
+given. In addition, the string is split into arguments _before_ the
+substrings are dynamically expanded. This step is done both to allow
+the substrings to contain spaces, and to prevent spaces in the
+expanded substrings from affecting the number of command-line
+arguments.
+
+For performance reasons, we recommend that the use of back-quoted
+strings be kept to a minimum. Executing external programs is
+relatively expensive, and executing a large number of programs for
+every request can quickly use all of the CPU time in a server. If many
+programs need to be executed, it is suggested that alternative ways to
+achieve the same result be found. In some cases, using a real
+programming language such as `lua`, `perl` or `python` may be better.
+
+.Examples
+
+`{backtick}/bin/echo hello{backtick}`
+
+// Copyright (C) 2020 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// Development of this documentation was sponsored by Network RADIUS SAS.
diff --git a/doc/antora/modules/unlang/pages/type/string/double.adoc b/doc/antora/modules/unlang/pages/type/string/double.adoc
new file mode 100644
index 0000000..ea87bc5
--- /dev/null
+++ b/doc/antora/modules/unlang/pages/type/string/double.adoc
@@ -0,0 +1,68 @@
+= Double Quoted Strings
+
+.Syntax
+`"string"`
+
+A double-quoted string allows escape sequences and xref:xlat/index.adoc[dynamic
+expansions]. As with xref:type/string/single.adoc[single-quoted strings], text
+within double quotes can include spaces.
+
+The main difference between the single and double quoted strings is
+that the double quoted strings can be dynamically expanded. The syntax
+`${...}` is used for parse-time expansion and `%{...}` is used for
+run-time expansion. The difference between the two methods is that the
+`${...}` form is expanded when the server loads the configuration
+files and is valid anywhere in the configuration files. The `%{...}`
+xref:xlat/index.adoc[string expansion] form is valid only in conditional
+expressions and attribute assignments.
+
+The output of the dynamic expansion can be interpreted as a string,
+a number, or an IP address, depending on its context.
+
+Note that the interpretation of text _strongly_ depends on the
+context. The text `"0000"` can be interpreted as a data type
+"integer", having value zero, or a data type "string", having value
+`"0000"`. In general when a particular piece of text is used, it is
+used with the context of a known attribute. That attribute has a
+xref:type/index.adoc[data type], and the text will be interpreted as that
+data type.
+
+NOTE: Most values retrieved from external datastores will be treated implicitly
+as double-quoted strings.
+
+== Escape sequences
+
+Escape sequences allow the inclusion of characters that may be difficult to
+represent in datastores, or the FreeRADIUS configuration files.
+
+.Escape sequences and their descriptions
+[options="header", cols="15%,85%"]
+|=====
+| Escape sequence | Character represented
+| `\\` | Literal backslash (0x5c)
+| `\r` | Carriage return (0x0d)
+| `\n` | Line feed (0x0a)
+| `\t` | Horizontal tab (0x09)
+| `\"` | Double quote (0x22)
+| `\x<hex><hex>` | A byte whose numerical value is given by `<hex><hex>` interpreted as a hexadecimal number.
+| `\x<oct><oct><oct>` | A byte whose numerical value is given by `<oct><oct><oct>` interpreted as an octal number.
+|=====
+
+.Examples
+
+`"word"` +
+`"a string"' +
+`"foo\"bar\""` +
+`"this is a long string"` +
+`"this has embedded\ncharacters"` +
+`"attribute\tvalue\nusername\t%{User-Name}\nreply-message\t%{reply.Reply-Message}"`
+`"The result of 'SELECT * FROM foo WHERE 1' is: %{sql:SELECT * FROM foo WHERE 1}"`
+
+// Licenced under CC-by-NC 4.0.
+// Copyright (C) 2019 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+// Copyright (C) 2019 The FreeRADIUS project.
+// Copyright (C) 2020 Network RADIUS SAS.
+
+
+
+
diff --git a/doc/antora/modules/unlang/pages/type/string/escaping.adoc b/doc/antora/modules/unlang/pages/type/string/escaping.adoc
new file mode 100644
index 0000000..e63a498
--- /dev/null
+++ b/doc/antora/modules/unlang/pages/type/string/escaping.adoc
@@ -0,0 +1,14 @@
+= Character Escaping
+
+The quotation characters in the above string data types can be
+escaped by using the backslash, or `\,` character. The backslash
+character itself can be created by using `\\`. Carriage returns and
+line feeds can be created by using `\n` and `\r`.
+
+.Examples
+
+`"I say \"hello\" to you"` +
+`"This is split\nacross two lines"`
+
+// Copyright (C) 2020 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// Development of this documentation was sponsored by Network RADIUS SAS.
diff --git a/doc/antora/modules/unlang/pages/type/string/single.adoc b/doc/antora/modules/unlang/pages/type/string/single.adoc
new file mode 100644
index 0000000..fa2ac05
--- /dev/null
+++ b/doc/antora/modules/unlang/pages/type/string/single.adoc
@@ -0,0 +1,19 @@
+= Single Quoted Strings
+
+.Syntax
+`'string'`
+
+A single-quoted string is interpreted without any dynamic string
+expansion. The quotes allow the string to contain spaces, among other
+special characters. The single quote character can be placed in such a
+string by escaping it with a backslash.
+
+.Examples
+
+`'hello'` +
+`'foo bar`' +
+`'foo\\'bar'` +
+`'this is a long string'`
+
+// Copyright (C) 2020 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// Development of this documentation was sponsored by Network RADIUS SAS.
diff --git a/doc/antora/modules/unlang/pages/type/string/unquoted.adoc b/doc/antora/modules/unlang/pages/type/string/unquoted.adoc
new file mode 100644
index 0000000..9dd6e55
--- /dev/null
+++ b/doc/antora/modules/unlang/pages/type/string/unquoted.adoc
@@ -0,0 +1,21 @@
+= Unquoted Strings
+
+Where a series of characters cannot be parsed as a decimal number,
+they are interpreted as a simple string composed of one word. This
+word is delimited by spaces, or by other tokens, such as `)` in
+conditional expressions.
+
+This unquoted text is interpreted as simple strings and are generally
+equivalent to placing the string in single quotes.
+
+The interpretation of the text depends on the context, which is
+usually defined by an attribute which has a xref:type/index.adoc[data type].
+
+.Examples
+
+`Hello` +
+`192.168.0.1` +
+`00:01:02:03:04:05`
+
+// Copyright (C) 2020 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// Development of this documentation was sponsored by Network RADIUS SAS.
diff --git a/doc/antora/modules/unlang/pages/update.adoc b/doc/antora/modules/unlang/pages/update.adoc
new file mode 100644
index 0000000..645f4d8
--- /dev/null
+++ b/doc/antora/modules/unlang/pages/update.adoc
@@ -0,0 +1,160 @@
+= The update Statement
+
+.Syntax
+[source,unlang]
+----
+update [ <list> ] {
+ <server-attribute> <op> <value>
+ ...
+}
+----
+
+The `update` statement adds attributes to, or edits the attributes in,
+the named _<list>_.
+
+The `update` statement consists of the following syntax elements:
+
+<list>:: The attribute list which will be updated. The list is
+usually `request`, `reply`, or `control`.
++
+If the _<list>_ qualifier is omitted, then each entry inside of the
+`update` section *must* be prefixed with a list name. For example,
+`&request.User-Name ...`
+
+<server-attribute>:: The server attribute which is assigned the
+_<value>_.
+
+<op>:: The operator such as `=`, `:=`, etc.
+
+<value>:: The value which is assigned to the attribute. If the field
+is a double-quoted string, it undergoes xref:xlat/index.adoc[string
+expansion], and the resulting value is assigned to the attribute.
+
+The update process is atomic, in that either all of the attributes are
+modified, or none of them are modified. If the `update` fails for any
+reason, then all of the results are discarded, and the `update` does
+not affect any server attributes.
+
+.Example
+[source,unlang]
+----
+update reply {
+ &Reply-Message := "Hello!"
+ &Framed-IP-Address := 192.0.2.4
+}
+----
+
+== Lists
+
+The _<list>_ field sets the attribute list that will be updated. If
+the _<list>_ qualifier is omitted, then each entry inside of the
+`update` section *must* be prefixed with a list name. For example,
+`&request.User-Name ...`
+
+Please see the xref:list.adoc[list] page for valid list names.
+
+== Server Attributes
+
+The _<server-attribute>_ field is an attribute name, such as
+`&Reply-Message`. The attribute name may also be prefixed with a
+_<list>_ qualifier, which overrides the _<list>_ given at the start
+of the `update` section.
+
+NOTE: In version 3, the leading `&` is optional but recommended.
+
+== Editing Operators
+
+The `<op>` field is used to define how the attribute is processed.
+Different operators allow attributes to be added, deleted, or
+replaced, as defined below.
+
+.Editing Operators
+[options="header"]
+[cols="10%,90%"]
+|=====
+| Operator | Description
+| = | Add the attribute to the list, if and only if an attribute of
+the same name is not already present in that list.
+| := | Add the attribute to the list. If any attribute of the same
+name is already present in that list, its value is replaced with the
+value of the current attribute.
+| += | Add the attribute to the tail of the list, even if attributes
+of the same name are already present in the list.
+| ^= | Add the attribute to the head of the list, even if attributes
+of the same name are already present in the list.
+| -= | Remove all attributes from the list that match _<value>_.
+| !* | Delete all occurances of the attribute, no matter what the value.
+|=====
+
+== Filtering Operators
+
+The following operators may also be used in addition to the ones
+listed above. These operators use the _<server-attribute>_ and
+_<value>_ fields to enforce limits on all attributes in the given
+_<list>_, and to edit attributes which have a matching
+_<server-attribute>_ name. All other attributes are ignored.
+
+.Filtering Operators
+[options="header]
+[cols="10%,90%"]
+|=====
+| Operator | Description
+| == | Keep only the attributes in the list that match _<value>_
+| < | Keep only the attributes in the list that have values less than _<value>_.
+| \<= | Keep only the attributes in the list that have values less than or equal to _<value>_.
+| > | Keep only the attributes in the list that have values greater than _<value>_.
+| >= | Keep only the attributes in the list that have values greater than or equal to _<value>_.
+| =~ | Keep only the attributes in the list which match the regular expression given in _<value>_.
+| !~ | Keep only the attributes in the list which do not match the regular expression given in _<value>_.
+|=====
+
+The `==` operator is very different from the `=` operator listed
+above. The `=` operator is used to add new attributes to the list,
+while the `==` operator removes all attributes that do not match the
+given value.
+
+The comparison operators `<`, `<=`, `>`, and `>=` have some additional
+side effects. Any non-matching value is replaced by the _<value>_
+given here. If no attribute exists, it is created with the given
+_<value>_.
+
+For IP addresses, the operators `>`, `>=`, `<`, and `\<=` check for
+membership in a network. The _<value>_ field should then be a IP
+network, given in `address/mask` format.
+
+.Example
+[source,unlang]
+----
+update reply {
+ &Session-timeout := 86400
+}
+----
+
+.Example
+[source,unlang]
+----
+update reply {
+ &Reply-Message += "Rejected: Also, realm does not end with ac.uk"
+}
+----
+
+== Values
+
+The _<value>_ field is the value which is assigned to the
+_<server-attribute>_. The interpretation of the _<value>_ field
+depends on the data type of the contents. For example, if the string
+`"192.0.2.1"` is assigned to an attribute of the `string` data type,
+then the result is an ASCII string containing that value. However, if
+the same string is assigned to an attribute of the `ipaddr` data type,
+then the result is a 32-bit IPv4 address, with binary value `0xc0000201`.
+
+.Example
+[source,unlang]
+----
+update reply {
+ &Session-Timeout <= 3600
+}
+----
+
+// Copyright (C) 2020 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// Development of this documentation was sponsored by Network RADIUS SAS.
diff --git a/doc/antora/modules/unlang/pages/xlat/alternation.adoc b/doc/antora/modules/unlang/pages/xlat/alternation.adoc
new file mode 100644
index 0000000..adb7604
--- /dev/null
+++ b/doc/antora/modules/unlang/pages/xlat/alternation.adoc
@@ -0,0 +1,24 @@
+= Alternation Syntax
+
+Alternation syntax similar to that used in Unix shells may also be
+used:
+
+`%{%{Foo}:-bar}`
+
+This code returns the value of `%{Foo}`, if it has a value.
+Otherwise, it returns a literal string bar.
+
+`%{%{Foo}:-%{Bar}}`
+
+This code returns the value of `%{Foo}`, if it has a value.
+Otherwise, it returns the expansion of `%{Bar}`.
+
+These conditional expansions can be nested to almost any depth, such
+as with `%{%{One}:-%{%{Two}:-%{Three}}}`.
+
+.Examples
+`%{%{Stripped-User-Name}:-%{User-Name}}` +
+`%{%{Framed-IP-Address}:-<none>}`
+
+// Copyright (C) 2020 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// Development of this documentation was sponsored by Network RADIUS SAS.
diff --git a/doc/antora/modules/unlang/pages/xlat/attribute.adoc b/doc/antora/modules/unlang/pages/xlat/attribute.adoc
new file mode 100644
index 0000000..a3ee29b
--- /dev/null
+++ b/doc/antora/modules/unlang/pages/xlat/attribute.adoc
@@ -0,0 +1,54 @@
+= Attribute References
+
+Attributes in a list may be referenced via one of the following two
+syntaxes:
+
+`%{Attribute-Name}` +
+`%{<list>:Attribute-Name}`
+
+The `<list>:` prefix is optional. If given, it must be a valid
+reference to an xref:list.adoc[attribute list].
+
+If the `<list>:` prefix is omitted, then the `request` list is
+assumed.
+
+For EAP methods with tunneled authentication sessions (i.e. PEAP and
+EAP-TTLS), the inner tunnel session can refer to a list for the outer
+session by prefixing the list name with `outer.` ; for example,
+`outer.request`.
+
+When a reference is encountered, the given list is examined for an
+attribute of the given name. If found, the variable reference in the
+string is replaced with the value of that attribute. Otherwise, the
+reference is replacedd with an empty string.
+
+.Examples
+
+`%{User-Name}` +
+`%{request.User-Name} # same as above` +
+`%{reply.User-Name}` +
+`%{outer.request.User-Name} # from inside of a TTLS/PEAP tunnel`
+
+Examples of using references inside of a string:
+
+`"Hello %{User-Name}"` +
+`"You, %{User-Name} are not allowed to use %{NAS-IP-Address}"`
+
+== Additional Variations
+
+`%{Attribute-Name[#]}`::
+Returns an integer containing the number of named attributes
+
+`%{Attribute-Name[0]}`::
+
+When an attribute appears multiple times in a list, this syntax allows
+you to address the attributes as with array entries. `[0]` refers to
+the first attributes, `[1]` refers to the second attribute, etc.
+
+`%{Attribute-Name[*]}`::
+
+Returns a comma-separated string containing all values for the named
+attributes.
+
+// Copyright (C) 2020 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// Development of this documentation was sponsored by Network RADIUS SAS.
diff --git a/doc/antora/modules/unlang/pages/xlat/builtin.adoc b/doc/antora/modules/unlang/pages/xlat/builtin.adoc
new file mode 100644
index 0000000..f236a57
--- /dev/null
+++ b/doc/antora/modules/unlang/pages/xlat/builtin.adoc
@@ -0,0 +1,891 @@
+= Built-In Expansions
+
+In addition to storing attribute references, the server has a number
+of built-in expansions. These expansions act largely as functions
+which operate on inputs, and produce an output.
+
+
+
+== Attribute Manipulation
+
+=== %{length: ... }
+
+The `length` expansion returns the size of the input as an integer.
+When the input is a string, then the output is identical to the
+`strlen` expansion.
+
+When the input is an attribute reference, the output is the size of
+the attributes data as encoded "on the wire".
+
+.Return: _size_
+
+.Determining the length of fixed and variable length attributes
+====
+[source,unlang]
+----
+update control {
+ &Tmp-String-0 := "Caipirinha"
+ &Framed-IP-Address := 192.0.2.1
+}
+
+update reply {
+ &Reply-Message := "The length of %{control:Tmp-String-0} is %{length:&control:Tmp-String-0}"
+ &Reply-Message += "The length of %{control:Framed-IP-Address} is %{length:&control:Framed-IP-Address}"
+}
+----
+
+.Output
+....
+The length of Caipirinha is 10
+The length of 192.168.0.2 is 4
+....
+====
+
+`length` is built in to the server core.
+
+
+
+=== %{integer:<&ref>}
+
+Print the value of the attribute an integer.
+
+In normal operation, `integer` attributes are printed using the name
+given by a `VALUE` statement in a dictionary. Similarly, date
+attributes are printed as dates, i.e., "January 1 2010.
+
+The `integer` expansion applies only to attributes which can be
+converted to an integer. For all other inputs, it returns `0`.
+
+A common usage is to find the difference between two dates.
+
+For example, if a request contains `Service-Type = Login-User`, the
+expansion of `%{integer:&Service-Type}` will yield `1`, which is the
+value associated with the `Login-User` name. Using
+`%{integer:&Event-Timestamp}` will return the event timestamp as an
+unsigned 32-bit number.
+
+.Return: _string_
+
+.Determining the integer value of an enumerated attribute
+====
+[source,unlang]
+----
+update {
+ &control:Service-Type := Login-User
+}
+update reply {
+ &Reply-Message := "The value of Service-Type is %{integer:&control:Service-Type}"
+}
+----
+
+.Output
+
+```
+The value of Service-Type is 1
+```
+====
+
+`integer` is built in to the server core.
+
+
+
+=== %{rand:<number>}
+
+Generate random number from `0` to `<number>-1`.
+
+.Return: _uint64_
+
+.Generating a random number between 0 and 511
+====
+[source,unlang]
+----
+update reply {
+ &Reply-Message := "The random number is %{rand:512}"
+}
+----
+
+.Output
+
+```
+The random number is 347
+```
+====
+
+`rand` is provided by the `rlm_expr` module.
+
+
+
+=== %{tag:<attribute ref>}
+
+CAUTION: This expansion is deprecated and will likely be removed.
+
+Returns a list of tags for any attributes found using ``<attribute ref>``.
+
+.Return: _int8_
+
+.Determining the tag value of the second instance of the `radius.Tunnel-Server-Endpoint` attribute
+====
+[source,unlang]
+----
+update request {
+ &Tunnel-Server-Endpoint := '192.0.1.1'
+ &Tunnel-Server-Endpoint:1 := '192.0.5.2'
+ &Tunnel-Server-Endpoint:1 += '192.0.3.8'
+ &Tunnel-Server-Endpoint:2 := '192.0.2.1'
+ &Tunnel-Server-Endpoint:2 += '192.0.3.4'
+}
+
+update reply {
+ &Reply-Message := "The tag value of the second instance of Tunnel-Server-Enpoint is %{request:Tunnel-Server-Endpoint[1]}"
+}
+----
+
+.Output
+
+```
+The tag value of the second instance of Tunnel-Server-Enpoint is 192.0.5.2
+```
+====
+
+`tag` is built in to the server core.
+
+
+
+=== %{string:<data>}
+
+Convert input to a string (if possible). For _octets_ type attributes, this
+means interpreting the data as a UTF8 string, and inserting octal escape
+sequences where appropriate.
+
+For other types, this means printing the value in its _presentation_ format,
+i.e. dotted quads for IPv4 addresses, link:https://en.wikipedia.org/wiki/ISO_8601[ISO 8601]
+time for date types, enumeration values for attributes such as `radius.Service-Type` etc.
+
+.Return: _string_
+
+.String interpolation using the raw octets value of Tmp-Octets-0, and the stringified version
+====
+[source,unlang]
+----
+update control {
+ &Tmp-Octets-0 := 0x7465737431
+}
+update reply {
+ &Reply-Message := "The string value of %{control:Tmp-Octets-0} is %{string:%{control:Tmp-Octets-0}}"
+}
+----
+====
+
+.Output
+
+```
+The string value of 0x7465737431 is test1
+```
+
+`string` is built in to the server core.
+
+
+
+== Server Manipulation
+
+=== %{config:<key>}
+
+Refers to a variable in the configuration file. See the documentation
+on configuration file references.
+
+.Return: _string_
+
+.Example
+
+[source,unlang]
+----
+"Server installed in %{config:prefix}"
+"Module rlm_exec.shell_escape = %{config:modules.exec.shell_escape}"
+----
+
+.Output
+
+```
+Server installed in /opt/freeradius
+Module rlm_exec.shell_escape = yes
+```
+
+`config` is built in to the server core.
+
+
+
+=== %{client:<key>}
+
+Refers to a variable that was defined in the client section for the
+current client. See the sections `client { ... }` in `clients.conf`.
+
+.Return: _string_
+
+.Example
+
+[source,unlang]
+----
+"The client ipaddr is %{client:ipaddr}"
+----
+
+.Output
+
+```
+The client ipaddr is 192.168.5.9
+```
+
+`client` is built in to the server core.
+
+
+
+=== %{debug:<level>}
+
+Dynamically change the debug level to something high, recording the old level.
+
+.Return: _string_
+
+.Example
+
+[source,unlang]
+----
+authorize {
+ if (&request:User-Name == "bob") {
+ "%{debug:4}"
+ } else {
+ "%{debug:0}"
+ }
+ ...
+}
+----
+
+.Output (_extra informations only for that condition_)
+
+```
+...
+(0) authorize {
+(0) if (&request:User-Name == "bob") {
+(0) EXPAND %{debug:4}
+(0) --> 2
+(0) } # if (&request:User-Name == "bob") (...)
+(0) filter_username {
+(0) if (&State) {
+(0) ...
+(0) }
+...
+```
+
+`debug` is built in to the server core.
+
+
+
+=== %{debug_attr:<list:[index]>}
+
+Print to debug output all instances of current attribute, or all attributes in a list.
+expands to a zero-length string.
+
+.Return: _string_
+
+.Example
+
+[source,unlang]
+----
+authorize {
+ if (&request:User-Name == "bob") {
+ "%{debug_attr:request[*]}"
+ }
+ ...
+}
+----
+
+.Output
+
+```
+...
+(0) authorize {
+(0) if (&request:User-Name == "bob") {
+(0) Attributes matching "request[*]"
+(0) &request:User-Name = bob
+(0) &request:User-Password = hello
+(0) &request:NAS-IP-Address = 127.0.1.1
+(0) &request:NAS-Port = 1
+(0) &request:Message-Authenticator = 0x9210ee447a9f4c522f5300eb8fc15e14
+(0) EXPAND %{debug_attr:request[*]}
+(0) } # if (&request:User-Name == "bob") (...)
+...
+```
+
+`debug_attr` is built in to the server core.
+
+
+
+== String manipulation
+
+=== %{lpad:<&ref> <val> <char>}
+
+Left-pad a string.
+
+.Return: _string_
+
+.Example
+
+[source,unlang]
+----
+update control {
+ &Tmp-String-0 := "123"
+}
+update reply {
+ &Reply-Message := "Maximum should be %{lpad:&control:Tmp-String-0 11 0}"
+}
+----
+
+.Output
+
+```
+Maximum should be 00000000123
+```
+
+`lpad` is provided by the `rlm_expr` module.
+
+
+
+=== %{rpad:<&ref> <val> <char>}
+
+Right-pad a string.
+
+.Return: _string_
+
+.Example
+
+[source,unlang]
+----
+update control {
+ &Tmp-String-0 := "123"
+}
+update reply {
+ &Reply-Message := "Maximum should be %{rpad:&control:Tmp-String-0 11 0}"
+}
+----
+
+.Output
+
+```
+Maximum should be 12300000000
+```
+
+`rpad` is provided by the `rlm_expr` module.
+
+
+
+=== %{pairs:<&list:[*]>}
+
+Serialize attributes as comma-delimited string.
+
+.Return: _string_
+
+.Example
+
+[source,unlang]
+----
+update {
+ &control:Tmp-String-0 := "This is a string"
+ &control:Tmp-String-0 += "This is another one"
+}
+
+update reply {
+ &Reply-Message := "Serialize output: %{pairs:&control[*]}"
+}
+----
+
+.Output
+
+```
+Serialize output: Tmp-String-0 = \"This is a string\"Tmp-String-0 = \"This is another one\"
+```
+
+`pairs` is provided by the `rlm_expr` module.
+
+
+
+=== %{randstr: ...}
+
+Get random string built from character classes.
+
+.Return: _string_
+
+.Example
+
+[source,unlang]
+----
+update reply {
+ &Reply-Message := "The random string output is %{randstr:aaaaaaaa}"
+}
+----
+
+.Output
+
+```
+The random string output is 4Uq0gPyG
+```
+
+`randstr` is provided by the `rlm_expr` module.
+
+
+
+=== %{strlen: ... }
+
+Length of given string.
+
+.Return: _integer_
+
+.Example
+
+[source,unlang]
+----
+update control {
+ &Tmp-String-0 := "Caipirinha"
+}
+update reply {
+ &Reply-Message := "The length of %{control:Tmp-String-0} is %{strlen:&control:Tmp-String-0}"
+}
+----
+
+.Output
+
+```
+The length of Caipirinha is 21
+```
+
+`strlen` is built in to the server core.
+
+
+
+=== %{tolower: ... }
+
+Dynamically expands the string and returns the lowercase version of
+it. This definition is only available in version 2.1.10 and later.
+
+.Return: _string_
+
+.Example
+
+[source,unlang]
+----
+update control {
+ &Tmp-String-0 := "CAIPIRINHA"
+}
+update reply {
+ &Reply-Message := "tolower of %{control:Tmp-String-0} is %{tolower:%{control:Tmp-String-0}}"
+}
+----
+
+.Output
+
+```
+tolower of CAIPIRINHA is caipirinha
+```
+
+`tolower` is provided by the `rlm_expr` module.
+
+
+
+=== %{toupper: ... }
+
+Dynamically expands the string and returns the uppercase version of
+it. This definition is only available in version 2.1.10 and later.
+
+.Return: _string_
+
+.Example
+
+[source,unlang]
+----
+update control {
+ &Tmp-String-0 := "caipirinha"
+}
+update reply {
+ &Reply-Message := "toupper of %{control:Tmp-String-0} is %{toupper:%{control:Tmp-String-0}}"
+}
+----
+
+.Output
+
+```
+toupper of caipirinha is CAIPIRINHA
+```
+
+`toupper` is provided by the `rlm_expr` module.
+
+
+
+== String Conversion
+
+=== %{base64: ... }
+
+Encode a string using Base64.
+
+.Return: _string_
+
+.Example
+
+[source,unlang]
+----
+update control {
+ &Tmp-String-0 := "Caipirinha"
+}
+update reply {
+ &Reply-Message := "The base64 of %{control:Tmp-String-0} is %{base64:%{control:Tmp-String-0}}"
+}
+----
+
+.Output
+
+```
+The base64 of foo is Q2FpcGlyaW5oYQ==
+```
+
+`base64` is provided by the `rlm_expr` module.
+
+
+
+=== %{base64tohex: ... }
+
+Decode a base64 string (e.g. previously encoded using `base64`) to
+hex.
+
+.Return: _string_
+
+.Example
+
+[source,unlang]
+----
+update control {
+ &Tmp-String-0 := "Q2FpcGlyaW5oYQ=="
+}
+update reply {
+ &Reply-Message := "The base64tohex of %{control:Tmp-String-0} is %{base64tohex:%{control:Tmp-String-0}}"
+}
+----
+
+.Output
+
+```
+The base64decode of Q2FpcGlyaW5oYQ== is 436169706972696e6861
+```
+
+`base64tohex` is provided by the `rlm_expr` module.
+
+
+
+=== %{hex: ... }
+
+Convert to hex.
+
+.Return: _string_
+
+.Example
+
+[source,unlang]
+----
+update control {
+ &Tmp-String-0 := "12345"
+}
+update reply {
+ &Reply-Message := "The value of %{control:Tmp-String-0} in hex is %{hex:%{control:Tmp-String-0}}"
+}
+----
+
+.Output
+
+```
+The value of 12345 in hex is 3132333435
+```
+
+`hex` is built in to the server core.
+
+
+
+=== %{urlquote: ... }
+
+Quote URL special characters.
+
+.Return: _string_.
+
+.Example
+
+[source,unlang]
+----
+update {
+ &control:Tmp-String-0 := "http://example.org/"
+}
+update reply {
+ &Reply-Message += "The urlquote of %{control:Tmp-String-0} is %{urlquote:%{control:Tmp-String-0}}"
+}
+----
+
+.Output
+
+```
+The urlquote of http://example.org/ is http%3A%2F%2Fexample.org%2F
+```
+
+`urlquote` is provided by the `rlm_expr` module.
+
+
+
+=== %{urlunquote: ... }
+
+Unquote URL special characters.
+
+.Return: _string_.
+
+.Example
+
+[source,unlang]
+----
+update {
+ &control:Tmp-String-0 := "http%%3A%%2F%%2Fexample.org%%2F" # Attention for the double %.
+}
+update reply {
+ &Reply-Message += "The urlunquote of %{control:Tmp-String-0} is %{urlunquote:%{control:Tmp-String-0}}"
+}
+----
+
+.Output
+
+```
+The urlunquote of http%3A%2F%2Fexample.org%2F is http://example.org/
+```
+
+`urlunquote` is provided by the `rlm_expr` module.
+
+
+
+== Hashing and Encryption
+
+=== %{hmacmd5:<shared_key> <string>}
+
+Generate `HMAC-MD5` of string.
+
+.Return: _octal_
+
+.Example
+
+[source,unlang]
+----
+update {
+ &control:Tmp-String-0 := "mykey"
+ &control:Tmp-String-1 := "Caipirinha"
+}
+update {
+ &control:Tmp-Octets-0 := "%{hmacmd5:%{control:Tmp-String-0} %{control:Tmp-String-1}}"
+}
+
+update reply {
+ &Reply-Message := "The HMAC-MD5 of %{control:Tmp-String-1} in octets is %{control:Tmp-Octets-0}"
+ &Reply-Message += "The HMAC-MD5 of %{control:Tmp-String-1} in hex is %{hex:control:Tmp-Octets-0}"
+}
+----
+
+.Output
+
+```
+The HMAC-MD5 of Caipirinha in octets is \317}\264@K\216\371\035\304\367\202,c\376\341\203
+The HMAC-MD5 of Caipirinha in hex is 636f6e74726f6c3a546d702d4f63746574732d30
+```
+
+`hmacmd5` is provided by the `rlm_expr` module.
+
+
+
+=== %{hmacsha1:<shared_key> <string>}
+
+Generate `HMAC-SHA1` of string.
+
+.Return: _octal_
+
+.Example
+
+[source,unlang]
+----
+update {
+ &control:Tmp-String-0 := "mykey"
+ &control:Tmp-String-1 := "Caipirinha"
+}
+update {
+ &control:Tmp-Octets-0 := "%{hmacsha1:%{control:Tmp-String-0} %{control:Tmp-String-1}}"
+}
+
+update reply {
+ &Reply-Message := "The HMAC-SHA1 of %{control:Tmp-String-1} in octets is %{control:Tmp-Octets-0}"
+ &Reply-Message += "The HMAC-SHA1 of %{control:Tmp-String-1} in hex is %{hex:control:Tmp-Octets-0}"
+}
+----
+
+.Output
+
+```
+The HMAC-SHA1 of Caipirinha in octets is \311\007\212\234j\355\207\035\225\256\372Ê™>R\"\341\351O)
+The HMAC-SHA1 of Caipirinha in hex is 636f6e74726f6c3a546d702d4f63746574732d30
+```
+
+`hmacsha1` is provided by the `rlm_expr` module.
+
+
+
+=== %{md5: ... }
+
+Dynamically expands the string and performs an MD5 hash on it. The
+result is binary data.
+
+.Return: _binary data_
+
+.Example
+
+[source,unlang]
+----
+update control {
+ &Tmp-String-0 := "Caipirinha"
+}
+update reply {
+ &Reply-Message := "md5 of %{control:Tmp-String-0} is octal=%{md5:%{control:Tmp-String-0}}"
+ &Reply-Message := "md5 of %{control:Tmp-String-0} is hex=%{hex:%{md5:%{control:Tmp-String-0}}}"
+}
+----
+
+.Output
+
+```
+md5 of Caipirinha is octal=\024\204\013md||\230\243\3472\3703\330n\251
+md5 of Caipirinha is hex=14840b6d647c7c98a3e732f833d86ea9
+```
+
+`md5` is provided by the `rlm_expr` module.
+
+
+
+== Miscellaneous Expansions
+
+=== +%{0}+..+%{32}+
+
+`%{0}` expands to the portion of the subject that matched the last regular
+expression evaluated. `%{1}`..`%{32}` expand to the contents of any capture
+groups in the pattern.
+
+Every time a regular expression is evaluated, whether it matches or not,
+the numbered capture group values will be cleared.
+
+
+
+=== +%{regex:<named capture group>}+
+
+Return named subcapture value from the last regular expression evaluated.
+
+Results of named capture groups are available using the `%{regex:<named capture
+group>}` expansion. They will also be accessible using the numbered expansions
+described xref:builtin.adoc#_0_32[above].
+
+Every time a regular expression is evaluated, whether it matches or not,
+the named capture group values will be cleared.
+
+[NOTE]
+====
+This expansion is only available if the server is built with libpcre or libpcre2.
+Use the output of `radiusd -Xxv` to determine which regular expression library in use.
+
+....
+...
+Debug : regex-pcre : no
+Debug : regex-pcre2 : yes
+Debug : regex-posix : no
+Debug : regex-posix-extended : no
+Debug : regex-binsafe : yes
+...
+Debug : pcre2 : 10.33 (2019-04-16) - retrieved at build time
+....
+====
+
+`regex` is built in to the server core.
+
+
+
+=== +%{nexttime:<time>}+
+
+Calculate number of seconds until next n hour(`s`), day(`s`), week(`s`), year(`s`).
+
+.Return: _string_
+
+.Example:
+
+With the current time at 16:18, `%{nexttime:1h}` will expand to `2520`.
+
+[source,unlang]
+----
+update reply {
+ &Reply-Message := "You should wait for %{nexttime:1h}s"
+}
+----
+
+.Output
+
+```
+You should wait for 2520s
+```
+
+`nexttime` is provided by the `rlm_expr` module.
+
+
+
+=== +%{Packet-Type}+
+
+The packet type (`Access-Request`, etc.)
+
+
+
+=== +%{Packet-Src-IP-Address} and %{Packet-Src-IPv6-Address}+
+
+The source IPv4 or IPv6 address of the packet. See also the expansions
+`%{client:ipaddr}` and `%{client:ipv6addr}`. The two expansions
+should be identical, unless `%{client:ipaddr}` contains a DNS hostname.
+
+
+
+=== +%{Packet-Dst-IP-Address} and %{Packet-Dst-IPv6-Address}+
+
+The destination IPv4 or IPv6 address of the packet. See also the
+expansions `%{listen:ipaddr}` and `%{listen:ipv6addr}`. If the socket
+is listening on a "wildcard" address, then these two expansions will be
+different, as follows: the `%{listen:ipaddr}` will be the wildcard
+address and `%{Packet-DST-IP-Address}` will be the unicast address to
+which the packet was sent.
+
+
+
+=== +%{Packet-Src-Port} and %{Packet-Dst-Port}+
+
+The source/destination ports associated with the packet.
+
+.Return: _string_.
+
+.Example
+
+[source,unlang]
+----
+update control {
+ &Tmp-String-0 := "user@example.com"
+}
+
+if (&control:Tmp-String-0 =~ /^(?<login>(.*))@(?<domain>(.*))$/) {
+ update reply {
+ &Reply-Message := "The %{control:Tmp-String-0} { login=%{regex:login}, domain=%{regex:domain} }"
+ }
+}
+----
+
+.Output
+
+```
+The user@example.com { login=user, domain=example.com }
+```
+
+// Copyright (C) 2020 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// Development of this documentation was sponsored by Network RADIUS SAS.
diff --git a/doc/antora/modules/unlang/pages/xlat/character.adoc b/doc/antora/modules/unlang/pages/xlat/character.adoc
new file mode 100644
index 0000000..84a148c
--- /dev/null
+++ b/doc/antora/modules/unlang/pages/xlat/character.adoc
@@ -0,0 +1,80 @@
+= Single Letter Expansions
+
+The following are single letter expansions. These expansions do not
+use the typical `%{...}` format. Instead, they are short-cuts for
+simple, common cases.
+
+== Miscellaneous
+
+`%%`::
+
+Returns `%`.
+
+
+== Current Time
+
+`%c`::
+
+The current Unix epoch time in seconds. This is an unsigned decimal number.
+It should be used with time-based calculations.
+
+`%C`::
+
+The microsecond component of the current epoch time. This is an unsigned
+decimal number. It should be used with time-based calculations.
+
+
+== Request Time
+
+`%l`::
+
+The Unix timestamp of when the request was received. This is an unsigned
+decimal number. It should be used with time-based calculations.
+
+`%Y`::
+
+Four-digit year when the request was received.
+
+`%m`::
+
+Numeric month when the request was received.
+
+`%d`::
+
+Numeric day of the month when the request was received.
+
+`%H`::
+
+Hour of the day when the request was received.
+
+`%G`::
+
+Minute component of the time when the request was received.
+
+`%e`::
+
+Second component of the time when the request was received.
+
+`%M`::
+
+Microsecond component of the time when the request was received.
+
+`%D`::
+
+Request date in the format `YYYYMMDD`.
+
+`%S`::
+
+Request timestamp in SQL format, `YYYY-mmm-ddd HH:MM:SS`.
+
+`%t`::
+
+Request timestamp in _ctime_ format, `Www Mmm dd HH:MM:SS YYYY`.
+
+`%T`::
+
+Request timestamp in ISO format, `YYYY-mm-ddTHH:MM:SS.000`.
+
+
+// Copyright (C) 2020 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// Development of this documentation was sponsored by Network RADIUS SAS.
diff --git a/doc/antora/modules/unlang/pages/xlat/index.adoc b/doc/antora/modules/unlang/pages/xlat/index.adoc
new file mode 100644
index 0000000..b42f725
--- /dev/null
+++ b/doc/antora/modules/unlang/pages/xlat/index.adoc
@@ -0,0 +1,56 @@
+= String Expansion
+
+String expansion is a feature that allows strings to dynamically
+define their value at run time. For historical reasons, these string
+expansions are called "xlats".
+
+String expansion is performed via the following syntax:
+
+`%{...}`
+
+Where the `%{` signals the start of a dynamic expansion, and `}`
+signals the end of the dynamic expansion. The contents of the
+expansion can be many things:
+
+.String Expansions
+[options="header"]
+|=====
+| Keyword | Description
+| xref:xlat/attribute.adoc[attributes] | Expand the value of a named attribute.
+| xref:xlat/character.adoc[single character] | Single character expansions.
+| xref:xlat/module.adoc[modules] | Pass a string to a module such as `sql`.
+| xref:xlat/alternation.adoc[condition] | Conditionally expand a string.
+| xref:xlat/builtin.adoc[built-in expansions] | Such as string length, tolower, etc...
+|=====
+
+This feature is used to create policies which refer to concepts rather
+than to specific values. For example, a policy can be created that
+refers to the User-Name in a request, via:
+
+`%{User-Name}`
+
+This string expansion is done only for double-quoted strings and for
+the back-tick operator.
+
+== Caveats
+
+Unlike other languages, there is no way to define new variables. All
+of the string expansions must refer to attributes that already exist,
+or to modules that will return a string value.
+
+== Character Escaping
+
+Some characters need to be escaped within a dynamically expanded
+string `%{...}`. The `%` character is used for variable expansion, so a
+literal `%` character can be created by using `%%`.
+
+Other than within a dynamically expanded string, very little
+character escaping is needed. The rules of the enclosing string context
+determine whether or not a space or " character needs to be escaped.
+
+.Example
+
+`Reply-Message := "%{User-Name} with a literal %%`
+
+// Copyright (C) 2020 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// Development of this documentation was sponsored by Network RADIUS SAS.
diff --git a/doc/antora/modules/unlang/pages/xlat/module.adoc b/doc/antora/modules/unlang/pages/xlat/module.adoc
new file mode 100644
index 0000000..3ce4322
--- /dev/null
+++ b/doc/antora/modules/unlang/pages/xlat/module.adoc
@@ -0,0 +1,18 @@
+= Module References
+
+Individual modules may be referenced via the following syntax:
+
+`%{module:string}`
+
+These references are allowed only by a small number of modules that
+usually perform database lookups. The module name is the actual name of
+the module, as described earlier. The string portion is specific to each
+module and is not documented here. It is, however, usually dynamically
+expanded to allow for additional flexibility.
+
+.Examples
+
+`%{sql:SELECT name FROM mytable WHERE username = %{User-Name}}`
+
+// Copyright (C) 2020 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// Development of this documentation was sponsored by Network RADIUS SAS.
diff --git a/doc/antora/modules/unlang/partials/rcode_table.adoc b/doc/antora/modules/unlang/partials/rcode_table.adoc
new file mode 100644
index 0000000..e114e74
--- /dev/null
+++ b/doc/antora/modules/unlang/partials/rcode_table.adoc
@@ -0,0 +1,39 @@
+[options="header"]
+[cols="15%,85%"]
+|=====
+| Return code | Description
+| `fail` | The operation failed. Usually as a result of an
+ external dependency like a database being unavailable
+ or an internal error.
+| `handled` | The request has been "handled", no further policies
+ in the current section should be called, and the section
+ should immediately exit.
+| `invalid` | The request, or operation, was invalid. In the case of
+ requests this usually indicates absent or malformed
+ attribute values.
+| `noop` | The operation did nothing.
+| `notfound` | A 'lookup' operation returned no results.
+| `ok` | Operation completed successfully but did not change any
+ attributes in the request.
+| `reject` | The operation indicates the current request should be
+ 'rejected'. What this actually means is different from
+ protocol to protocol. It usually means that access to
+ the requested resource should be denied, or that the
+ current request should be NAKd. Usually returned when
+ provided credentials were invalid.
+| `updated` | The operation completed successfully and updated one
+ or more attributes in the request.
+| `disallow` | Access to a particular resource is
+ denied. This is similar to `reject` but is the result
+ of an authorizational check failing, as opposed to
+ credentials being incorrect.
+| `yield` | Returned by an operation when execution of a request should
+ be suspended.
+|=====
+
+[NOTE]
+====
+In versions ≤ v3.0.x the `disallow` rcode was called `userlock`. `disallow` and
+`userlock` have an identical meaning. `disallow` will be returned in any
+instance where `userlock` was returned in v3.0.x
+====
diff --git a/doc/bugs b/doc/bugs
new file mode 100644
index 0000000..086ca34
--- /dev/null
+++ b/doc/bugs
@@ -0,0 +1,175 @@
+BUGS
+
+0. INTRODUCTION
+
+ The FreeRADIUS web site is at <URL: https://freeradius.org>, and
+ most information referenced in this document can be found there.
+
+ This is primarily for non-developers of the FreeRADIUS server. If you are
+ able to patch the code to work correctly, then we invite you to join the
+ development list to discuss it. If you're the type who know little about
+ how to code, then this is the place for you!
+
+
+1. YOU FOUND A BUG
+
+ Where the server terminates ungracefully due to a bus error,
+ segmentation violation, or other memory error, you should create
+ a new issue in the issue tracker <URL: http://bugs.freeradius.org>,
+ including information from sections 4 and 5.
+
+ For other issues, you should first discuss them on the users list,
+ to see if anyone can reproduce them. Often there's a simple explanation
+ of why the server behaves as it does, and it's not necessarily a bug in
+ the code, so browse the lists' archives of the last two months, and if
+ you don't see messages about it, ask!
+
+ If the behavior is correct but confusing, we think that's a bug too, and
+ you should file a bug against our documentation.
+
+ For more information about the users list, the lists' archives and the
+ faq, please visit https://freeradius.org/support/
+ Please make sure to READ and RESPECT the house-rules. You will get much
+ better response and much faster if you do!
+
+
+2. CORE DUMPS
+
+ If the server, or one of the accompanying programs core dumps, then
+ you should rebuild the server as follows:
+
+ $ ./configure --enable-developer
+ $ make
+ $ make install
+
+ and then run the program again. You may have to to enable core
+ dumps, via:
+
+ $ ulimit -c unlimited
+
+ When it core dumps, do:
+
+ $ gdb /path/to/executable /path/to/core/file
+
+ Enable logging in gdb via the following commands:
+
+ (gdb) set logging file gdb-radiusd.log
+ (gdb) set logging on
+
+ and follow the instructions in section 4, below.
+
+ You can also enable the "panic_action" given in raddb/radiusd.conf.
+ See the comments in that file for more details about automatically
+ collecting gdb debugging information when the server crashes.
+
+
+3. DEBUGGING A LIVE SERVER
+
+ If you can't get a core dump, or the problem doesn't result in a
+ core dump, you may have to run the server under gdb. To do this,
+ ensure that you have symbols in the binaries (i.e. a non-stripped
+ binary) by re-building the server as described in the previous
+ section. Then, run the server under gdb as follows:
+
+ $ gdb radiusd
+
+ Enable logging in gdb via the following commands:
+
+ (gdb) set logging file gdb-radiusd.log
+ (gdb) set logging on
+
+ Tell gdb to pass any necessary command-line arguments to the
+ server:
+
+ (gdb) set args ...
+
+ Where the "..." are the command-line arguments you normally pass to
+ radiusd. For debugging, you probably want to do:
+
+ (gdb) set args -f
+
+ Then, do:
+
+ (gdb) run
+
+ When something interesting happens, you can hit CTRL-C in the
+ window, and you should be back at the gdb prompt:
+
+ (gdb)
+
+ And follow the instructions in section 4, below.
+
+
+4. OBTAINING USEFUL INFORMATION
+
+ Once you have a core dump loaded into gdb, or FreeRADIUS running under
+ gdb, you may use the commands below to get useful information about
+ the state of the server.
+
+ If the server was built with threads, you can do:
+
+ (gdb) info threads
+
+ Which will give you information about the threads. If the server
+ isn't threaded, that command-line will print a message saying so.
+
+ Then, do:
+
+ (gdb) thread apply all bt full
+
+ If the server isn't threaded, the "thread apply" section isn't necessary
+
+ The output should be printed to the screen, and also sent to the
+ gdb-radiusd.log file.
+
+ You should then submit the information from the log file, along with
+ any server output, the output of radiusd -xv, and information about your
+ operating system to:
+
+ http://bugs.freeradius.org/
+
+ Submitting it to the bug database ensures that the bug report won't
+ get forgotten, and that it will be dealt with in due course.
+
+ You should provide the issue number in any mail sent to the user's list.
+
+
+5. VALGRIND
+
+ On Linux systems, "valgrind" is a useful tool that can catch certain
+ classes of bugs. To use it, run the server voa:
+
+$ valgrind --tool=memcheck --leak-check=full radiusd -Xm
+
+ It will print out certain kinds of errors to the screen. There may
+ be a number of errors related to OpenSSL, dlopen(), or libtldl. We
+ cannot do anything about those problems. However, any errors that are
+ inside of the FreeRADIUS source should be brought to our attention.
+
+
+6. RUNNING WITH "SCREEN"
+
+ If the bug is a crash of the server, and it takes a long time for the
+ crash to happen, perform the following steps:
+
+ * log in as root
+ * open a screen session (https://www.gnu.org/software/screen/)
+ $ screen bash
+ * make sure FreeRADIUS is not running
+ * make sure you have all the debug symbols about, or a debugable
+ version of the server installed
+ * configure screen to log to a file; 'Ctrl-A H'
+ * type 'gdb /path/to/radius' (or /path/to/freeradius on Debian)
+ * at the (gdb) prompt, type 'run -X'
+ * detach from screen 'Ctrl-A D'
+ * when you notice FreeRADIUS has died, reconnect to your screen session
+ $ screen -D -r
+ * at the (gdb) prompt type 'where' or for *lots* of info try
+ 'thread apply all bt full'
+ * tell screen to stop logging, 'Ctrl-A H'
+ * logout from screen
+
+--
+
+FreeRADIUS Project, copyright 2014
+$Id$
diff --git a/doc/concepts/aaa.rst b/doc/concepts/aaa.rst
new file mode 100644
index 0000000..5d897c6
--- /dev/null
+++ b/doc/concepts/aaa.rst
@@ -0,0 +1,99 @@
+Authorization, Authentication, and Accounting request handling
+==============================================================
+
+There are a lot of questions about misconfigured FreeRADIUS servers
+because of misunderstanding of FreeRADIUS operations. This document
+explains how the server operates.
+
+Normally there are 2 steps in processing authentication request coming
+from NAS in FreeRADIUS (plus additional steps to proxy request if we
+use FreeRADIUS as a proxy): authorization and authentication.
+
+
+Authorization
+-------------
+
+Authorization is a process of obtaining information about the user
+from external source (file, database or LDAP), and checking that the
+information in request is enough to authenticate user. Authorization
+modules deal with data sources, so ldap, sql, files, passwd are
+authorization modules.
+
+The authentication method is decided during the authorization phase,
+along with any reply attributes. The reason for this behaviour is
+that for example, a user may not be permitted to use a particular
+authentication method. So during the authorize phase, we can deny
+them the ability to use that kind of authentication.
+
+Authentication
+--------------
+
+Authentication is simply a process of comparing user's credentials in
+request with credentials stored in database. Authentication usually
+deals with password encryption. PAP, CHAP, MS-CHAP are authentication
+modules. Few modules act as both authorization and authentication.
+For example, the MS-CHAP module is normally authentication only, but it
+may be used during authorization to verify that request contains
+MS-CHAP related attribute and only in this case perform MS-CHAP based
+authentication. LDAP is normally an authorization module, but it may
+be used for authentication (In this case FreeRADIUS will authenticate
+user in case he can connect to LDAP server with his account). SQL is
+only an authorization module, as dial-in users are not normally given
+passwords to access an SQL server.
+
+
+Request Processing
+------------------
+
+During authorization and authentication processes, there are 3 lists
+of RADIUS attributes supported by FreeRADIUS: request items, config
+items and reply items. (See 'man 5 users' for additional
+information.) Attributes from the RADIUS authentication request
+packet are included into request items list. Both authorization and
+authentication modules can add attributes into reply items list. These
+attributes will be added to reply will be sent by RADIUS server to
+NAS. There is third list, called config items. It's used for
+internal FreeRADIUS operations, for example to pass some data from
+authorization to authentication module.
+
+Before authorization begins FreeRADIUS creates request items list with
+attributes from request and empty config and reply lists.
+
+An authorization module searches a database with attributes
+(e.g. User-Name) taken from request list as a key, and fetches all
+relevant records. It retrieves 3 types of attributes: check
+attributes, configure attributes and reply attributes. It compares the
+check attributes with attributes from request items. If none of
+database record for this User-Name matches in check attributes with
+request items authorization will fail. If a matching record is found,
+then the configure attributes will be added to configure items, and
+the reply attributes will be added to reply items list. The check
+list may be required if we need to authenticate users with same name
+for different services (for example to treat User1 from NAS1 and User1
+from NAS2 as different users).
+
+There should be at list one configure attribute provided by
+authorization module, called Auth-Type (since this attribute is from
+config items list it can't be in request or reply). This attribute
+decides which module will be used to authenticate the user. The
+Config items also contains information from database required to
+authenticate user, for example valid user's password or it's hash,
+login restrictions, etc.
+
+A quite common mistake is to place the attributes in the wrong lists,
+for example placing Auth-Type, Password, NT-Password etc in the check
+list, or in the reply list. When run in debugging mode, the server
+will normally issue 'WARNING' messages saying that the attributes are
+in the wrong list.
+
+If you place Password into check list and user does cleartext
+authentication it may work, because authorization module compares 2
+cleartext passwords. But if user does some encrypted authentication
+(for example MS-CHAP), then the authorization will fail, because the
+Password in the request items will not match the password in the check
+attributes. You should place Password attribute obtained from
+database into configure items and also place Auth-Type attribute with
+value of 'MS-CHAP' into same list. The same goes for NT-Password
+(before calling MS-CHAP Password attribute should be converted to
+NT-Password, it may be achieved by calling mschap module in
+authorization section after module which does actual authorization).
diff --git a/doc/concepts/proxy.rst b/doc/concepts/proxy.rst
new file mode 100644
index 0000000..1af597a
--- /dev/null
+++ b/doc/concepts/proxy.rst
@@ -0,0 +1,118 @@
+FreeRADIUS as a proxy RADIUS server.
+====================================
+
+
+Introduction
+------------
+
+It is possible to use FreeRADIUS as a proxy RADIUS server. This
+means that it can consult a remote RADIUS server to validate a user.
+This is handy for roaming setups, or for renting ports to someone else.
+
+Files
+-----
+
+If a user logs in with a defined realm syntax, the "realm" portion is
+matched against the configuration to determine how the request should
+be handled. Common realm formats are:
+
+::
+
+ username@realm
+ realm/username
+ username%realm
+ realm\username
+
+The realm parsing syntax ( and search order ) is user definable via the
+realm module config in the ``/etc/raddb/mods-available/realm`` configuration
+file.
+
+You can define multiple instances of the realm module to support multiple
+realm syntax's at the same time. Be sure to pay close attention to the
+search order that you define, as you may inadvertently get unexpected
+behaviour ( by having a user use ``realm1/username@realm2`` for instance ).
+If you need to proxy to IPASS, it should go first, because usernames will
+be in the form ``IPASS/username@realm`` and you want to proxy these users to
+IPASS, not to the realm behind the ``@``.
+
+The realms are configured in the file ``/etc/raddb/proxy.conf``, which is
+included by ``radiusd.conf``. The formats and sample configurations are
+included as comments.
+
+The realm ``DEFAULT`` (without the quotes) matches all realms.
+The realm ``NULL`` matches any requests WITHOUT a realm.
+
+If you set the remote server to ``LOCAL``, the request will be handled
+locally as usual, without sending it to a remote radius server.
+
+There are several options you can add in ``/etc/raddb/proxy.conf``:
+
+- nostrip:
+ By default the realm is stripped from the username before sending it
+ on to the remote radius server. By specifying the "nostrip" option
+ the @realm suffix will not be stripped.
+- hints
+ By default the original username is sent to the remote radius
+ server. By specifying the "hints" option the username will be
+ sent as it is after the "hints" file was processed.
+- notrealm:
+ By default if a realm is matched, it will be proxied to the server
+ specified. However, if you are using Replication functionality, you
+ may want to override this behaviour. This option will prevent a
+ user who enters ``user@foobar`` from being proxied if the ``foobar``
+ realm configuration contains ``notrealm``. This function used to be
+ called ``notsuffix``, and the old syntax is still supported.
+
+The ``/etc/raddb/realms`` file is deprecated and should not be used anymore.
+If you use the ``/etc/raddb/realms`` file to enter realm configurations you will
+need to add the hostname and secret for the remote server in the
+file ``/etc/raddb/clients.conf``.
+It is not recommended to use both the realms file and the proxy.conf file,
+as that could cause confusion.
+
+Accounting
+----------
+
+All accounting data for proxied requests does `not` get stored in the
+standard logfiles, but in a separate directory. The name of this
+directory is the name of the remote radius server.
+
+Remote Server
+----------------
+
+When your server proxies requests to another server, it acts as a NAS for
+the remote server. On the remote server, you need to add the hostname of
+your server and the same secret to ``/etc/raddb/clients.conf`` as well.
+
+As you might not control the remote radius server, you might want to
+control the attributes sent back by the remote server in an Access-Accept
+packet. Have a look at the attrs file for this!
+
+What Happens
+---------------
+The exact thing that happens is this:
+
+- A user logs in with a realm
+- The hints file gets processed as usual
+- The user is checked against the huntgroups file. At this point
+ the user `might` already be rejected.
+- The realm is looked up in the realms file. If it isn't defined,
+ the users file is processed normally.
+- If the ``notrealm`` option is defined, the user is processed
+ locally.
+- The realm is stripped from the username unless ``nostrip`` was
+ set, and the request is sent to a remote radius server. Note that
+ any stripping done in the hints file doesn't have an effect on the
+ username sent to the remote radius server unless you set the
+ ``hints`` option.
+- The remote server replies with Access-Accept or Access-Reject
+
+::
+
+ On Access-Accept: The initial Auth-Type is set to Accept
+ On Access-Reject: The initial Auth-Type is set to Reject
+
+Then the users file is processed as usual. The username used at
+this point is the one after hints file processing (regardless of
+the ``hints`` option). It also includes the realm (regardless of the
+setting of the ``nostrip`` option) unless the realm is ``LOCAL``.
diff --git a/doc/configuration/acct_type.rst b/doc/configuration/acct_type.rst
new file mode 100644
index 0000000..e8abff4
--- /dev/null
+++ b/doc/configuration/acct_type.rst
@@ -0,0 +1,71 @@
+Acct-Type
+=========
+
+FreeRADIUS supports the Acct-Type attribute to select between
+accounting methods based on arbitrary attribute/value pairs contained
+in an accounting packet. Its use follows the same general configuration
+syntax as Auth-Type and Autz-Type. The main difference in configuration
+between Acct-Type and Auth/Autz-Type lies in where the Acct-Type
+method is assigned. With Auth/Autz-Type, the method is typically
+assigned in the 'users' file. The 'users' file, naturally, is not
+processed during the handling of the accounting {} section. However,
+part of the default files {} module is the 'acct_users' file, which
+serves the same purpose as the 'users' file, but applies to accounting
+packets.
+
+For example, a server administrator is responsible for handling the
+accounting data for two different realms, foo.com and bar.com, and
+wishes to use different instances of the SQL module for each. In
+addition, there is one RADIUS client sending accounting data that is
+to be logged only to a specific detail file. Everything else should
+use a third SQL instance.
+
+The acct_users file would look something like this::
+
+ DEFAULT Realm == "foo.com", Acct-Type := "SQLFOO"
+
+ DEFAULT Realm == "bar.com", Acct-Type := "SQLBAR"
+
+ DEFAULT Client-IP-Address == "10.0.0.1", Acct-Type := "OTHERNAS"
+
+And in radiusd.conf::
+
+ $INCLUDE ${confdir}/sql0.conf # Instance named 'sql0'.
+ $INCLUDE ${confdir}/sql1.conf # Instance named 'sql1'.
+ $INCLUDE ${confdir}/sql2.conf # Instance named 'sql2'.
+
+ detail othernas {
+ filename = ${radacctdir}/10.0.0.1/detail-%Y%m%d
+ }
+
+ preacct {
+ suffix # Add the Realm A/V pair.
+ files # Add the Acct-Type A/V pair based on the Realm A/V pair.
+ }
+
+ accounting {
+
+ # If Acct-Type is SQLFOO use the 'sql1' instance of the SQL module.
+
+ Acct-Type SQLFOO {
+ sql1
+ }
+
+ # If Acct-Type is SQLBAR, use the 'sql2' instance of the SQL module.
+
+ Acct-Type SQLBAR {
+ sql2
+ }
+
+ # If Acct-Type is OTHERNAS, use the 'othernas' instance of the detail
+ # module
+
+ Acct-Type OTHERNAS {
+ othernas
+ }
+
+ # If we've made it this far, we haven't matched an Acct-Type, so use
+ # the sql0 instance.
+
+ sql0
+ }
diff --git a/doc/configuration/autz_type.rst b/doc/configuration/autz_type.rst
new file mode 100644
index 0000000..a91e4e5
--- /dev/null
+++ b/doc/configuration/autz_type.rst
@@ -0,0 +1,88 @@
+Autz-Type
+=========
+
+Like Auth-Type for authentication method selection freeradius also
+supports the Autz-Type to select between authorization methods. The only
+problem is that authorization is the first thing to be called when an
+authentication request is handled. As a result we first have to call the
+authorize section without checking for Autz-Type. After that we check for
+Autz-Type and if it exists we call the corresponding subsection in the
+authorize section. In other words the authorize section in radiusd.conf
+should look like this::
+
+ authorize{
+ suffix
+ preprocess
+ # whatever other authorize modules here
+ Autz-Type Ldap{
+ ldap
+ }
+ Autz-Type SQL{
+ sql
+ }
+ files
+ }
+
+What happens is that the first time the authorize section is examined the
+suffix, preprocess and files modules are executed. If Autz-Type is set
+after that the server core checks for any matching Autz-Type subsection.
+If one is found it is called. The users file should look something
+like this::
+
+ DEFAULT Called-Station-Id == "123456789", Autz-Type := Ldap
+
+ DEFAULT Realm == "other.example.com", Autz-Type := SQL
+
+Autz-Type could also be used to select between multiple instances of
+a module (ie sql or ldap) which have been configured differently. For
+example based on the user realm different ldap servers (belonging to
+different companies) could be queried. If Auth-Type was also set then we
+could do both Authentication and Authorization with the user databases
+belonging to other companies. In detail:
+
+radiusd.conf::
+
+ authenticate{
+ Auth-Type customer1{
+ ldap1
+ }
+ Auth-Type customer2{
+ ldap2
+ }
+ }
+
+ authorize{
+ preprocess
+ suffix
+ Autz-Type customer1{
+ ldap1
+ }
+ Autz-Type customer2{
+ ldap2
+ }
+ files
+ }
+
+The users file::
+
+ DEFAULT Realm == "customer1", Autz-Type := customer1, Auth-Type := customer1
+
+ DEFAULT Realm == "customer2", Autz-Type := customer2, Auth-Type := customer2
+
+
+Apart from Autz-Type the server also supports the use of
+Acct-Type, Session-Type and Post-Auth-Type for the corresponding sections.
+The corresponding section names in the radiusd.conf file are the same. So for example:
+
+users file::
+
+ DEFAULT Called-Station-Id == "236473", Session-Type := SQL
+
+radiusd.conf::
+
+ session {
+ radutmp
+ Session-Type SQL {
+ sql
+ }
+ }
diff --git a/doc/configuration/configurable_failover.rst b/doc/configuration/configurable_failover.rst
new file mode 100644
index 0000000..4e21335
--- /dev/null
+++ b/doc/configuration/configurable_failover.rst
@@ -0,0 +1,476 @@
+Configurable Module Fail Over
+=============================
+
+Before configurable module failover, we had this kind of entry in
+``radiusd.conf``:
+
+::
+
+ #---
+ authorize {
+ preprocess
+ files
+ }
+ #---
+
+This entry instructed the ``authorize`` section to first process the
+request through the ``preprocess`` module, and if that returned success,
+to process it through ``files`` module. If that sequence returned
+success, then the ``authorize`` stage itself would then return success.
+Processing was strictly linear and if one module failed, the whole
+section would fail immediately.
+
+Configurable failover provides more flexibility. It takes advantage
+of the tree structure of radiusd.conf to support a configuration
+language that allows you to ``group`` modules that should work together
+in ways other than simple lists. You can control the flow of any
+stage (e.g. ``authorize``) to fit your needs, without touching C code,
+just by altering radiusd.conf.
+
+This configurable fail-over has a convenient short-hand, too.
+Administrators commonly want to say things like "try SQL1, if it's
+down, try SQL2, otherwise drop the request."
+
+For example:
+
+::
+
+ #---
+ modules {
+ sql sql1 {
+ # configuration to connect to SQL database one
+ }
+ sql sql2 {
+ # configuration to connect to SQL database two
+ }
+ always handled {
+ rcode = handled
+ }
+ }
+
+ # Handle accounting packets
+ accounting {
+ detail # always log to detail, stopping if it fails
+ redundant {
+ sql1 # try module sql1
+ sql2 # if that's down, try module sql2
+ handled # otherwise drop the request as
+ # it's been ``handled`` by the ``always``
+ # module (see doc/rlm_always)
+ }
+ }
+ #---
+
+The ``redundant`` section is a configuration directive which tells the
+server to process the second module if the first one fails. Any
+number of modules can be listed in a ``redundant`` section. The server
+will process each in turn, until one of the modules succeeds. It will then stop processing the ``redundant`` list.
+
+Rewriting results for single modules
+------------------------------------
+
+Normally, when a module fails, the entire section (``authorize``,
+``accounting``, etc.) stops being processed. In some cases, we may want
+to permit "soft failures". That is, we may want to tell the server
+that it is "ok" for a module to fail, and that the failure should not
+be treated as a fatal error.
+
+In this case, the module is treated as a "section", rather than just
+as a single lne in ``radiusd.conf``. The configuration entries for
+that section are taken from the ``configurable fail-over`` code, and not
+from the configuration information for that module.
+
+For example, the ``detail`` module normally returns ``fail`` if it is
+unable to write its information to the ``detail`` file. As a test, we
+can configure the server so that it continues processing the request,
+even if the ``detail`` module fails. The following example shows how:
+
+::
+
+ #--
+ # Handle accounting packets
+ accounting {
+ detail {
+ fail = 1
+ }
+ redundant {
+ sql1
+ sql2
+ handled
+ }
+ }
+ #--
+
+The ``fail = 1`` entry tells the server to remember the ``fail`` code,
+with priority ``1``. The normal configuration is ``fail = return``, which
+means ``if the detail module fails, stop processing the accounting
+section``.
+
+Fail-over configuration entries
+-------------------------------
+
+Modules normally return on of the following codes as their result:
+
++-----------+-----------------------------------------------------+
+|Code | Meaning |
++===========+=====================================================+
+|notfound | the user was not found |
++-----------+-----------------------------------------------------+
+|noop | the module did nothing |
++-----------+-----------------------------------------------------+
+|ok | the module succeeded |
++-----------+-----------------------------------------------------+
+|updated | the module updated information in the request |
++-----------+-----------------------------------------------------+
+|fail | the module failed |
++-----------+-----------------------------------------------------+
+|reject | the module rejected the user |
++-----------+-----------------------------------------------------+
+|userlock | the user was locked out |
++-----------+-----------------------------------------------------+
+|invalid | the user's configuration entry was invalid |
++-----------+-----------------------------------------------------+
+|handled | the module has done everything to handle the request|
++-----------+-----------------------------------------------------+
+
+In a configurable fail-over section, each of these codes may be
+listed, with a value. If the code is not listed, or a configurable
+fail-over section is not defined, then values that make sense for the
+requested ``group`` (group, redundant, load-balance, etc) are used.
+
+The special code ``default`` can be used to set all return codes to
+the specified value. This value will be used with a lower priority
+than ones that are explicitly set.
+
+The values for each code may be one of two things:
+
++---------+---------------------------------------------------------------+
+|Value | Meaning |
++=========+===============================================================+
+|<number> | Priority for this return code. |
++---------+---------------------------------------------------------------+
+|return | Stop processing this configurable fail-over list. |
++---------+---------------------------------------------------------------+
+|reject | Stop processing this configurable fail-over list and |
+| | immediately return a reject. |
++---------+---------------------------------------------------------------+
+
+The ``<number>`` used for a value may be any decimal number between 1
+and 99999. The number is used when processing a list of modules, to
+determine which code is returned from the list. For example, if
+``module1`` returns ``fail`` with priority ``1``, and a later ``module2``
+returns ``ok`` with priority ``3``, the return code from the list of
+modules will be ``ok``, because it has higher priority than ``fail``.
+
+This configurability allows the administrator to permit some modules
+to fail, so long as a later module succeeds.
+
+
+More Complex Configurations
+---------------------------
+
+The ``authorize`` section is normally a list of module names. We can
+create sub-lists by using the section name ``group``. The ``redundant``
+section above is just a short-hand for ``group``, with a set of default
+return codes, which are different than the normal ``stop processing the
+list on failure``.
+
+For example, we can configure two detail modules, and allow either
+to fail, so long as one of them succeeds.
+
+::
+
+ #--
+ # Handle accounting packets
+ accounting {
+ group {
+ detail1 {
+ fail = 1 # remember ``fail`` with priority 1
+ ok = return # if we succeed, don't do ``detail2``
+ }
+ detail2 {
+ fail = 1 # remember ``fail`` with priority 1
+ ok = return # if we succeed, return ``ok``
+ # if ``detail1`` returned ``fail``
+ }
+ } # returns ``fail`` only if BOTH modules returned ``fail``
+ redundant {
+ sql1
+ sql2
+ handled
+ }
+ }
+ #--
+
+This configuration says:
+
+ - log to ``detail1``, and stop processing the ``group`` list if ``detail1`` returned OK.
+
+ - If ``detail1`` returned ``fail``, then continue, but remember the ``fail`` code, with priority 1.
+
+ - If ``detail2`` fails, then remember ``fail`` with priority 1.
+
+ - If ``detail2`` returned ``ok``, return ``ok`` from the ``group``.
+
+The return code from the ``group`` is the return code which was either
+forced to return (e.g. ``ok`` for ``detail1``), or the highest priority
+return code found by processing the list.
+
+This process can be extended to any number of modules listed in a
+``group`` section.
+
+
+Virtual Modules
+---------------
+
+Some configurations may require using the same list of modules, in
+the same order, in multiple sections. For those systems, the
+configuration can be simplified through the use of ``virtual`` modules.
+These modules are configured as named sub-sections of the
+``instantiate`` section, as follows:
+
+::
+
+ instantiate {
+ ...
+
+ redundant sql1_or_2 {
+ sql1
+ sql2
+ }
+ }
+
+The name ``sql1_or_2`` can then be used in any other section, such as
+``authorize`` or ``accounting``. The result will be *exactly* as if that
+section was placed at the location of the ``sql1_or_2`` reference.
+
+These virtual modules are full-fledged objects in and of themselves.
+One virtual module can refer to another virtual module, and they can
+contain ``if`` conditions, or any other configuration permitted in a
+section.
+
+
+Redundancy and Load-Balancing
+-----------------------------
+
+See ``man unlang`` or ``doc/load-balance`` for information on simple
+redundancy (fail-over) and load balancing.
+
+
+The Gory Details
+-----------------
+
+The fundamental object is called a MODCALLABLE, because it is something that
+can be passed a specific radius request and returns one of the RLM_MODULE_*
+results. It is a function - if you can accept the fact that pieces of
+radiusd.conf are functions. There are two kinds of MODCALLABLEs: GROUPs and
+SINGLEs.
+
+A SINGLE is a reference to a module instance that was set up in the modules{}
+section of radiusd.conf, like ``preprocess`` or ``sql1``. When a SINGLE is
+called, the corresponding function in the rlm is invoked, and whichever
+RLM_MODULE_* it returns becomes the RESULT of the SINGLE.
+
+A GROUP is a section of radiusd.conf that includes some MODCALLABLEs.
+Examples of GROUPs above include ``authorize{...}``, which implements the C
+function module_authorize, and ``redundant{...}``, which contains two SINGLEs
+that refer to a couple of redundant databases. Note that a GROUP can contain
+other GROUPs - ``Auth-Type SQL{...}`` is also a GROUP, which implements the C
+function module_authenticate when Auth-Type is set to SQL.
+
+Now here's the fun part - what happens when a GROUP is called? It simply runs
+through all of its children in order, and calls each one, whether it is
+another GROUP or a SINGLE. It then looks at the RESULT of that child, and
+takes some ACTION, which is basically either ``return that RESULT immediately``
+or ``Keep going``. In the first example, any ``bad`` RESULT from the preprocess
+module causes an immediate return, and any ``good`` RESULT causes the
+authorize{...} GROUP to proceed to the files module.
+
+We can see the exact rules by writing them out the long way:
+
+::
+
+ authorize {
+ preprocess {
+ notfound = 1
+ noop = 2
+ ok = 3
+ updated = 4
+ fail = return
+ reject = return
+ userlock = return
+ invalid = return
+ handled = return
+ }
+ files {
+ notfound = 1
+ noop = 2
+ ok = 3
+ updated = 4
+ fail = return
+ reject = return
+ userlock = return
+ invalid = return
+ handled = return
+ }
+ }
+
+This is the same as the first example, with the behavior explicitly
+spelled out. Each SINGLE becomes its own section, containing a list of
+RESULTs that it may return and what ACTION should follow from them. So
+preprocess is called, and if it returns for example RLM_MODULE_REJECT,
+then the reject=return rule is applied, and the authorize{...} GROUP
+itself immediately returns RLM_MODULE_REJECT.
+
+If preprocess returns RLM_MODULE_NOOP, the corresponding ACTION is ``2``. An
+integer ACTION serves two purposes - first, it tells the parent GROUP to go
+on to the next module. Second, it is a hint as to how desirable this RESULT
+is as a candidate for the GROUP's own RESULT. So files is called... suppose
+it returns RLM_MODULE_NOTFOUND. The ACTION for notfound inside the files{...}
+block is ``1``. We have now reached the end of the authorize{...} GROUP and we
+look at the RESULTs we accumulated along the way - there is a noop with
+preference level 2, and a notfound with preference level 1, so the
+authorize{...} GROUP as a whole returns RLM_MODULE_NOOP, which makes sense
+because to say the user was not found at all would be a lie, since preprocess
+apparently found him, or else it would have returned RLM_MODULE_NOTFOUND too.
+
+We could use the ``default`` code to simplify the above example a
+little. The following two configurations are identical:
+
+::
+
+ files {
+ notfound = 1
+ noop = 2
+ ok = 3
+ updated = 4
+ default = return
+ }
+
+
+When putting the ``default`` first, later definitions over-ride it's
+return code:
+
+::
+
+ files {
+ default = return
+ notfound = 1
+ noop = 2
+ ok = 3
+ updated = 4
+ }
+
+[Take a deep breath - the worst is over]
+
+That RESULT preference/desirability stuff is pretty complex, but my hope is
+that it will be complex enough to handle the needs of everyone's real-world
+imperfect systems, while staying out of sight most of the time since the
+defaults will be right for the most common configurations.
+
+So where does redundant{...} fit in with all that? Well, redundant{...} is
+simply a group that changes the default ACTIONs to something like
+
+::
+
+ fail = 1
+ everythingelse = return
+
+so that when one module fails, we keep trying until we find one that doesn't
+fail, then return whatever it returned. And at the end, if they all failed,
+the redundant GROUP as a whole returns RLM_MODULE_FAIL, just as you'd want it
+to (I hope).
+
+There are two other kinds of grouping: ``group{...}`` which does not have any
+specialized default ACTIONs, and ``append{...}``, which should be used when you
+have separate but similarly structured databases that are guaranteed not to
+overlap.
+
+That's all that really needs to be said. But now a few random notes:
+
+GROUPs may have RESULT=ACTION
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+It would look like this:
+
+::
+
+ authorize {
+ preprocess
+ redundant {
+ sql1
+ sql2
+ notfound = return
+ }
+ files
+ }
+
+which would prevent ``files`` from being called if neither of the SQL
+instances could find the user.
+
+redundant{...} and append{...} are just shortcuts
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+You could write:
+
+::
+
+ group {
+ sql1 {
+ fail = 1
+ notfound = 2
+ noop = return
+ ok = return
+ updated = return
+ reject = return
+ userlock = return
+ invalid = return
+ handled = return
+ }
+ sql2 {
+ fail = 1
+ notfound = 2
+ noop = return
+ ok = return
+ updated = return
+ reject = return
+ userlock = return
+ invalid = return
+ handled = return
+ }
+ }
+ instead of
+ redundant {
+ sql1
+ sql2
+ }
+
+but the latter is just a whole lot easier to read.
+
+``authenticate{...}`` is not a GROUP
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+even though it contains a list of ``Auth-Type`` GROUPs, because its
+semantics are totally different - it uses ``Auth-Type`` to decide which of
+its members to call, and their order is irrelevant.
+
+The default rules are context-sensitive
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+For ``authorize``, the defaults are
+what you saw above - notfound, noop, ok, and updated are considered
+success, and anything else has an ACTION of ``return``. For authenticate, the
+default is to return on success *or* reject, and only try the second and
+following items if the first one fails. You can read all the default ACTIONs
+in modcall.c (int defaultactions[][][]), or just trust me. They do the right
+thing.
+
+There are some rules that can't be implemented in this language
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+things like ``notfound = 1-reject``, ``noop = 2-ok``, ``ok = 3-ok``, etc. But I don't feel
+justified adding that complexity in the first draft.
+There are already enough things here that may never see real-world usage.
+Like append{...}
+
+-- Pac. 9/18/2000
diff --git a/doc/configuration/dynamic_home_servers.md b/doc/configuration/dynamic_home_servers.md
new file mode 100644
index 0000000..7518f0a
--- /dev/null
+++ b/doc/configuration/dynamic_home_servers.md
@@ -0,0 +1,238 @@
+# Dynamic Home Servers in v3
+
+FreeRADIUS has some support for dynamic home servers, with certain
+limitations.
+
+
+## Configuration
+
+The configuration needs to have dynamic home servers enabled, by
+editing `proxy.conf`.
+
+```
+proxy server {
+ ...
+ dynamic = true
+ ...
+}
+```
+
+This configuration item causes the internal data structures to become
+thread-safe for updates. This change means that there will be more
+lock contention on the data structures holding home servers. As a
+result, high-load proxy may see slowdowns.
+
+Once dynamic home servers are enabled, they should be placed into
+a subdirectory. FreeRADIUS should be told which subdirectory the
+home servers are located in:
+
+```
+proxy server {
+ ...
+ dynamic = true
+ ...
+ directory = ${raddb}/home_servers/
+}
+```
+
+This directory should contain nothing other than definitions for
+dynamic home servers. These definitions are simply normal
+`home_server` definitions:
+
+```
+home_server example.com {
+ ...
+}
+```
+
+Each file in the directory should be named for the home server domain
+name. In the above example, the filename should be
+`${raddb}/home_servers/example.com`. The name of the home server in
+the file should be the same as the filename which contains the home
+server definition.
+
+Each file in the directory should have one, and only one,
+`home_server` definition.
+
+Home servers which use RadSec can `$INCLUDE tls.conf` in this
+directory to use a common site-local TLS configuration. The script
+`freeradius-naptr-to-home-server.sh` referenced below assumes that
+this file exists. If you are not using that file, it is safe to just
+replace it with an empty file.
+
+### The Control Socket
+
+The virtual server `sites-enabled/control` *must* be enabled for
+dynamic home servers to work. The `radmin` program *must* have
+read/write permission in order for dynamic home servers to work.
+
+Please see that `sites-enabled/control` file for information on
+configuring that virtual server.
+
+
+## Starting FreeRADIUS
+
+When FreeRADIUS starts, it will read each file in the
+`${raddb}/home_servers/` directory. The file will parsed in order to
+define a dynamic `home_server`.
+
+
+## Adding a new Home Server
+
+In order to add a new home server while FreeRADIUS is running, simply
+add a new `home_server` definition file to the
+`${raddb}/home_servers/` directory.
+
+Then, tell FreeRADIUS that the home server is available in a new file:
+
+```
+$ radmin -e "add home_server file /path/to/raddb/home_servers/example/com"
+```
+
+If all goes well, the home server will be added. If there are issues,
+`radmin` will print a descriptive error.
+
+Once a dynamic home server has been added, it can be used just like
+any other home server.
+
+
+## Deleting a Home Server
+
+Dynamically created home servers can be deleted via `radmin`. Note
+also that dynamic home servers which are loaded when FreeRADIUS starts
+can be deleted.
+
+```
+$ radmin -e "del home_server file <name> <type>"
+```
+
+Note that this command deletes the home server by name and type, not
+by filename. This difference from the `add home_server` command is
+due to internal limitations in the server core.
+
+```
+home_server <name> {
+ type = <type>
+}
+```
+
+
+## Listing a Home Server
+
+It is possible to list all home servers and know which is dynamic or no.
+
+```
+$ radmin -e "show home_server list all"
+```
+
+
+## Limitations
+
+Note that due to internal limitations, dynamic home servers are _not_
+freed. So repeatedly adding and deleted home servers _will_ cause
+FreeRADIUS to gradually use more memory.
+
+Other internal limitations means that it is impossible to add dynamic
+home servers to a `home_server_pool`. In short, dynamic home servers
+exist by themselves, with no associated realm, pool, or failover
+capability.
+
+
+## Proxying to a Home Server
+
+The new attribute `Home-Server-Name` controls proxying to a particular
+home server. The home server just has to exist, it does not need to
+be a dynamic home server.
+
+```
+authorize {
+ ...
+
+ update control {
+ Home-Server-Name := "example.com"
+ }
+ ...
+}
+```
+
+
+## Checking if a Dynamic Home Server exists
+
+You can see if a dynamic home server exists through the following
+dynamic string expansion:
+
+```
+%{home_server_dynamic:name}
+```
+
+This expansion looks up the home server by name, and returns whether
+or not the home server exists, and is dynamic.
+
+The return values are:
+
+* empty string - the home server does not exist.
+* `0` - the home server exists, and is statically defined.
+* `1` - the home server exists, and is dynamically defined
+
+```
+authorize {
+ ...
+ if (User-Name =~ /@(.*)$/) {
+ switch "%{home_server_dynamic:%{1}}" {
+ case "1" {
+ # Proxy to this one particular home server
+ update control {
+ &Home-Server-Name := "%{1}"
+ }
+ }
+
+ case "0" {
+ # Proxy with home server pool, failover, etc.
+ update control {
+ &Proxy-To-Realm := "%{1}"
+ }
+ }
+
+ case {
+ # no home server exists, ask DNS
+ update control {
+ # you can add a parameter for the NAPTR tag to look up, e.g. "aaa+auth:radius.tls.tcp" (RFC7585, OpenRoaming)
+ # if the third parameter is omitted, it defaults to "x-eduroam:radius.tls"
+ &Temp-Home-Server-String := `%{config:confdir}/mods-config/realm/freeradius-naptr-to-home-server.sh -d %{config:confdir} %{1}`
+ }
+ if ("%{control:Temp-Home-Server-String}" == "" ) {
+ reject
+ } else {
+ update control {
+ &Home-Server-Name := "%{1}"
+ }
+ }
+ }
+ }
+ }
+ ...
+}
+```
+
+## Maintenance of Dynamic Home Servers
+
+Dynamic home servers are discovered from DNS, and DNS has TTLs. These
+TTLs are not tracked by FreeRADIUS, as they are not available when
+using the standard DNS APIs.
+
+Dynamic realms should be regularly deleted, so that they can be
+recreated with updated information. The server should be restarted
+with an empty home_server directory regularly, for two reasons:
+
+* Entries in DNS may change over time, or be removed, and the server should learn this.
+ If the entries are not removed, the server will not discover any changes.
+* dynamic home servers are often RADIUS/TLS based with client and server certificates,
+ and the server should refresh CRL information regularly
+
+As a result, we recommend emptying the home_servers directory (except
+for the `tls.conf` file), refreshing CRLs and then restarting the server
+once per day. e.g.
+
+```
+rm -f $(ls -1 raddb/home_servers | egrep -v tls.conf)
+```
diff --git a/doc/configuration/load_balance.rst b/doc/configuration/load_balance.rst
new file mode 100644
index 0000000..7926444
--- /dev/null
+++ b/doc/configuration/load_balance.rst
@@ -0,0 +1,172 @@
+Load Balancing
+==============
+
+As of version 2.0.0, the load balance documentation is in the
+available in the "unlang" man page. The text below may not be up to
+date, and is here only for historical purposes.
+
+As of version 1.1.0, FreeRADIUS supports load balancing in module
+sections. Please see the "configurable_failover" file in this
+directory for a more complete description of module sections.
+
+The short summary is that you can use a "load-balance" section in
+any place where a module name may be used. The semantics of the
+"load-balance" section are that one of the modules in the section will
+be chosen at random, evenly spread over the modules in the list.
+
+An example is below::
+
+ accounting {
+ load-balance {
+ sql1
+ sql2
+ sql2
+ }
+ }
+
+In this case, 1/3 of the RADIUS requests will be processed by
+"sql1", one third by "sql2", and 1/3 by "sql3".
+
+The "load-balance" section can be nested in a "redundant" section,
+or vice-versa::
+
+ accounting {
+ load-balance { # between two redundant sections below
+ redundant {
+ sql1
+ sql2
+ }
+ redundant {
+ sql2
+ sql1
+ }
+ }
+ }
+
+This says "load balance between sql1 and sql2, but if sql1 is down,
+use sql2, and if sql2 is down, use sql1". That way, you can guarantee
+both that load balancing occurs, and that the requests are *always*
+logged to one of the databases::
+
+ accounting {
+ redundant {
+ load-balance {
+ sql1
+ sql2
+ }
+ detail
+ }
+ }
+
+This says "load balance between sql1 and sql2, but if the one being
+used is down, then log to detail".
+
+And finally::
+
+ accounting {
+ redundant { # between load-balance & detail
+ load-balance { # between two redundant sections
+ redundant {
+ sql1
+ sql2
+ }
+ redundant {
+ sql2
+ sql1
+ }
+ }
+ detail
+ }
+ }
+
+This says "try to load balance between sql1 and sql2; if sql1 is down,
+use sql2; if sql2 is down use sql1; if both sql1 and sql2 are down,
+then log to the detail file"
+
+
+More complicated scenarios
+--------------------------
+
+If you want to do redundancy and load-balancing among three
+modules, the configuration is quite complex::
+
+ load-balance {
+ redundant {
+ sql1
+ load-balance {
+ redundant {
+ sql2
+ sql3
+ }
+ redundant {
+ sql3
+ sql2
+ }
+ }
+ } # sql1, etc.
+ redundant {
+ sql2
+ load-balance {
+ redundant {
+ sql3
+ sql1
+ }
+ redundant {
+ sql1
+ sql3
+ }
+ }
+ } # sql2, etc.
+ redundant {
+ sql3
+ load-balance {
+ redundant {
+ sql1
+ sql2
+ }
+ redundant {
+ sql2
+ sql1
+ }
+ }
+ } # sql3, etc.
+ }
+
+For four or more modules, it quickly becomes unmanageable.
+
+The solution is to use the "redundant-load-balance" section, which
+combines the features of "load-balance", with "redundant" fail-over
+between members. The above complex configuration for three modules
+then becomes::
+
+ redundant-load-balance {
+ sql1
+ sql2
+ sql3
+ }
+
+
+Which means "load-balance evenly among all three servers. If the
+one picked for load-balancing is down, load-balance among the
+remaining two. If that one is down, pick the one remaining 'live'
+server".
+
+The "redundant-load-balance" section can contain any number of
+modules.
+
+
+Interaction with "if" and "else"
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+It's best to have "if" and "else" blocks contain "load-balance" or
+"redundant-load-balance" sections, rather than the other way around.
+The "else" and "elsif" sections cannot appear inside of a
+"load-balance" or "redundant-load-balance" section, because the "else"
+condition would be chose as one of the modules for load-balancing,
+which is not what you want.
+
+It's OK to have a plain "if" block inside of a "load-balance" or
+"redundant-load-balance" section. In that case, the "if" condition
+checks the return code of the module or group that executed just
+before the "load-balance" section. It does *not* check the return
+code of the previous module in the section.
diff --git a/doc/configuration/post_auth_type b/doc/configuration/post_auth_type
new file mode 100644
index 0000000..7492324
--- /dev/null
+++ b/doc/configuration/post_auth_type
@@ -0,0 +1,44 @@
+This is now called Post-Auth-Type, for consistency.
+
+O.INTRODUCTION
+
+ Post-Auth-Type is used to select between groupings of
+ modules in the post-auth stanza using arbitrary attributes.
+ It is functionally identical to Acct-Type, apart from
+ the name of the attribute and its dealing with rejected
+ requests.. This means that (unlike Autz-Type) the attribute
+ must be set before the stanza is run. Changes to
+ Post-Auth-Type during post-auth will have no effect.
+
+1.HOW IT WORKS
+
+ If a request has been rejected, the value of Post-Auth-Type
+ is overwritten with REJECT automatically, so anonymous
+ modules outside the REJECT substanza will not be run, only
+ modules within the appropriate substanza will be run.
+
+2.EXAMPLES
+
+ In the example below, when a request has been rejected, the
+ module my_ippool will not be run, only the module my_detail
+ will be run.
+ If the request is not rejected, the my_ippool module will be
+ run, but not the my_detail module
+
+ post-auth {
+ my_ippool
+ Post-Auth-Type REJECT {
+ my_detail
+ }
+ }
+
+ In the following example, 2 different sql modules are used
+ to store accepted requests and rejected requests.
+
+ post-auth {
+ my_sql_accept
+ Post-Auth-Type REJECT {
+ my_sql_reject
+ }
+ }
+
diff --git a/doc/configuration/session_type b/doc/configuration/session_type
new file mode 100644
index 0000000..9efcd7c
--- /dev/null
+++ b/doc/configuration/session_type
@@ -0,0 +1,10 @@
+Session-Type is used to select between groupings of
+modules in the session stanza using arbitrary attributes.
+It is functionally identical to Acct-Type, apart from
+the name of the attribute. This means that (unlike
+Autz-Type) the attribute must be set before the stanza
+is run. Changes to Session-Type during session will
+have no effect.
+
+This allows Simultaneous-Use checking behaviour to be very flexible.
+
diff --git a/doc/configuration/simultaneous_use b/doc/configuration/simultaneous_use
new file mode 100644
index 0000000..5639738
--- /dev/null
+++ b/doc/configuration/simultaneous_use
@@ -0,0 +1,173 @@
+
+ FreeRADIUS server and the Simultaneous-Use parameter.
+
+
+0. INTRODUCTION
+
+ Lots of people want to limit the number of times one user account can
+ login, usually to one. This is hard to do with the radius protocol;
+ the nature of the accounting stuff is such that the idea the radius server
+ has about the list of logged-in users might be different from the idea
+ the terminal server has about it.
+
+ However, most terminal servers have an alternative way to get a list
+ of logged-in users. Most support some way through telnet, some have
+ a finger-daemon builtin and a lot of them support SNMP. So if the
+ radius server thinks that someone is trying to login a second time,
+ it is possible to check on the terminal server itself if the first
+ login is indeed still active. Only then access is denied for the
+ second login.
+
+
+1. PREREQUISITES
+
+ You need to have perl installed.
+
+ For SNMP checks, you have 2 options. You can use the `snmpget' program
+ from the cmu-snmp tools. You can probably get precompiled ones,
+ maybe even packaged for your system (Debian/Linux, Redhat/Linux, FreeBSD
+ ports collection etc). The source code is at
+ http://www.net.cmu.edu/projects/snmp/snmpapps/. The Linux-specific
+ version of this is at http://www.gaertner.de/snmp/
+
+ The other option is to install the SNMP_Session and BER modules that
+ for example the well known `mrtg' package uses. This is recommended.
+ In that case you need no external snmpget program, checkrad will
+ speak SNMP directly. See http://www.switch.ch/misc/leinen/snmp/perl/
+
+ The checkroutine for USR/3Com Total Control racks uses the Net::Telnet
+ module from CPAN, at least version 3.00. If you need that, obtain it from
+ your local CPAN mirror (or see http://www.perl.com/CPAN/). The checkrad.pl
+ perl script will autodetect if that module is installed.
+
+2. USAGE.
+
+ It works by adding the `check' parameter "Simultaneous-Use" to the entry
+ for a users or DEFAULT in /etc/raddb/users. It should be at least one;
+ it defines the maximum number of users logged in with the same account name.
+ For example:
+
+ #
+ # Simultaneous use restrictions.
+ #
+ DEFAULT Group == "staff", Simultaneous-Use := 4
+ Fall-Through = 1
+ DEFAULT Group == "business", Simultaneous-Use := 2
+ Fall-Through = 1
+ DEFAULT Simultaneous-Use := 1
+ Fall-Through = 1
+
+
+ NOTE!!! The "Simultaneous-Use" parameter is in the "check" A/V pairs,
+ and not in the Reply A/V pairs (it _is_ a check).
+
+ For SQL, after creating and populating your schema, you should
+ execute the following statement (for MySQL, others may vary):
+
+ INSERT INTO radgroupcheck (GroupName, Attribute, op, Value) values("dialup", "Simultaneous-Use", ":=", "1");
+
+ Once that is done, your users should be limited to only one login at a time.
+
+3. IMPLEMENTATION
+
+ The server keeps a list of logged-in users in the /var/log/radutmp file.
+ This is also called "the session database". When you execute "radwho",
+ all that radwho really does is list the entries in this file in a pretty
+ format. Only when someone tries to login who _already_ has an active
+ session according to the radutmp file, the server executes the perl
+ script /usr/local/sbin/checkrad (or /usr/sbin/checkrad, it checks for
+ the presence of both and in that order). This script queries the terminal
+ server to see if the user indeed already has an active session.
+
+ The script uses SNMP for Livingston Portmasters and Ciscos, finger for
+ Portslave, Computone and Ascend, and Net::Telnet for USR/3Com TC.
+
+ Since the script has been witten in perl, it's easy to adjust for
+ any type of terminal server. There are implementations in the script for
+ checks using SNMP, finger, and telnet, so it should be easy to add
+ your own check routine if your terminal server is not supported yet.
+
+ You can find the script in the file src/checkrad.pl.
+
+ You need to set the correct type in the file /etc/raddb/naslist so that
+ checkrad KNOWS how it should interrogate the terminal server. At this
+ time you can define the following types:
+
+ type Vendor Uses method needs Need naspasswd
+ ==== ====== =========== ===== ==============
+ ascend Lucent SNMP SNMP No
+ bay Nortel finger finger command No
+ cisco Cisco SNMP SNMP Optional [1]
+ computone Computone finger finger command No
+ cvx Nortel SNMP SNMP No
+ digitro Digitro rusers rusers command No
+ livingston Livingston SNMP SNMP No [2]
+ max40xx Lucent finger finger command No
+ netserver USR/3com telnet CPAN Net::Telnet Yes
+ pathras Cyclades telnet CPAN Net::Telnet Yes
+ patton Patton SNMP SNMP No
+ portslave ? finger finger command No
+ pr3000 Cyclades SNMP snmpwalk command No
+ pr4000 Cyclades SNMP snmpwalk command No
+ tc USR/3com telnet CPAN Net::Telnet Yes
+ usrhyper USR/3com SNMP SNMP No [3]
+ versanet VersaNet SNMP SNMP No
+
+ other none N/A - No
+
+ [1] In naspasswd file: set username to SNMP, password is community.
+ [2] Needs at least ComOS 3.5, SNMP enabled.
+ [3] Set "Reported Port Density" to 256 (default)
+
+ "other" means "don't bother checking, I believe what radutmp says".
+ This really is not recommended, if a user has a "stuck" entry in the
+ session database she will not be able to login again - hence the
+ extra check that "checkrad" does.
+
+4. IF IT DOESN'T WORK
+
+ Note that you need to add the Simultaneous-Use parameter to the
+ check item (first line), not the reply item, using the ':=' operator.
+
+ You can edit the `checkrad' perl script and turn on debugging. Then
+ watch the debug file. The `radius.log' file also gives some hints.
+
+ You can also run the "checkrad" script manually, use the "-d"
+ switch to get debug output on standard output instead of in the log.
+
+ See also:
+
+ http://wrath.geoweb.ge/simult.html
+
+ which has a good discussion of the use of Simultaneous-Use.
+
+
+5. CAVEATS
+
+ This solution checks the radutmp file. This file is kept up-to-date from
+ the Accounting records the NAS sends. Since some NASes delay these records
+ for quite some time, it is possible to get a double login by logging in
+ twice at _exactly_ the same time (plus or minus the mentioned delay time),
+ since neither of the logins are registered yet.
+
+ The solution would be to create a small 1-minute cache of Authentication
+ records, that is also checked for double login attempts. Perhaps in the
+ next version.
+
+ When implementing this one thing was considered the most important: when
+ trying to detect double logins, we always try to err on the safe side. So
+ in rare cases, a double login is possible but we try never to limit access
+ for a legitimate login.
+
+6. PROBLEMS WITH DROPPED CONNECTIONS
+
+ Our PM3, with 2 ISDN-30 lines coming into it, had the habit of sometimes
+ dropping connections. In a few cases, the portmaster thought the session was
+ still alive so if the user tried to login again, he or she was denied access.
+ In our case, this problem was caused by a bad PRI line from the phone
+ company.
+
+ We tried to compensate this by setting the Idle-Timeout to 15 minutes. That
+ way, even if a user did get locked out the portmaster would clear the rogue
+ session within 15 minutes and the user could login again.
+
diff --git a/doc/configuration/snmp b/doc/configuration/snmp
new file mode 100644
index 0000000..713cb83
--- /dev/null
+++ b/doc/configuration/snmp
@@ -0,0 +1,58 @@
+INSTALL
+-------
+
+Installing the SNMP patch is straightforward:
+
+$ tar -zxf freeradius-server-2.1.11.tar.gz
+$ cd freeradius-server-2.1.11
+$ patch -p1 < ../snmp.patch
+$ ./configure --args....
+$ make
+$ make install
+
+MIB Installation
+----------------
+
+The traps *REQUIRE* that the files in the "mibs" directory be copied
+to the global mibs directory, usually /usr/share/snmp/mibs/.
+If this is not done, the "snmptrap" program has no idea what information
+to send, and will not work. The MIB installation is *NOT* done as
+part of the default installation, so that step *MUST* be done manually.
+
+The global MIB directory can be found by running the following command:
+
+ $ snmptranslate -Dinit_mib .1.3 2>&1 | grep MIBDIR | sed "s/' .*//;s/.* '//;s/.*://"
+
+Or maybe just:
+
+ $ snmptranslate -Dinit_mib .1.3 2>&1 | grep MIBDIR
+
+If you have copied the MIBs to that directory, you can test the
+FreeRADIUS MIBs by running the following command:
+
+ $ snmptranslate -m +FREERADIUS-NOTIFICATION-MIB -IR -On serverStart
+
+It should print out:
+
+ .1.3.6.1.4.1.11344.4.1.1
+
+As always, run the server in debugging mode after enabling the
+traps. You will see the "snmptrap" command being run, and it will
+print out any errors or issues that it encounters. Those need to
+be fixed before running the server in daemon mode.
+
+We also suggest running in debugging mode as the "radiusd" user, if
+you have "user/group" set in radiusd.conf. The "snmptrap" program
+may behave differently when run as "root" or as the "radiusd" user.
+
+You will also need to edit "radiusd.conf", and uncomment the line saying
+
+ # $INCLUDE trigger.conf
+
+That will enable the triggers.
+
+
+More Documentation
+------------------
+
+See raddb/trigger.conf for complete documentation.
diff --git a/doc/configuration/variables.rst b/doc/configuration/variables.rst
new file mode 100644
index 0000000..4a2f28c
--- /dev/null
+++ b/doc/configuration/variables.rst
@@ -0,0 +1,151 @@
+Run-time variables
+==================
+
+See "man unlang" for more complete documentation on the run-time
+variables. This file is here only for historical purposes.
+
+The above variable expansions also support the following
+meta-attributes. These are not normal RADIUS attributes, but are
+created by the server to be used like them, for ease of use. They can
+only be queried, and cannot be assigned.
+
++-----------------------+-------------------------------------------------+
+| Packet-Type | RADIUS packet type (Access-Request, etc.) |
++-----------------------+-------------------------------------------------+
+| Packet-Src-IP-Address | IP address from which the packet was sent |
++-----------------------+-------------------------------------------------+
+| Packet-Dst-IP-Address | IP address to which the packet was sent. |
+| | This may be "0.0.0.0", if the server |
+| | was configured with ``bind_address = *``. |
++-----------------------+-------------------------------------------------+
+| Packet-Src-Port | UDP port from which the packet was sent |
++-----------------------+-------------------------------------------------+
+| Packet-Dst-Port | UDP port to which the packet was sent. |
++-----------------------+-------------------------------------------------+
+
+``%{config:section.subsection.item}``
+ Corresponding value in ``radiusd.conf`` for the string value of that item.
+
+The ``%{config:...}`` variables should be used VERY carefully, as they
+may leak secret information from your RADIUS server, if you use them
+in reply attributes to the NAS!
+
+::
+
+ DEFAULT User-Name =~ "^([^@]+)@(.*)"
+ All-That-Matched = `%{0}`
+ Just-The-User-Name = `%{1}`
+ Just-The-Realm-Name = `%{2}`
+
+
+The variables are used in dynamically translated strings. Most of the
+configuration entries in ``radiusd.conf`` (and related files) will do
+dynamic string translation. To do the same dynamic translation in a
+RADIUS attribute (when pulling it from a database, or "users" file),
+you must put the string into an back-quoted string:
+
+::
+
+ Session-Timeout = `%{expr: 2 + 3}`
+
+To do the dynamic translation in the ``radiusd.conf`` (or some other
+configuration files), just use the variable as-is. See
+``radiusd.conf`` for examples.
+
+
+Attributes as environment variables in executed programs
+--------------------------------------------------------
+
+When calling an external program (e.g. from ``rlm_exec`` module), these
+variables can be passed on the command line to the program. In
+addition, the server places all of the attributes in the RADIUS
+request into environment variables for the external program. The
+variables are renamed under the following rules:
+
+ #. All letters are made upper-case.
+ #. All hyphens '-' are turned into underscores '_'
+
+so the attribute ``User-Name`` can be passed on the command line to the
+program as ``%{User-Name}``, or used inside the program as the environment
+variable ``USER_NAME`` (or ``$USER_NAME`` for shell scripts).
+
+If you want to see the list of all of the variables, try adding a line
+``printenv > /tmp/exec-program-wait`` to the script. Then look in the
+file for a complete list of variables.
+
+One-character variables
+-----------------------
+
+The following one-character variables were defined. They were duplicates of the
+previous general cases, and were only provided for backwards compatibility.
+They are in the process of being removed, this table documents the old variables
+and their new equivalents.
+(i.e. ``:-``, as described above.
+
++-----------+---------------------------+-----------------------+
+| Variable | Description | Proper Equivalent |
++===========+===========================+=======================+
+|%a |Protocol (SLIP/PPP) |%{Framed-Protocol} |
++-----------+---------------------------+-----------------------+
+|%c |Callback-Number |%{Callback-Number} |
++-----------+---------------------------+-----------------------+
+|%d |request day (DD) | |
++-----------+---------------------------+-----------------------+
+|%f |Framed IP address |%{Framed-IP-Address} |
++-----------+---------------------------+-----------------------+
+|%i |Calling Station ID |%{Calling-Station-Id} |
++-----------+---------------------------+-----------------------+
+|%l |request timestamp | |
++-----------+---------------------------+-----------------------+
+|%m |request month (MM) | |
++-----------+---------------------------+-----------------------+
+|%n |NAS IP address |%{NAS-IP-Address} |
++-----------+---------------------------+-----------------------+
+|%p |Port number |%{NAS-Port} |
++-----------+---------------------------+-----------------------+
+|%s |Speed (PW_CONNECT_INFO) |%{Connect-Info} |
++-----------+---------------------------+-----------------------+
+|%t |request in ctime format | |
++-----------+---------------------------+-----------------------+
+|%u |User name |%{User-Name} |
++-----------+---------------------------+-----------------------+
+|%A |radacct_dir |%{config:radacctdir} |
++-----------+---------------------------+-----------------------+
+|%C |clientname | |
++-----------+---------------------------+-----------------------+
+|%D |request date (YYYYMMDD) | |
++-----------+---------------------------+-----------------------+
+|%G |request minute | |
++-----------+---------------------------+-----------------------+
+|%H |request hour | |
++-----------+---------------------------+-----------------------+
+|%I |request ID | |
++-----------+---------------------------+-----------------------+
+|%L |radlog_dir |%{config:logdir} |
++-----------+---------------------------+-----------------------+
+|%M |MTU |%{Framed-MTU} |
++-----------+---------------------------+-----------------------+
+|%R |radius_dir |%{config:raddbdir} |
++-----------+---------------------------+-----------------------+
+|%S |request timestamp | |
+| |in SQL format | |
++-----------+---------------------------+-----------------------+
+|%T |request timestamp | |
+| |in database format | |
++-----------+---------------------------+-----------------------+
+|%U |Stripped User name |%{Stripped-User-Name} |
++-----------+---------------------------+-----------------------+
+|%V |Request-Authenticator | |
+| |(Verified/None) | |
++-----------+---------------------------+-----------------------+
+|%v |Server Version | |
++-----------+---------------------------+-----------------------+
+|%Y |request year (YYYY) | |
++-----------+---------------------------+-----------------------+
+|%Z |All request attributes | |
+| |except password | |
+| |(must have a big buffer) | |
++-----------+---------------------------+-----------------------+
+
+
+ $Id$
diff --git a/doc/deployment/CYGWIN.rst b/doc/deployment/CYGWIN.rst
new file mode 100644
index 0000000..da61d49
--- /dev/null
+++ b/doc/deployment/CYGWIN.rst
@@ -0,0 +1,283 @@
+FreeRADIUS for EAP under CygWin
+===============================
+
+From: "Philip Blow" <philipb@simplywireless.com.au>
+To: <freeradius-users@lists.cistron.nl>
+Date: Wed, 29 Jan 2003 15:23:45 +1100
+
+Here are some brief notes I but together for compiling FreeRADIUS 0.8.1
+on Windows XP with EAP/TLS support.
+
+Configuring FreeRADIUS for EAP under CygWin.
+--------------------------------------------
+
+#. Installing CygWin
+
+ Install the latest version of CygWin (at time of writing 1.3.19-1) from http://www.cygwin.com
+
+#. Install the following packages (make as minimum list)
+
+ +--------------------+-----------------+
+ | Package | Version |
+ +====================+=================+
+ | _update-info-dir | 00126-1 |
+ +--------------------+-----------------+
+ | ash | 20020731-1 |
+ +--------------------+-----------------+
+ | autoconf | 2.54-1 |
+ +--------------------+-----------------+
+ | autoconf-devel | 2.57-1 |
+ +--------------------+-----------------+
+ | autoconf-stable | 2.13-4 |
+ +--------------------+-----------------+
+ | automake | 1.7.1-1 |
+ +--------------------+-----------------+
+ | automake-devel | 1.7.2-1 |
+ +--------------------+-----------------+
+ | automake-stable | 1.4p5-5 |
+ +--------------------+-----------------+
+ | base-files | 1.1-1 |
+ +--------------------+-----------------+
+ | base-passwd | 1.0-1 |
+ +--------------------+-----------------+
+ | bash | 2.05b-8 |
+ +--------------------+-----------------+
+ | bc | 1.06-1 |
+ +--------------------+-----------------+
+ | binutils | 20021117-1 |
+ +--------------------+-----------------+
+ | byacc | 1.9-1 |
+ +--------------------+-----------------+
+ | bzip2 | 1.0.2-2 |
+ +--------------------+-----------------+
+ | crypt | 1.0-1 |
+ +--------------------+-----------------+
+ | cygrunsrv | 0.95-1 |
+ +--------------------+-----------------+
+ | cygutils | 1.1.3-1 |
+ +--------------------+-----------------+
+ | cygwin | 1.3.19-1 |
+ +--------------------+-----------------+
+ | cygwin-doc | 1.3-2 |
+ +--------------------+-----------------+
+ | diff | 1.0-1 |
+ +--------------------+-----------------+
+ | diffutils | 2.8.1-1 |
+ +--------------------+-----------------+
+ | ed | 0.2-1 |
+ +--------------------+-----------------+
+ | file | 3.37-1 |
+ +--------------------+-----------------+
+ | fileutils | 4.1-1 |
+ +--------------------+-----------------+
+ | findutils | 4.1.7-4 |
+ +--------------------+-----------------+
+ | gawk | 3.1.1-5 |
+ +--------------------+-----------------+
+ | gcc | 3.2-3 |
+ +--------------------+-----------------+
+ | gcc-mingw | 20020817-5 |
+ +--------------------+-----------------+
+ | gcc2 | 2.95.3-10 |
+ +--------------------+-----------------+
+ | gdb | 20021218-1 |
+ +--------------------+-----------------+
+ | gdbm | 1.8.0-4 |
+ +--------------------+-----------------+
+ | gettext | 0.11.5-1 |
+ +--------------------+-----------------+
+ | grep | 2.5-1 |
+ +--------------------+-----------------+
+ | groff | 1.18.1-2 |
+ +--------------------+-----------------+
+ | gzip | 1.3.3-4 |
+ +--------------------+-----------------+
+ | inetutils | 1.3.2-20 |
+ +--------------------+-----------------+
+ | initscripts | 0.9-1 |
+ +--------------------+-----------------+
+ | less | 378-1 |
+ +--------------------+-----------------+
+ | libbz2_0 | 1.0.2-1 |
+ +--------------------+-----------------+
+ | libbz2_1 | 1.0.2-2 |
+ +--------------------+-----------------+
+ | libiconv2 | 1.8-2 |
+ +--------------------+-----------------+
+ | libintl | 0.10.38-3 |
+ +--------------------+-----------------+
+ | libintl1 | 0.10.40-1 |
+ +--------------------+-----------------+
+ | libintl2 | 0.11.5-1 |
+ +--------------------+-----------------+
+ | libltdl3 | 20030103-1 |
+ +--------------------+-----------------+
+ | libncurses5 | 5.2-1 |
+ +--------------------+-----------------+
+ | libncurses6 | 5.2-8 |
+ +--------------------+-----------------+
+ | libpng10 | 1.0.14-2 |
+ +--------------------+-----------------+
+ | libpng12 | 1.2.4-2 |
+ +--------------------+-----------------+
+ | libpopt0 | 1.6.4-4 |
+ +--------------------+-----------------+
+ | libreadline4 | 4.1-2 |
+ +--------------------+-----------------+
+ | libreadline5 | 4.3-2 |
+ +--------------------+-----------------+
+ | libtool | 20020202a-1 |
+ +--------------------+-----------------+
+ | libtool-devel | 20021227-1 |
+ +--------------------+-----------------+
+ | libtool-stable | 1.4.2-2 |
+ +--------------------+-----------------+
+ | libxml2 | 2.4.23-1 |
+ +--------------------+-----------------+
+ | login | 1.7-1 |
+ +--------------------+-----------------+
+ | m4 | 1.4-1 |
+ +--------------------+-----------------+
+ | make | 3.79.1-7 |
+ +--------------------+-----------------+
+ | man | 1.5j-1 |
+ +--------------------+-----------------+
+ | mingw-runtime | 2.3-1 |
+ +--------------------+-----------------+
+ | mktemp | 1.4-1 |
+ +--------------------+-----------------+
+ | more | 2.11o-1 |
+ +--------------------+-----------------+
+ | nasm | 0.98.35-1 |
+ +--------------------+-----------------+
+ | ncurses | 5.2-8 |
+ +--------------------+-----------------+
+ | newlib-man | 20020801 |
+ +--------------------+-----------------+
+ | openssh | 3.5p1-3 |
+ +--------------------+-----------------+
+ | openssl | 0.9.7-1 |
+ +--------------------+-----------------+
+ | openssl-devel | 0.9.7-1 |
+ +--------------------+-----------------+
+ | openssl096 | 0.9.6h-1 |
+ +--------------------+-----------------+
+ | patch | 2.5.8-2 |
+ +--------------------+-----------------+
+ | pcre | 3.7-1 |
+ +--------------------+-----------------+
+ | perl | 5.6.1-2 |
+ +--------------------+-----------------+
+ | readline | 4.3-2 |
+ +--------------------+-----------------+
+ | sed | 4.0.5-1 |
+ +--------------------+-----------------+
+ | sh-utils | 2.0.15-3 |
+ +--------------------+-----------------+
+ | sharutils | 4.2.1-2 |
+ +--------------------+-----------------+
+ | sysvinit | 2.84-3 |
+ +--------------------+-----------------+
+ | tar | 1.13.25-1 |
+ +--------------------+-----------------+
+ | tcltk | 20021218-1 |
+ +--------------------+-----------------+
+ | termcap | 20020930-1 |
+ +--------------------+-----------------+
+ | terminfo | 5.2-3 |
+ +--------------------+-----------------+
+ | texinfo | 4.2-4 |
+ +--------------------+-----------------+
+ | textutils | 2.0.21-1 |
+ +--------------------+-----------------+
+ | tiff | 3.5.7-1 |
+ +--------------------+-----------------+
+ | time | 1.7-1 |
+ +--------------------+-----------------+
+ | unzip | 5.50-1 |
+ +--------------------+-----------------+
+ | vim | 6.1-2 |
+ +--------------------+-----------------+
+ | w32api | 2.1-1 |
+ +--------------------+-----------------+
+ | wget | 1.8.2-2 |
+ +--------------------+-----------------+
+ | which | 1.5-1 |
+ +--------------------+-----------------+
+ | xinetd | 2.3.9-1 |
+ +--------------------+-----------------+
+ | zip | 2.3-2 |
+ +--------------------+-----------------+
+ | zlib | 1.1.4-1 |
+ +--------------------+-----------------+
+
+#. Download
+
+ Download the FreeRADIUS source code from http://www.freeradius.org/
+
+#. Expand the FreeRADIUS source file.
+
+#. Make the following changes to the source code
+ (the diffs are reversed)
+
+ ::
+
+ src/main/Makefile.in
+
+ 145,148c145,148
+ < $(LIBTOOL) --mode=install $(INSTALL) -m 755 $(INSTALLSTRIP)
+ radiusd.exe $(R)$(sbindir)
+ < $(INSTALL) -m 755 $(INSTALLSTRIP) radwho.exe
+ $(R)$(bindir)
+ < $(INSTALL) -m 755 $(INSTALLSTRIP) raduse.exe
+ $(R)$(bindir)
+ < $(INSTALL) -m 755 $(INSTALLSTRIP) radzap.exe
+ $(R)$(bindir)
+ ---
+ > $(LIBTOOL) --mode=install $(INSTALL) -m 755 $(INSTALLSTRIP)
+ radiusd $(R)$(sbindir)
+ > $(INSTALL) -m 755 $(INSTALLSTRIP) radwho
+ $(R)$(bindir)
+ > $(INSTALL) -m 755 $(INSTALLSTRIP) raduse
+ $(R)$(bindir)
+ > $(INSTALL) -m 755 $(INSTALLSTRIP) radzap
+ $(R)$(bindir)
+ 150,151c150,151
+ < $(INSTALL) -m 755 radclient.exe $(R)$(bindir)
+ < $(INSTALL) -m 755 radrelay.exe $(R)$(bindir)
+ ---
+ > $(INSTALL) -m 755 radclient $(R)$(bindir)
+ > $(INSTALL) -m 755 radrelay $(R)$(bindir)
+
+ src/modules/rlm_dbm/Makefile.in
+
+ 22,23c22,23
+ < $(INSTALL) -m 755 $(INSTALLSTRIP) rlm_dbm_parser.exe
+ $(R)$(bindir)
+ < $(INSTALL) -m 755 $(INSTALLSTRIP) rlm_dbm_cat.exe
+ $(R)$(bindir)
+ ---
+ > $(INSTALL) -m 755 $(INSTALLSTRIP) rlm_dbm_parser $(R)$(bindir)
+ > $(INSTALL) -m 755 $(INSTALLSTRIP) rlm_dbm_cat $(R)$(bindir)
+
+ src/modules/rlm_mschap/Makefile
+
+ 20c20
+ < $(INSTALL) -m 755 $(INSTALLSTRIP) smbencrypt.exe $(R)$(bindir)
+ ---
+ > $(INSTALL) -m 755 $(INSTALLSTRIP) smbencrypt $(R)$(bindir)
+
+#. Run configure with the following command line
+
+ ::
+
+ ./configure -without-snmp -disable-shared -enable-static
+
+#. Execute make and then make install
+
+::
+
+ Philip Blow
+ Senior Technical Manager
+ Simply Wireless
+ philipb@simplywireless.com.au
diff --git a/doc/deployment/MACOSX b/doc/deployment/MACOSX
new file mode 100644
index 0000000..39ebaec
--- /dev/null
+++ b/doc/deployment/MACOSX
@@ -0,0 +1,12 @@
+ Installing FreeRADIUS on MAC OSX
+ --------------------------------
+
+1) download, unzip and untar freeradius.tar.gz
+
+2) $ ./configure
+
+3) $ make
+
+4) $ make install
+
+It's what the developers use, so we make sure it works.
diff --git a/doc/deployment/OS2 b/doc/deployment/OS2
new file mode 100644
index 0000000..fc676c9
--- /dev/null
+++ b/doc/deployment/OS2
@@ -0,0 +1,22 @@
+Compiling FreeRADIUS under OS/2
+
+To compile FreeRADIUS unde OS/2 you must have a full EMX environment with GNU
+utilities (like make,sh)
+
+The EMX can be get from http://hobbes.nmsu.edu
+
+To work with CVS repository you must install cvs110.zip from hobbes also
+
+before entering in sh.exe you must do
+SET SHELL=sh.exe
+
+before running ./configure you must set the shell the variables :
+export CC=gcc
+export MAKE=fullpathofyourmake.exe
+export PERL=fullpathofyourperl.exe
+
+
+The OS/2 version of FreeRADIUS can't directly execute checkrad.pl then the
+program will execute a checkrad.cmd
+
+
diff --git a/doc/deployment/performance-testing b/doc/deployment/performance-testing
new file mode 100644
index 0000000..71945c1
--- /dev/null
+++ b/doc/deployment/performance-testing
@@ -0,0 +1,168 @@
+
+Radius Test Procedures
+
+0. INTRODUCTION
+
+This document describes how to test your radius server authentication
+using random usernames and passwords with the 'radclient' program.
+
+1. WHY TEST
+
+Many people want to see the difference in efficiency behind the various
+authentication methods, compilation methods, etc of their radius server.
+Before now, this was difficult to do efficiently across a large number
+of users. However, with this document, you'll be able to test your
+radius server and determine the best options to use for your system.
+
+2. GETTING STARTED
+
+First thing we have to do is generate a large number of users. You'll
+want to do this even if you have a large passwd file you want to use
+from your system, because the create user script sets up other files
+you need for testing. So head to the scripts/ directory, and do this:
+
+Make a tmp dir
+# mkdir tmp
+# cp create-users.pl tmp
+# cd tmp
+
+Run the script to create 10,000 (or however many you want) random users
+and passwords
+# ./create-users.pl 10000
+
+Output from the script will include several files:
+ passwd : A standard passwd file you can append to /etc/passwd
+ shadow : A standard shadow file you can append to /etc/shadow
+passwd.nocrypt : A file with *unencrypted* users & passes in form "user:pass"
+ radius.test : File you'll use as input for radclient
+ radius.users : A standard radius 'users' file
+
+So, equipped with lots of users and passwords, there's several methods of
+authentication you can test:
+
+ o System users (Auth-Type:=System)
+ o Local users (Auth-Type:=Local)
+ o Cached system (passwd) users
+ o Others
+
+NOTE: Before moving on, you will probably want to add '/dev/null' to
+/etc/shells *temporarily* so that default system authentication will
+work. REMEMBER TO TAKE IT OUT!
+
+3. TEST PROCEDURES
+
+ A. System (/etc/passwd) users testing
+
+ 1. Append the 'passwd' file from create-users.pl onto your
+ system passwd file:
+
+ # cat ./passwd >> /etc/passwd
+
+ 2. If you have shadow, append the shadow file onto /etc/shadow
+
+ # cat ./shadow >> /etc/shadow
+
+ 3. Make sure you have a DEFAULT user similar to the following
+ in your radius 'users' file:
+
+ DEFAULT Auth-Type:=System
+ Reply-Message = "Success!"
+
+ 4. Start radiusd
+
+ # /usr/local/sbin/radiusd
+
+ 5. Run radclient with 'radius.test' as the input file.
+
+ NOTE: First you need to setup a secret for your local
+ machine in the 'clients' file and use that secret below
+
+ # time /usr/local/bin/radclient -q -s -f radius.test \
+ <yourhostname> auth <secret>
+
+ NOTE: The above is to be put all on one line.
+
+ NOTE: Some systems do not have the 'time' command,
+ so you may need to break out the stopwatch instead :)
+
+ Take note of the output of radclient. If there were lots of
+ failures, something is wrong. All authentications should
+ succeed.
+
+ 6. Take note of the output from the above 'time' command.
+ The output format should be something similar to the
+ following (on linux, this for example only!):
+
+ 1.72user 0.53system 5:11.34elapsed 0%CPU
+ (0avgtext+0avgdata 0maxresident)k 0inputs+0outputs
+ (340major+29minor)pagefaults 0swaps
+
+ This means it took 5:11 (311 seconds) to authenticate
+ 10,000 users. Simple division tells us this is:
+
+ 10,000 auths / 311 seconds = 32.1543 auths/second
+
+ B. Local users testing
+
+ 1. Copy the 'radius.users' file from the script over your 'users'
+ file. Make sure you do NOT have a DEFAULT entry or you will
+ invalidate this test.
+
+ 2. Restart radiusd (kill and restart)
+
+ 3. Run radclient (See A-5 above for NOTES on this):
+
+ # time /usr/local/bin/radclient -q -s -f radius.test \
+ <yourhostname> auth <secret>
+
+ 4. Take note of the output from the above 'time' command, and
+ divide the number of auths (10,000 in this case) with the
+ number of seconds it took to complete. See A6 above for
+ more info.
+
+ C. Cached system users
+
+ 1. Set 'cache=yes' in your radiusd.conf file
+
+ 2. Restart radiusd (ie, kill it and restart, not just a HUP)
+
+ 3. Perform the same steps outlined above for testing System users (A)
+
+ D. Other methods
+
+ There is no reason why you can't use some of this to test modules
+ for PAM, SQL, LDAP, etc, but that will require a little extra
+ work on your end (ie, getting the users/passes you generated into
+ the corresponding database). However, by now you should have a
+ good idea of how to test once you do that.
+
+ Also, play around with compile options like --with-thread,
+ --with-thread-pool, etc. Run radiusd with '-s' so it runs
+ one process only, etc etc. Play around with it.
+
+4. CAVEATS
+
+The above test procedures make no allowances for users that login with
+incorrect usernames or passwords. If you want a true test of performance,
+you should add in lots of bad usernames and passwords to the radius.test
+file and then re-run 'radclient' with that file as input.
+
+Additionally, these tests make no reference to how the pre-authenticate,
+post-authenticate, and accounting methods you choose could affect server
+performance. For example, checking for simultaneous use after authenti-
+cating the user is obviously going to slow down authenticate performance.
+
+The numbers you get from this test are raw authentications/second in a
+perfect environment. Do not expect this kind of result in the real world.
+However, having tested in this manner, you will have a good idea of which
+authentication methods and compilation options give you the best base to
+start from, which is key to an efficient server.
+
+5. RESULTS
+
+I'd really rather not post results because they will vary tremendously
+with other system-specific configuration. This is exactly the reason
+you should run tests of this nature, to find what's best for *your*
+system. Good luck!
+
+
diff --git a/doc/deployment/supervise-radiusd.rst b/doc/deployment/supervise-radiusd.rst
new file mode 100644
index 0000000..e4922ed
--- /dev/null
+++ b/doc/deployment/supervise-radiusd.rst
@@ -0,0 +1,163 @@
+
+Supervising the Radiusd Daemon
+==============================
+
+Introduction
+------------
+
+We all hope that our radius daemons won't die in the middle of the
+nite stranding customer and beeping beepers. But, alas, it's going to
+happen, and when you least expect it. That's why you want a another
+process watching your radius daemon, restarting it if and when it
+dies.
+
+This text describes how to setup both the free radius daemon so that
+it is automatically restarted if the process quits unexpectedly. To
+do this, we'll use either Dan Bernstein's 'daemontools' package or the
+inittab file. Note: The radwatch script that used to be part of this
+distribution, is depreciated and SHOULD NOT BE USED.
+
+Setting Up Daemontools
+----------------------
+
+First, download (and install) daemontools from:
+
+ http://cr.yp.to/daemontools.html
+
+The latest version as of this writing is 0.70. It would be well worth
+your while to read all the documentation at that site too, as you can
+do much more with daemontools than I describe here.
+
+Next, we'll need a directory for the radius 'service' to use with
+daemontools. I usually create a dir '/var/svc' to hold all my
+daemontool supervised services. i.e.::
+
+ $ mkdir /var/svc
+ $ mkdir /var/svc/radiusd
+
+Now we just need a short shell script called 'run' in our new service
+directory that will start our daemon. The following should get you
+started::
+
+ #!/bin/sh
+ # Save as /var/svc/radiusd/run
+ exec /usr/local/sbin/radiusd -s -f
+
+Of course you'll want to make that 'run' file executable::
+
+ $ chmod +x /var/svc/radiusd/run
+
+Note, you *MUST* use the '-f' option when supervising. That option
+tells radiusd not to detach from the tty when starting. If you don't
+use that option, the daemontools will always think that radiusd has
+just died and will (try to) restart it. Not good.
+
+Now the only left to do is to start the 'supervise' command that came
+with daemontools. Do that like so::
+
+ $ supervise /var/svc/radiusd
+
+Maintenance With Daemontools
+----------------------------
+
+ Any maintenance you need to do with almost certainly be done with the
+ 'svc' program in the deamontools package. i.e.::
+
+ Shutdown radiusd:
+ $ svc -d /var/svc/radiusd
+
+ Start it back up:
+ $ svc -u /var/svc/radiusd
+
+ Send HUP to radiusd:
+ $ svc -h /var/svc/radiusd
+
+ Shutdown and stop supervising radiusd:
+ $ svc -dx /var/svc/radiusd
+
+Supervising With Inittab
+------------------------
+
+This is really pretty easy, but it is system dependent. I strongly
+suggest you read the man pages for your 'init' before playing with
+this. You can seriously hose your system if you screw up your
+inittab.
+
+Add this line (or something similar to it) to your inittab::
+
+ fr:23:respawn:/usr/local/sbin/radiusd -f -s &> /dev/null
+
+Now all that's left is to have the system reread the inittab. Usually
+that's done with one of the following::
+
+ $ telinit Q
+
+or::
+
+ $ init q
+
+Now you should see a 'radiusd' process when you issue a 'ps'. If you
+don't, try to run the radiusd command you put in inittab manually. If
+it works, that means you didn't tell the system to reread inittab
+properly. If it doesn't work, that means your radius start command is
+bad and you need to fix it.
+
+Acknowledgements
+----------------
+
+ Document author : Jeff Carneal
+ daemontools auther : Dan Bernstein
+ Further daemontool notes (below): Antonio Dias
+ Radwatch note : Andrey Melnikov
+
+Further Daemontools notes
+=========================
+
+Here are some notes by Antonia Dias sent to the free radius mailing
+list. Some of you may find this useful after reading the above and the
+docs for daemontools.
+
+Daemontools Instructions
+------------------------
+
+I am running radiusd under supervise from daemontools without
+problems. The only thing I am missing right now is an option to force
+radiusd to send log to stderr so I can manage logs better with
+multilog (also included in daemontools package). Here is the procedure
+I've been following (for Cistron RADIUS)::
+
+ $ groupadd log
+ $ useradd -g log log
+ $ mkdir /etc/radiusd
+ $ mkdir /etc/radiusd/log
+ $ mkdir /etc/radiusd/log/main
+ $ chmod +t+s /etc/radiusd /etc/radiusd/log
+ $ chown log.log /etc/radiusd/log/main
+
+Here are the contents of run files from '/etc/radiusd' and '/etc/radiusd/log'::
+
+ $ cd /etc/radiusd
+ $ cat run
+ #!/bin/sh
+ exec 2>&1
+ exec /usr/sbin/radiusd -fyzx
+ $ cd /etc/radiusd/log
+ $ cat run
+ #!/bin/sh
+ exec setuidgid log multilog t ./main
+
+ To make service wake-up do::
+
+ $ ln -sf /etc/radiusd /service
+
+ Hang-up (to reload config) it using::
+
+ $ svc -h /service/radiusd
+
+Disable (down) it using::
+
+ $ svc -d /service/radiusd
+
+Reenable (up) it using::
+
+ $ svc -u /service/radiusd
diff --git a/doc/deployment/tuning_guide b/doc/deployment/tuning_guide
new file mode 100644
index 0000000..264749f
--- /dev/null
+++ b/doc/deployment/tuning_guide
@@ -0,0 +1,58 @@
+------------ MAIN SERVER -------------
+o If you have a large user base and/or many authentication requests try
+ using a scalable authentication mechanism like ldap or sql.
+o Enable noatime on all the freeradius log files or better yet on the
+ freeradius log directory.
+o Always use the latest cvs version. It will probably contain a few
+ fixes and enhancements.
+o Always try to use the least modules possible. In particular if you
+ can avoid it do not use the detail and radwtmp (files) modules.
+ They will slow down your accounting.
+o Use the users file to only set default profiles. Do not place any
+ users there. Keep it as small as possible. Always set default
+ attributes in the users file and don't fill the user entries in
+ ldap/sql with default values. In general the ldap/sql user profiles
+ should contain user attributes only in special user cases.
+o Tune thread pool parameters to match your size requirements.
+ Set max_requests_per_server to zero to avoid server thread restarts.
+o Enlarge the timeout (10 secs) and retries (5-7) in the access servers
+ for accounting. That way you won't lose any accounting information.
+o Use well tuned Fast Ethernet connections to minimize latency.
+o freeradius is multi threaded and i/o bound. That means you should use
+ the latest OS kernels/patches for improved multi processor and
+ network performance.
+
+------------ LDAP MODULE -------------
+o Try to maximize caching in the ldap server. In particular *always*
+ enable indexing of the uid attribute (equality index) and the
+ cn attribute (equality index - the cn attribute is used to search
+ for groups). Make the ldap server entry/directory cache memory sizes
+ as large as possible. In general try allocating as much memory as you
+ can afford to your ldap server.
+o Put default profiles in ldap. User entries should only contain
+ non standard values in order to remain small and maximize the gains
+ of caching the user default/regular profiles.
+o Enable group caching in groups.
+
+------------ SQL MODULE --------------
+o Use the sql module in the session section instead of the radutmp module.
+ It works *much* quicker.
+o Create a multi column index for the (UserName,AcctStopTime) attributes especially
+ if you are using sql for double login detection.
+o If you are using mysql and you do a lot of accounting try using InnoDB for the radacct
+ table instead of MyISAM (this should be the default in all schemas)
+o Add AcctUniqueId in the accounting_stop query. Especially if you have a lot of access
+ servers or your NAS does not send very random Session-Ids. That way you will always have
+ one candidate row to search for, instead of all the rows that have the same AcctSessionId
+
+------------ COUNTER MODULE ----------
+o Enable noatime on the counter db files.
+o Tune the cache_size configuration directive to match your needs.
+ The cache size should be set to 2-3 * number of available nas ports.
+o Keep the database in a memory mapped file if you can help. Backup the
+ file every 10 mins to the disk and copy it to the memory mapped one
+ on server startup.
+
+------------ RADUTMP MODULE ----------
+o Enable noatime on the radutmp file
+o Don't use it
diff --git a/doc/developer/autotools.md b/doc/developer/autotools.md
new file mode 100644
index 0000000..a7ad6a8
--- /dev/null
+++ b/doc/developer/autotools.md
@@ -0,0 +1,179 @@
+FreeRADIUS use of GNU autotools
+===============================
+
+The full autotools suite includes many utilities, which we do not
+need or want to use. Especially libtool, for which we use the
+faster replacement, jlibtool.
+
+In a normal autotools setup, one would run "autoreconf" to rebuild
+all of the configure scripts, which will perform at least the
+following tasks:
+
+ - aclocal
+ - autoconf
+ - autoheader
+ - automake
+ - libtoolize
+
+Specifically, all we really want to run is `autoconf`, to rebuild
+the configure scripts.
+
+We have a more complicated setup than most. There is normally just
+one `configure` script, in the top-level directory. In FreeRADIUS
+there are also configure scripts in most RLM module directories as
+well. Autotools is not really set up to handle this well,
+preferring to treat every sub-directory as a separate project.
+
+This means that e.g. cache files are not shared, and include files
+(for configure macros) are not found as they are expected to be in
+the current directory.
+
+What's more, autoconf macros can be found in multiple places - the
+automake install directory, the system aclocal directory, and in
+multiple places in the FreeRADIUS source (mainly `m4/`, but also
+`acinclude.m4`, both potentially in multiple places).
+
+In our setup we want to run the following only:
+
+ - autoconf, to generate configure files and `all.mk` make files.
+ - autoheader, to generate header files.
+
+
+autoconf
+--------
+
+`autoconf` expands a `configure.ac` file to create a `configure`
+script, with optionally also a Makefile. We generate a makefile
+called `all.mk` to work with the boilermake system.
+
+Being based on m4, autoconf needs to find macro definitions from
+somewhere, which will be expanded as needed upon invocation.
+autoconf has several search paths for macros, including some
+system paths for its own internal macros.
+
+Notably within the project, autoconf looks in `aclocal.m4` to find
+"local" macros to add. These days, `aclocal.m4` is supposed to be
+written by the `aclocal` script, so autotools added the concept of
+`acinclude.m4` to put local macros. `aclocal` will add an include
+directive at the bottom of `aclocal.m4` to include the
+`acinclude.m4` file, if it is found in the current directory.
+
+When `aclocal` is run it will scan `configure.ac` for anything
+that looks like a macro to expand. It will then search project
+directories, the automake system directory and the aclocal system
+directory, to find any macros that match. These are copied into
+the `aclocal.m4` file. `autoconf` will then pick up these macro
+definitions and use them when expanding `configure.ac`. Notably,
+macros can be in `*.m4` files in given search directories and
+`aclocal` will extract the macros and copy them over.
+
+`autoconf` itself will not look in `*.m4` files, only in
+`aclocal.m4` and, if that is not found, `acinclude.m4`.
+
+We therefore have, _within one level directory_:
+
+ - `acinclude.m4`, local macro definitions;
+ - `aclocal.m4`, macros collated by `aclocal`;
+ - `m4/` or other directories, macro files searched by `aclocal`;
+ - `configure.ac` the input configure script;
+ - `all.mk`, `configure`, etc as outputs from `autoconf`.
+
+The GNU Autotools manual these days recommends splitting macros
+up, one file per macro, and putting them in the `m4/` directory
+rather than in the `acinclude.m4` file. This makes them much
+easier to maintain.
+
+
+FreeRADIUS sub-directories
+--------------------------
+
+All the above is not too much of an issue for the top-level
+configure script. We can have an automatically generated
+`aclocal.m4` file, macros in `m4/` and extra components in
+`acinclude.m4` if needed. However, the sub-directory configure
+scripts really want to be kept as small as possible. There is no
+real need for a separate `aclocal.m4` file if all of the configure
+scripts could be scanned together. The top-level `m4/` directory and
+`acinclude.m4` file can be used.
+
+Unfortunately, autotools doesn't like to work like this. It wants
+all files to be in one directory, and `aclocal` won't scan more
+than one `configure.ac` file.
+
+The two compromise solutions seem to be:
+
+ - Don't use `aclocal`.
+
+ - Nearly all local macros are put in the top-level
+ `acinclude.m4` file.
+ - A few local macros can go in `m4/`, but they have to
+ explicitly included in configure.ac scripts with
+ `m4_include()`.
+ - `autoconf` has to be run with multiple `-I` include args to
+ capture all the places where macros could be.
+ - Any missing macros won't get pulled in from system
+ locations, because `aclocal` noramally does that.
+ - Sub-directories are relatively clean, e.g. no `aclocal.m4`
+ or `acinclude.m4` files all over the place.
+
+ - Use `aclocal`.
+
+ - The `-I` arg can be passed to `aclocal` which makes it
+ search multiple project directories for local macros to copy
+ to `aclocal.m4`.
+ - All directories with a `configure` script must have an
+ `aclocal.m4` file to collate macros from the top-level `m4/`
+ directory.
+ - The top-level `acinclude.m4` file is ignored except in the
+ top-level configure script, meaning it needs to be symlinked
+ or copied everywhere else.
+ - If `autoconf` finds an `aclocal.m4` file it no longer seems
+ to look for macros elsewhere.
+ - Sub-directories get messy with `aclocal.m4` and
+ `acinclude.m4` files, though these don't need to be checked
+ into the repository.
+ - The top-level `m4/` directory can contain all macros as
+ separate files, which is much cleaner than `acinclude.m4`.
+ - System macros will be found and used.
+
+We pretty much need to use `aclocal` - it removes the need for an
+`acinclude.m4` file (tidier), picks up macros from `m4/`
+automatically (tidier), removes the need for `m4_include()` macros
+(tidier), and means that macros will be found that might not be
+shipped in the FreeRADIUS distribution (easier).
+
+That comes with some downsides as above - we will end up with
+`aclocal.m4` files all over the place, and have to handle the case
+where things were originally in `acinclude.m4` and are not macros.
+
+Fixing `aclocal.m4` files can be done by either including them in
+git (unnecessary) or hiding them with `.gitignore` (best).
+
+Picking up non-macro definitions from `acinclude.m4` can be done
+by adding a new macro, `FR_INIT()`, which defines anything needed.
+In fact, as long as that macro is included, the _entire_
+`m4/fr_init.m4` file will be included by `aclocal`. This means the
+extra definition doesn't even need to be inside the macro.
+
+
+Rebuilding the configure scripts
+================================
+
+The normal way to rebuild all of the autotools outputs is to run
+`autoreconf`. This must not be run with FreeRADIUS as it will
+initialise and use libtool and other things we do not want.
+
+Instead, we have a make target to rebuild everything needed.
+
+ make reconfig
+
+This will rebuild any configure files that are out of date.
+However, sometimes everything needs to be forced, e.g. due to some
+macros changing that are missed by the Make dependencies (maybe
+from the system directories). In this case a forced rebuild can be
+undertaken with:
+
+ find . -name configure.ac | xargs touch
+ make reconfig
+
+This will ensure that _all_ configure scripts are rebuilt.
diff --git a/doc/developer/coding-methods.rst b/doc/developer/coding-methods.rst
new file mode 100644
index 0000000..444696d
--- /dev/null
+++ b/doc/developer/coding-methods.rst
@@ -0,0 +1,242 @@
+Helpful coding methods
+======================
+
+The following is a short set of guidelines to follow while
+programming. It does not address coding styles, function naming
+methods, or debugging methods. Rather, it describes the processes
+which SHOULD go on in the programmers mind, while he is programming.
+
+Coding standards apply to function names, the look of the code, and
+coding consistency. Coding methods apply to the daily practices used
+by the programmer to write code.
+
+
+
+1. Comment your code.
+
+ If you don't, you'll be forced to debug it 6 months later, when
+ you have no clue as to what it's doing.
+
+ If someone REALLY hates you, you'll be forced to debug
+ un-commented code that someone else wrote. You don't want to do
+ that.
+
+ For FreeRADIUS use doxygen @style comments so you get the benefits
+ of docs.freeradius.org.
+
+2. Give things reasonable names.
+
+ Variables and functions should have names. Calling them 'x',
+ 'xx', and 'xxx' makes your life hell. Even 'foo' and 'i' are
+ problematic.
+
+ Avoid smurfs. Don't re-use struct names in field names i.e.
+ struct smurf {
+ char *smurf_pappa_smurf;
+ }
+
+ If your code reads as full english sentences, you're doing it
+ right.
+
+
+3. Check input parameters in the functions you write.
+
+ Your function CANNOT do anything right if the user passed in
+ garbage, and you were too lazy to check for garbage input.
+
+ assert() (rad_assert()) is ugly. Use it.
+
+ GIGO is wrong. If your function gets garbage input, it
+ should complain loudly and with great descriptiveness.
+
+
+4. Write useful error messages.
+
+ "Function failed" is useless as an error message. It makes
+ debugging the code impossible without source-level instrumentation.
+
+ If you're going to instrument the code at source level for error
+ messages, leave the error messages there, so the next sucker won't
+ have to do the same work all over again.
+
+
+5. Check error conditions from the functions you call.
+
+ Your function CANNOT do anything right if you called another
+ function, and they gave you garbage output.
+
+ One of the most common mistakes is::
+
+ fp = fopen(...);
+ fgetc(fp); /* core dumps! */
+
+ If the programmer had bothered to check for a NULL fp (error
+ condition), then he could have produced a DESCRIPTIVE error
+ message, instead of having his program core dump.
+
+
+6. Core dumps are for weenies.
+
+ If your program core dumps accidentally, you're a bad programmer.
+ You don't know what your program is doing, or what it's supposed
+ to be doing when anything goes wrong.
+
+ If it hits an assert() and calls abort(), you're a genius. You've
+ thought ahead to what MIGHT go wrong, and put in an assertion to
+ ensure that it fails in a KNOWN MANNER when something DOES go
+ wrong. (As it usually does...)
+
+
+7. Initialize your variables.
+
+ memset() (talloc_zero()) is your friend. 'ptr = NULL' is
+ nice, too.
+
+ Having variables containing garbage values makes it easy for the
+ code to do garbage things. The contents of local variables are
+ inputs to your function. See #3.
+
+ It's also nearly impossible for you to debug any problems, as you
+ can't tell the variables with garbage values from the real ones.
+
+
+8. Don't allow buffer over-runs.
+
+ They're usually accidental, but they cause core dumps.
+ strcpy() and strcat() are ugly. Use them under duress.
+
+ sizeof() is your friend.
+
+
+9. 'const' is your friend.
+
+ If you don't mean to modify an input structure to your function,
+ declare it 'const'. Declare string constants 'const'. It can't
+ hurt, and it allows more errors to be found at compile time.
+
+ Use 'const' everywhere. Once you throw a few into your code, and
+ have it save you from stupid bugs, you'll blindly throw in 'const'
+ everywhere. It's a life-saver.
+
+
+10. Use C compiler warnings.
+
+ Turn on all of the C compiler warnings possible. You might have
+ to turn some off due to broken system header files, though. But
+ the more warnings the merrier.
+
+ Getting error messages at compile time is much preferable to
+ getting core dumps at run time. See #7.
+
+ Notice that the C compiler error messages are helpful? You should
+ write error messages like this, too. See #4.
+
+
+11. Avoid UNIXisms and ASCIIisms and visualisms.
+
+ You don't know under what system someone will try to run your code.
+ Don't demand that others use the same OS or character set as you use.
+
+ Never assign numbers to pointers. If foo is a char*, and you want it
+ to be be null, assign NULL, not 0. The zeroth location is perfectly
+ as addressable as any other on plenty of OSes. Not all the world
+ runs on Unix (though it should :) ).
+
+ Another common mistake is to assume that the zeroth character in the
+ character set is the string terminator. Instead of terminating a
+ string with 0, use '\0', which is always right. Similarly, memset()
+ with the appropriate value: NULL, '\0', or 0 for pointers, chars,
+ and numbers.
+
+ Don't put tabs in string constants, either. Always use '\t' to
+ represent a tab, instead of ASCII 9. Literal tabs are presented to
+ readers of your code as arbitrary whitespace, and it's easy to mess
+ up.
+
+
+12. Make conditionals explicit.
+
+ Though it's legal to test "if (foo){}", if you test against the
+ appropriate value (like NULL or '\0'), your code is prettier and
+ easier for others to read without having to eyeball your prototypes
+ continuously to figure out what you're doing (especially if your
+ variables aren't well-named). See #2.
+
+
+13. Test your code.
+
+ Even Donald Knuth writes buggy code. You'll never find all of the
+ bugs in your code unless you write a test program for it.
+
+ This also means that you'll have to write your code so that it
+ will be easily testable. As a result, it will look better, and be
+ easier to debug.
+
+Hints, Tips, and Tricks
+-----------------------
+
+This section lists many of the common "rules" associated with code
+submitted to the project. There are always exceptions... but you must
+have a really good reason for doing so.
+
+ 1. Read the Documentation and follow the CodingStyle
+
+ The FreeRADIUS server has a common coding style. Use real tabs
+ to indent. There is whitespace in variable assignments.
+ (i = 1, NOT i=1).
+
+ When in doubt, format your code to look the same as code already
+ in the server. If your code deviates too much from the current
+ style, it is likely to be rejected without further review, and
+ without comment.
+
+ 2. #ifdefs are ugly
+
+ Code cluttered with ifdefs is difficult to read and
+ maintain. Don't do it. Instead, put your ifdefs in a header, and
+ conditionally define 'static inline' functions, or macros, which
+ are used in the code. Let the compiler optimize away the "no-op"
+ case.
+
+ Simple example, of poor code::
+
+ #ifdef CONFIG_MY_FUNKINESS
+ init_my_stuff(foo);
+ #endif
+
+ Cleaned-up example:
+
+ (in header)::
+
+ #ifndef CONFIG_MY_FUNKINESS
+ static inline void init_my_stuff(char *foo) {}
+ #endif
+
+ (in the code itself)::
+
+ init_my_stuff(dev);
+
+ 3. 'static inline' is better than a macro
+
+ Static inline functions are greatly preferred over macros. They
+ provide type safety, have no length limitations, no formatting
+ limitations, and under gcc they are as cheap as macros.
+
+ Macros should only be used for cases where a static inline is
+ clearly suboptimal [there a few, isolated cases of this in fast
+ paths], or where it is impossible to use a static inline
+ function [such as string-izing].
+
+ 'static inline' is preferred over 'static __inline__', 'extern
+ inline', and 'extern __inline__'.
+
+ 4. Don't over-design.
+
+ Don't try to anticipate nebulous future cases which may or may
+ not be useful: "Make it as simple as you can, and no simpler"
+
+ Split up functionality as much as possible. If your code needs
+ to do two unrelated things, write two functions. Mashing two
+ kinds of work into one function makes the server difficult to
+ debug and maintain.
+
diff --git a/doc/developer/contributing.rst b/doc/developer/contributing.rst
new file mode 100644
index 0000000..b40f98c
--- /dev/null
+++ b/doc/developer/contributing.rst
@@ -0,0 +1,127 @@
+Submitting patches or diff's to the FreeRADIUS project
+======================================================
+
+For a person or company wishing to submit a change to the FreeRADIUS project
+the process can sometimes be daunting if you're not familiar with "the system."
+This text is a collection of suggestions which can greatly increase the chances
+of your change being accepted.
+
+Note: Only trivial patches will be accepted via email. Large patches, or
+patches that modify a number of files MUST be submitted as a pull-request via
+GitHub.
+
+Hints and tips
+--------------
+
+1. Describe your changes
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Describe the technical detail of the change(s) your patch or commit includes.
+
+Be as specific as possible. The WORST descriptions possible include things like
+"update file X", "bug fix for file X", or "this patch includes updates for
+subsystem X. Please apply."
+
+If your description starts to get long, that's a sign that you probably need to
+split up your commit. See #3, next.
+
+2. Separate your changes
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Separate each logical change into its own commit.
+
+For example, if your changes include both bug fixes and performance
+enhancements for a single module, separate those changes into two or more
+patches.
+
+On the other hand, if you make a single change to numerous files, group those
+changes into a single commit. Thus a single LOGICAL change is contained within
+a single commit.
+
+If one commit depends on another commit in order for a change to be complete,
+that is OK. Simply note "this commit depends on commit X" in the extended
+commit description.
+
+If your commit includes significant whitespace changes these should also be
+broken out into another, separate, commit.
+
+Submitting patches via GitHub
+-----------------------------
+
+See the following links for more details about submitting via github:
+
+- https://help.github.com/articles/fork-a-repo
+- http://wiki.freeradius.org/contributing/GitHub
+
+Submitting patches via email
+----------------------------
+
+1. "diff -u"
+~~~~~~~~~~~~
+Use ``diff -u`` or ``diff -urN`` to create patches.
+
+All changes to the source occur in the form of patches, as generated by
+diff(1). When creating your patch, make sure to create it in "unified diff"
+format, as supplied by the '-u' argument to diff(1). Patches should be based in
+the root source directory, not in any lower subdirectory.
+
+To create a patch for a single file, it is often sufficient to do::
+
+ SRCTREE=/home/user/src/freeradiusd/
+ MYFILE=src/modules/rlm_foo/foo.c
+
+ cd $SRCTREE
+ cp $MYFILE $MYFILE.orig
+ vi $MYFILE # make your change
+ diff -u $MYFILE.orig $MYFILE > /tmp/patch
+
+To create a patch for multiple files, you should unpack a "vanilla", or
+unmodified source tree, and generate a diff against your own source tree. For
+example::
+
+ MYSRC=/home/user/src/freeradiusd-feature/
+
+ gunzip freeradiusd-version.tar.gz
+ tar xvf freeradiusd-version.tar
+ diff -urN freeradiusd-version $MYSRC > ~/feature-version.patch
+
+
+2. Select e-mail destination
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you are on the developers mailing list, send the patch there.
+freeradius-devel@lists.freeradius.org
+
+Otherwise, send the patch to 'patches@freeradius.org'
+
+3. No MIME, no links, no compression, no attachments. Just plain text
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The developers need to be able to read and comment on the changes you are
+submitting. It is important for a developer to be able to "quote" your changes,
+using standard e-mail tools, so that they may comment on specific portions of
+your code.
+
+For this reason, all patches should be submitting e-mail "inline".
+
+Do not attach the patch as a MIME attachment, compressed or not. Many popular
+e-mail applications will not always transmit a MIME attachment as plain text,
+making it impossible to comment on your code. A MIME attachment also takes a
+bit more time to process, decreasing the likelihood of your MIME-attached
+change being accepted.
+
+Compressed patches are generally rejected outright. If the developer has to do
+additional work to read your patch, the odds are that it will be ignored
+completely.
+
+4. E-mail size
+~~~~~~~~~~~~~~
+
+Large changes are not appropriate for mailing lists, and some maintainers. If
+your patch, exceeds 5Kb in size, you must submit the patch via GitHub instead.
+
+5. Name the version of the server
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+It is important to note, either in the subject line or in the patch
+description, the server version to which this patch applies.
diff --git a/doc/developer/module_interface.rst b/doc/developer/module_interface.rst
new file mode 100644
index 0000000..2fc510e
--- /dev/null
+++ b/doc/developer/module_interface.rst
@@ -0,0 +1,186 @@
+
+RLM Module Interface (for developers)
+=====================================
+
+Overview
+--------
+
+Intent of the server
+^^^^^^^^^^^^^^^^^^^^
+
+FreeRADIUS is an authentication server. It does RADIUS authorization,
+authentication, and accounting. It does NOT do database management,
+user configuration updates, or email. All of those functions may be
+more easily (and correctly) performed in programs outside of the
+server.
+
+The only functionality performed by the server is:
+
+- receive a RADIUS request
+ - process the request
+ - look up information one or more databases
+- store information in one or more databases (proxying can be viewed this way)
+- respond to the request
+
+There is no room, or need, for timers, listening on sockets, or
+anything else in the server. Adding those functions to the server
+means that it will become more complex, more unstable, more insecure,
+and more difficult to maintain.
+
+
+Intent of the modules
+^^^^^^^^^^^^^^^^^^^^^
+
+The intent of modules is that they do small, simple, well-defined
+things when RADIUS packets are received. If the module does things
+when RADIUS packets are NOT received, then it has no business being in
+the server. Similarly, the module infrastructure is NOT intended to
+allow servers, applications, timed events, or anything other than
+handling incoming RADIUS packets.
+
+Modules perform an action when RADIUS packets are received. Modules
+which do more (creating threads, forking programs) will NOT be added
+to the server, and the server core will NOT be modified to enable
+these kinds of modules. Those functions more properly belong in a
+separate application.
+
+Modules ARE permitted to open sockets to other network programs, and
+to send and receive data on those sockets. Modules are NOT permitted
+to open sockets, and to listen for requests. Only the server core has
+that functionality, and it only listens for RADIUS requests.
+
+
+Module outline
+^^^^^^^^^^^^^^
+
+The fundamental concepts of the rlm interface are module, instance,
+and component.
+
+A module is a chunk of code that knows how to deal with a particular
+kind of database, or perhaps a collection of similar
+databases. Examples:
+
+- rlm_sql contains code for talking to MySQL or Postgres, and for mapping RADIUS records onto SQL tables
+- rlm_unix contains code for making radiusd fit in well on unix-like systems, including getpw* authentication and utmp/wtmp-style logging.
+
+An instance specifies the actual location of a collection data that
+can be used by a module. Examples:
+
+- /var/log/radutmp
+- "the MySQL database on bigserver.theisp.com.example"
+
+A module can have multiple components which act on
+RADIUS requests at different stages. The components are:
+
+- authorization: check that a user exists, decide on an authentication method or proxy realm, and possibly apply some attributes to be returned in the reply packet.
+- authentication: verify that the password is correct.
+- preaccounting: decide whether to proxy the request, and possibly add attributes that should be included in any logs
+- accounting: record the request in the log
+- checksimul: count the number of active sessions for the user
+- postauth: process the response before it's sent to the NAS
+- preproxy: process a request before it's proxied
+- postproxy: filter attributes from a reply to a proxied request
+
+A module declares which components it supports by putting function
+pointers in its "module_t rlm_*" structure.
+
+
+Module configuration
+^^^^^^^^^^^^^^^^^^^^
+
+The administrator requests the creation of a module instance by adding
+it inside the modules{} block in radiusd.conf. The instance definition
+looks like this::
+
+ module_name [instance_name] {
+ param1 = value1
+ param2 = value2
+ param3 = value3
+ ...
+ }
+
+The module_name is used to load the module. To see the names of the available
+modules, look for the rlm\_\*.so files in $installprefix/lib. The module_name
+is that, minus the rlm\_ and the .so.
+
+instance_name is an identifier for distinguishing multiple instances of the
+same module. If you are only loading a module once, you can leave out the
+instance_name and it will be assumed to be the same as the module_name.
+
+The parameters inside the module block are passed without interpretation to
+the module and generally point to the exact location of a database or enable
+optional features of the module. Each module should document what parameters
+it accepts and what they do.
+
+For each Access-Request that comes to the server, the authorize{}
+block is called. Then one of the Auth-Type{} blocks from authenticate{}
+is called, depending on the Auth-Type attribute that was chosen by
+authorize{}. Finally, the post-auth{} block is called. If authorize{}
+set the Proxy-To-Realm attribute, then proxying takes over via
+pre-proxy{} and post-proxy{}, and the local authenticate{} phase is
+skipped.
+
+For each Accounting-Request that comes to the server, the preacct{} block is
+called, followed by the accounting{} block. accounting{} is skipped if
+preacct{} sets Proxy-To-Realm.
+
+For an explanation of what "calling" a config block means, see
+the "configurable_failover" file.
+
+
+The lifetime of a module
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+When the server is starting up, or reinitializing itself as a result of a
+SIGHUP, it reads the modules{} section. Each configured module will be loaded
+and its init() method will be called::
+
+ int init(void)
+
+The init() method should take care of
+any setup that is not tied to a specific instance. It will only be called
+once, even if there are multiple instances configured.
+
+For each configured instance, after the init() method, the instantiate()
+method is called. It is given a handle to the configuration block holding its
+parameters, which it can access with cf_section_parse().::
+
+ int instantiate(CONF_SECTION \*cs, void \**instance)
+
+The instantiate() function should look up options in the config section, and
+open whatever files or network connections are necessary for the module to do
+its job. It also should create a structure holding all of the persistent
+variables that are particular to this instance (open file descriptors,
+configured pathnames, etc.) and store a pointer to it in \*instance. That
+void \* becomes a handle (some would call it a "cookie") representing this
+instance. The instance handle is passed as a parameter in all subsequent
+calls to the module's methods, so they can determine which database they are
+supposed to act on.
+
+The authorize(), authenticate(), preaccounting(), and accounting() functions
+are all called the same way::
+
+ int authorize(void \*instance, REQUEST \*request)
+ int authenticate(void \*instance, REQUEST \*request)
+ int preaccounting(void \*instance, REQUEST \*request)
+ int accounting(void \*instance, REQUEST \*request)
+
+they each receive the instance handle and the request, and are expected to
+act on the request using the database pointed to by the instance handle
+(which was set by the instantiate() function).
+
+When the server is being shut down (as the first part of SIGHUP for example)
+detach() is called for each module instance.::
+
+ int detach(void \*instance)
+
+The detach() method should release whatever resources were allocated by the
+instantiate() method.
+
+After all instances are detached, the destroy() method is called.::
+
+ int destroy(void)
+
+It should release resources that were acquired by the init() method.
+
+--Alan Curry <pacman@world.std.com>
diff --git a/doc/developer/release-method.rst b/doc/developer/release-method.rst
new file mode 100644
index 0000000..6e218c0
--- /dev/null
+++ b/doc/developer/release-method.rst
@@ -0,0 +1,42 @@
+Release Method
+==============
+
+As of 2.0, the release process is much simpler. Edit the
+Changelog with the version number and any last updates.
+
+vi doc/ChangeLog
+git commit doc/ChangeLog
+
+
+ Change version numbers in the VERSION file:
+
+vi VERSION
+git commit VERSION
+
+
+ Make the files
+
+ Note that it also does "make dist-check", which checks
+ the build rules for various packages.
+
+make dist
+
+
+ Validate that the packages are OK. If so, tag the release.
+
+ Note that this does NOT actually do the tagging! You will
+ have to run the command it prints out yourself.
+
+make dist-tag
+
+
+ Sign the packages. You will need the correct GPG key for this
+ to work.
+
+make dist-sign
+
+
+ Push to the FTP site. You will need write access to the FTP site
+ for this to work.
+
+make dist-publish
diff --git a/doc/index.rst b/doc/index.rst
new file mode 100644
index 0000000..c8ef10a
--- /dev/null
+++ b/doc/index.rst
@@ -0,0 +1,29 @@
+.. FreeRADIUS documentation master file, created by
+ sphinx-quickstart on Tue May 18 13:26:39 2010.
+ You can adapt this file completely to your liking, but it should at least
+ contain the root `toctree` directive.
+
+.. toctree::
+ :maxdepth: 2
+
+ aaa
+ ldap_howto
+ load-balance
+
+ coding-methods
+ DIFFS
+ release-method
+
+ cisco
+ configurable_failover
+ processing_users_file
+ proxy
+ variables
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
+
diff --git a/doc/modules/RADIUS-LDAP-eDirectory b/doc/modules/RADIUS-LDAP-eDirectory
new file mode 100644
index 0000000..abfa1cf
--- /dev/null
+++ b/doc/modules/RADIUS-LDAP-eDirectory
@@ -0,0 +1,18 @@
+"Integrating Novell eDirectory with FreeRADIUS"
+
+Overview
+You can integrate Novell® eDirectoryTM 8.7.1 or later with FreeRADIUS
+1.0.2 onwards to allow wireless authentication for eDirectory users.
+By integrating eDirectory with FreeRADIUS, you can do the following:
+* Use universal password for RADIUS authentication.
+ Universal password provides single login and authentication for
+ eDirectory users. Therefore, the users need not have a separate
+ password for RADIUS and eDirectory authentication.
+* Enforce eDirectory account policies for users.
+ The existing eDirectory policies on the user accounts can still be
+ applied even after integrating with RADIUS. Also, you can make use
+ of the intruder lockout facility of eDirectory by logging the
+ failed logins into eDirectory.
+
+For configuration information please refer to the Novell documentation
+ http://www.novell.com/documentation/edir_radius/index.html
diff --git a/doc/modules/ldap_howto.rst b/doc/modules/ldap_howto.rst
new file mode 100644
index 0000000..53f0f3e
--- /dev/null
+++ b/doc/modules/ldap_howto.rst
@@ -0,0 +1,1648 @@
+LDAP Configuration
+==================
+
+This document describes how to setup Freeradius on a Freebsd machine
+using LDAP as a backend. This is by no means complete and your
+mileage may vary. If you are having any problems with the setup of
+your freeradius installation, please read the documentation that comes
+with Freeradius first as that is where all the information for this
+project came from. If you find any bugs, typos, alternative ideas, or
+just plain wrong information, please let me know by sending an email
+to the address above.
+
+The radius servers in this document are built on Freebsd 4.8, using
+Freeradius .81 with OpenLDAP 2.0.27 as the backend. The servers are
+designed to support customers for multiple services. In this document
+we will use regular dialup and dialup ISDN as examples of two
+different services using the same radius server for authentication.
+
+OVERVIEW
+--------
+
+The radius servers are to be provisioned by a some sort of system we
+will call Billing. Billing could simply be a script, a web front-end,
+or an actual integration into a billing system. Billing will provision
+to the master LDAP server. The master LDAP server is running slurpd,
+which will replicate all changes to the other radius servers. Each
+radius server will run a local instance of LDAP.
+
+The radius servers will be accepting Radius auth packets and Radius
+acct packets. The accounting packets will be stored locally on each
+radius server and then forwarded to the Accounting radius server,
+using radrelay. The Accounting radius server will store all the
+radius information in some sort of database such as MySQL, Postgres,
+or Oracle. The configuration of the actual Accounting radius server
+is outside the scope of this document. Please refer to the freeradius
+documentation for setting up that server.
+
+The Accounting radius server will help to provide a searchable
+interface to the accounting data for billing and usage purposes and
+could allow a web front-end to be built for helpdesk/customer service
+usage. If that is not needed for your purposes, then disregard all
+details about the Accounting radius server.
+
+In order to make sure no data is lost in the event of the Accounting
+radius server going down, the replication of data will take place
+using radrelay. Radrelay will do the equivalent of a tail on the
+detail file and will continually attempt to duplicate each radius
+packet that is stored in the detail file and send it off to the
+recipient(s) specified. Upon receipt of an accounting_response packet
+radrelay will consider that packet completed and continue working on
+the others. Each radius server will also be storing its own copy of
+all accounting packets that are sent to it.
+
+Each NAS will be setup with a primary radius server and a failover
+radius server. We will spread the load among the group of radius
+servers that we have so some are acting as a primary to some NAS's and
+acting as a secondary to others. In the event of a radius failure,
+the NAS should failover to the backup radius server. How to configure
+this is dependent on the particular NAS being used.
+
+::
+
+ Will use Radius acct data Billing will provision
+ for real-time billing out to the Master LDAP
+ server over LDAP
+ +------------+
+ | Accounting | +---------+
+ | Radius | | Billing |
+ +------------+ +----+----+
+ /|\ |
+ | |
+ | |
+ | |
+ | Provisioning
+ | Message
+ | |
+ Duplicate |
+ Acct |
+ | |
+ | \|/
+ | +------------+
+ | +------------------| LDAP Master|
+ | | +------------+
+ | | |
+ | Slurpd Slurpd Replication
+ | Replication |
+ | | |
+ | | \|/
+ | | +------------+
+ | | | Radius2 |
+ The Radius servers | | | LDAP Slave |
+ will create a local | \|/ +------------+
+ copy of all acct +-------------+
+ packets and then | Radius1 |
+ fwd a copy back | LDAP Slave | All Radius servers run a
+ to accounting +-------------+ local copy of LDAP for
+ /|\ /|\ Authorization and Authentication
+ | |
+ | |
+ | |
+ | |
+ Auth Acct
+ | |
+ | |
+ | |
+ | |
+ | |
+ \|/ \|/
+ +-----------+
+ | |
+ | |
+ | NAS |
+ | |
+ +-----------+
+ The NAS will be setup to
+ use one of the Radius servers
+ as primary and the others as failover
+
+
+LDAP
+----
+
+The LDAP directory is designed to start with the top level of
+dc=mydomain,dc=com. The next level of the tree contains the different
+services that will be stored within the ldap server. For the radius
+users, it will be specified as ou=radius. Below ou=radius, will be
+the different types of accounts. For example, ou=users will store the
+users and ou=profiles will store the default radius profiles. The
+profiles are entries that will be used to store group-wide radius
+profiles. The group ou=admins will be a place to enter the users for
+Billing, Freeradius, and any other administrative accounts that are
+needed.
+
+::
+
+ +---------------------+
+ | |
+ | Dc=mydomain,dc=com |Objectclass:organizationalUnit
+ | |Objectclass:dcObject
+ +---------------------+
+ |
+ |
+ \|/
+ +---------------+
+ | |
+ | Ou=radius | Objectclass:organizationalUnit
+ | |
+ +---------------+
+ |
+ +-----------------------+-------------------------|
+ | | |
+ \|/ \|/ \|/
+ +---------+ +---------------+ +-------------+
+ | | | | | |
+ |Ou=users | | Ou=profiles | | Ou=admins |
+ | | | | | |
+ +---------+ +---------------+ +------|------+
+ | | |
+ | | |
+ \|/ | \|/
+ ----- Objectclass: | ----- Objectclass:
+ // \\ radiusprofile | // \\ person
+ | | | | |
+ \\ // | \\ //
+ ----- \|/ ----- Dn:cn=freeradius
+ Dn: uid=example,ou=users, ----- ObjectClass: ou=admins,ou=radius
+ dc=mydomain,dc=com // \\ radiusprofile dc=mydomain,dc=com
+ | |
+ | |
+ \\ //
+ -----
+ Dn: uid=dial,ou=profiles,ou=radius,dc=mydomain,dc=com
+
+
+An example LDIF file is below.
+NOTE: There are unique radius attribute types and objectclasses, these will be
+explained in the configuration section.
+
+::
+
+ dn: dc=mydomain,dc=com
+ objectClass: dcObject
+ objectClass: organizationUnit
+ ou: Mydomain.com Radius
+ dc: mydomain
+
+ dn: ou=radius,dc=mydomain,dc=com
+ objectclass: organizationalunit
+ ou: radius
+
+ dn: ou=profiles,ou=radius,dc=mydomain,dc=com
+ objectclass: organizationalunit
+ ou: profiles
+
+ dn: ou=users,ou=radius,dc=mydomain,dc=com
+ objectclass: organizationalunit
+ ou: users
+
+ dn: ou=admins,ou=radius,dc=mydomain,dc=com
+ objectclass: organizationalunit
+ ou: admins
+
+ dn: uid=dial,ou=profiles,ou=radius,dc=mydomain,dc=com
+ objectclass: radiusprofile
+ uid: dial
+ radiusServiceType: Framed-User
+ radiusFramedProtocol: PPP
+ radiusFramedIPNetmask: 255.255.255.0
+ radiusFramedRouting: None
+
+ dn: uid=isdn,ou=profiles,ou=radius,dc=mydomain,dc=com
+ objectclass: radiusprofile
+ uid: isdn
+ radiusServiceType: Framed-User
+ radiusFramedProtocol: PPP
+ radiusFramedIPNetmask: 255.255.255.0
+ radiusFramedRouting: None
+
+ dn: uid=example,ou=users,ou=radius,dc=mydomain,dc=com
+ objectclass: radiusProfile
+ uid: example
+ userPassword: test
+ radiusGroupName: dial
+ radiusGroupName: isdn
+
+ dn: cn=freeradius,ou=admins,ou=radius,dc=mydomain,dc=com
+ objectclass: person
+ sn: freeradius
+ cn: freeradius
+ userPassword: freeradius
+
+ dn: cn=billing,ou=admins,ou=radius,dc=mydomain,dc=com
+ objectclass: person
+ sn: freeradius
+ cn: freeradius
+ userPassword: billing
+
+ dn: cn=replica,ou=admins,ou=radius,dc=mydomain,dc=com
+ objectclass: person
+ sn: replica
+ cn: replica
+ userPassword: replica
+
+In order to configure the ldap server to understand the radius schema that we
+are using, the attribute types and objectclasses must be defined in slapd.conf.
+The file is included with the following line in slapd.conf::
+
+ include /usr/local/etc/openldap/schema/RADIUS-LDAPv3.schema
+
+Below is the complete Schema::
+
+ ----Begin RADIUS-LDAPv3.schema----
+
+ #################################################
+ ##### custom radius attributes ##################
+
+ objectIdentifier myOID 1.1
+ objectIdentifier mySNMP myOID:1
+ objectIdentifier myLDAP myOID:2
+ objectIdentifier myRadiusFlag myLDAP:1
+ objectIdentifier myObjectClass myLDAP:2
+
+ attributetype
+ ( myRadiusFlag:1
+ NAME 'radiusAscendRouteIP'
+ DESC 'Ascend VSA Route IP'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+ attributetype
+ (myRadiusFlag:2
+ NAME 'radiusAscendIdleLimit'
+ DESC 'Ascend VSA Idle Limit'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+ attributetype
+ (myRadiusFlag:3
+ NAME 'radiusAscendLinkCompression'
+ DESC 'Ascend VSA Link Compression'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+ attributetype
+ (myRadiusFlag:4
+ NAME 'radiusAscendAssignIPPool'
+ DESC 'Ascend VSA AssignIPPool'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+
+ attributetype
+ (myRadiusFlag:5
+ NAME 'radiusAscendMetric'
+ DESC 'Ascend VSA Metric'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+ #################################################
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.1
+ NAME 'radiusArapFeatures'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.2
+ NAME 'radiusArapSecurity'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.3
+ NAME 'radiusArapZoneAccess'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.44
+ NAME 'radiusAuthType'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.4
+ NAME 'radiusCallbackId'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.5
+ NAME 'radiusCallbackNumber'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.6
+ NAME 'radiusCalledStationId'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.7
+ NAME 'radiusCallingStationId'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.8
+ NAME 'radiusClass'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.45
+ NAME 'radiusClientIPAddress'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.9
+ NAME 'radiusFilterId'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.10
+ NAME 'radiusFramedAppleTalkLink'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.11
+ NAME 'radiusFramedAppleTalkNetwork'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.12
+ NAME 'radiusFramedAppleTalkZone'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.13
+ NAME 'radiusFramedCompression'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.14
+ NAME 'radiusFramedIPAddress'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.15
+ NAME 'radiusFramedIPNetmask'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.16
+ NAME 'radiusFramedIPXNetwork'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.17
+ NAME 'radiusFramedMTU'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.18
+ NAME 'radiusFramedProtocol'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.19
+ NAME 'radiusFramedRoute'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.20
+ NAME 'radiusFramedRouting'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.46
+ NAME 'radiusGroupName'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.47
+ NAME 'radiusHint'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.48
+ NAME 'radiusHuntgroupName'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.21
+ NAME 'radiusIdleTimeout'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.22
+ NAME 'radiusLoginIPHost'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.23
+ NAME 'radiusLoginLATGroup'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.24
+ NAME 'radiusLoginLATNode'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.25
+ NAME 'radiusLoginLATPort'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.26
+ NAME 'radiusLoginLATService'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.27
+ NAME 'radiusLoginService'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.28
+ NAME 'radiusLoginTCPPort'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.29
+ NAME 'radiusPasswordRetry'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.30
+ NAME 'radiusPortLimit'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.49
+ NAME 'radiusProfileDn'
+ DESC ''
+ EQUALITY distinguishedNameMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
+ SINGLE-VALUE
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.31
+ NAME 'radiusPrompt'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.50
+ NAME 'radiusProxyToRealm'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.51
+ NAME 'radiusReplicateToRealm'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.52
+ NAME 'radiusRealm'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.32
+ NAME 'radiusServiceType'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.33
+ NAME 'radiusSessionTimeout'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.34
+ NAME 'radiusTerminationAction'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.35
+ NAME 'radiusTunnelAssignmentId'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.36
+ NAME 'radiusTunnelMediumType'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.37
+ NAME 'radiusTunnelPassword'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.38
+ NAME 'radiusTunnelPreference'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.39
+ NAME 'radiusTunnelPrivateGroupId'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.40
+ NAME 'radiusTunnelServerEndpoint'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.41
+ NAME 'radiusTunnelType'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.42
+ NAME 'radiusVSA'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.43
+ NAME 'radiusTunnelClientEndpoint'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ )
+
+
+ #need to change asn1.id
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.53
+ NAME 'radiusSimultaneousUse'
+ DESC ''
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+ SINGLE-VALUE
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.54
+ NAME 'radiusLoginTime'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.55
+ NAME 'radiusUserCategory'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.56
+ NAME 'radiusStripUserName'
+ DESC ''
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
+ SINGLE-VALUE
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.57
+ NAME 'dialupAccess'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.58
+ NAME 'radiusExpiration'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.59
+ NAME 'radiusCheckItem'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ )
+
+ attributetype
+ ( 1.3.6.1.4.1.3317.4.3.1.60
+ NAME 'radiusReplyItem'
+ DESC ''
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ )
+
+
+ objectclass
+ ( 1.3.6.1.4.1.3317.4.3.2.1
+ NAME 'radiusprofile'
+ SUP top STRUCTURAL
+ DESC ''
+ MUST ( uid )
+ MAY ( userPassword $
+ radiusArapFeatures $ radiusArapSecurity $ radiusArapZoneAccess $
+ radiusAuthType $ radiusCallbackId $ radiusCallbackNumber $
+ radiusCalledStationId $ radiusCallingStationId $ radiusClass $
+ radiusClientIPAddress $ radiusFilterId $ radiusFramedAppleTalkLink $
+ radiusFramedAppleTalkNetwork $ radiusFramedAppleTalkZone $
+ radiusFramedCompression $ radiusFramedIPAddress $
+ radiusFramedIPNetmask $ radiusFramedIPXNetwork $
+ radiusFramedMTU $ radiusFramedProtocol $
+ radiusCheckItem $ radiusReplyItem $
+ radiusFramedRoute $ radiusFramedRouting $ radiusIdleTimeout $
+ radiusGroupName $ radiusHint $ radiusHuntgroupName $
+ radiusLoginIPHost $ radiusLoginLATGroup $ radiusLoginLATNode $
+ radiusLoginLATPort $ radiusLoginLATService $ radiusLoginService $
+ radiusLoginTCPPort $ radiusLoginTime $ radiusPasswordRetry $
+ radiusPortLimit $ radiusPrompt $ radiusProxyToRealm $
+ radiusRealm $ radiusReplicateToRealm $ radiusServiceType $
+ radiusSessionTimeout $ radiusStripUserName $
+ radiusTerminationAction $ radiusTunnelAssignmentId $
+ radiusTunnelClientEndpoint $ radiusIdleTimeout $
+ radiusLoginIPHost $ radiusLoginLATGroup $ radiusLoginLATNode $
+ radiusLoginLATPort $ radiusLoginLATService $ radiusLoginService $
+ radiusLoginTCPPort $ radiusPasswordRetry $ radiusPortLimit $
+ radiusPrompt $ radiusProfileDn $ radiusServiceType $
+ radiusSessionTimeout $ radiusSimultaneousUse $
+ radiusTerminationAction $ radiusTunnelAssignmentId $
+ radiusTunnelClientEndpoint $ radiusTunnelMediumType $
+ radiusTunnelPassword $ radiusTunnelPreference $
+ radiusTunnelPrivateGroupId $ radiusTunnelServerEndpoint $
+ radiusTunnelType $ radiusUserCategory $ radiusVSA $
+ radiusExpiration $ dialupAccess $
+ radiusAscendRouteIP $ radiusAscendIdleLimit $
+ radiusAscendLinkCompression $
+ radiusAscendAssignIPPool $ radiusAscendMetric )
+ )
+ ----End RADIUS-LDAPv3.schema----
+
+
+Now we need to setup the permissions on the ldap server. Notice above we
+created three users in the admin ou. These users will be specific for billing,
+freeradius, and replication.
+
+On the master ldap server, we will set the following permissions::
+
+ access to attr=userPassword
+ by self write
+ by dn="cn=billing,ou=admins,ou=radius,dc=mydomain,dc=com" write
+ by anonymous auth
+ by * none
+
+ access to *
+ by self write
+ by dn="cn=billing,ou=admins,ou=radius,dc=mydomain,dc=com" write
+ by anonymous auth
+ by * none
+
+This will give the billing user write access to add/delete users. For security
+we will not give read access to any other users. You can easily add another
+read-only user to this setup if you want to build some sort of web interface to
+do only reads.
+
+Now on the slave ldap servers (aka the radius servers) we will setup the
+following permissions::
+
+ access to attr=userPassword
+ by self write
+ by dn="cn=replica,ou=admins,ou=radius,dc=mydomain,dc=com" write
+ by anonymous auth
+ by * none
+
+ access to dn="ou=users,ou=radius,dc=mydomain,dc=com"
+ by dn="cn=replica,ou=admins,ou=radius,dc=mydomain,dc=com" write
+ by dn="cn=freeradius,ou=admins,ou=radius,dc=mydomain,dc=com" read
+ by anonymous auth
+ by * none
+
+ access to *
+ by self write
+ by dn="cn=replica,ou=admins,ou=radius,dc=mydomain,dc=com" write
+ by anonymous auth
+ by * none
+
+
+This will give the replica user write access. This user will be discussed
+below and it is involved in the process of replicating the master server to the
+slaves. The freeradius user only needs read access to do the lookups for
+authorization.
+
+Now we will want to setup indexes to speed up searches. At the minimum, below
+will work. Since all radius lookups are currently using the uid, we will want
+to index that. It is also a good idea to index the objectclass attribute.
+
+# Indices to maintain
+index objectClass eq
+index uid eq
+
+Now we need to setup the replication from the master to the slave servers. To
+do this, we will add the following to the slapd.conf file on the master:
+
+On the master LDAP server::
+ replica host=radius1.mydomain.com
+ binddn=cn=replica,ou=admins,ou=radius,dc=mydomain,dc=com
+ bindmethod=simple credentials=replica
+
+ replica host=radius2.mydomain.com
+ binddn=cn=replica,ou=admins,ou=radius,dc=mydomain,dc=com
+ bindmethod=simple credentials=replica
+
+We will need to add a replica for each slave LDAP server. The binddn is the
+name that is used to bind to the slave server, and the credentials is the
+secret for that user.
+
+On the slave LDAP servers::
+
+ updatedn cn=replica,ou=admins,ou=radius,dc=mydomain,dc=com
+ updateref ldap://ldapmaster.mydomain.com
+
+Those will determine what name is allowed to update the LDAP server and if an
+update is attempted directly, what server to refer the update to.
+
+RADIUS
+------
+
+The radius server is setup to use LDAP for both Authorization and
+Authentication. This section will describe what events will take place during
+an AAA session with a NAS. When the NAS sends a access_request to the radius
+server, the radius server will perform authorization and authentication based
+on a series of modules that are defined in radiusd.conf. For example, the
+module defined as ldap, will be used to make connections to the LDAP directory.
+
+An example is seen in raddb/mods-config/ldap::
+
+The first thing that is done is authorization of the user. The radius server
+will process the modules in the order specified in the authorization section of
+radiusd.conf. Currently, they are in the following order.
+
+1) preprocess
+2) suffix
+3) files
+4) ldap
+
+The first module will be preprocess. This will first check the huntgroups of
+the user coming in. The huntgroups are defined in the file huntgroups and they
+are a group listing of the NAS-IP-Addresses that make the access_request. This
+is useful in creating specific actions based on the NAS-IP that the request is
+made from. An example, is below::
+
+ isdncombo NAS-IP-Address == 10.10.10.1
+ dialup NAS-IP-Address == 10.10.10.2
+ dialup NAS-IP-Address == 10.10.10.3
+
+We will have one NAS that is used for both ISDN and regular dialup customers,
+the other NAS's will be only used for dialup.
+
+The preprocess module may also use the hints file, to load hints to the radius
+server, and add additional hacks that are based on the type of request that
+comes in. This is to help with certain NAS's that don't conform to radius
+RFC's. Check the comments in radiusd.conf for an explanation on those.
+
+The second module is suffix. This event will determine which realm the user is
+in, based on the User-Name attribute. It is currently setup to split the
+username at the occurence of the @symbol. For example, the username of
+example@mydomain.com, will be split into example and mydomain.com. The realm
+is then checked against the file proxy.conf, which will determine what actions
+should be taken for that realm. Certain realms can be setup to be proxied to a
+different radius server or set to authenticate locally. Also, the username can
+be setup to be stripped from the realm or left intact. An example of
+proxy.conf, is listed below. If the realm is to be proxied, then a secret is
+needed, which is the secret of the radius server it is to be proxied to.
+By default the User-Name will be stripped, unless the nostrip option is set.
+
+Currently we will not be using realms with our users, but adding this ability
+in the future will be much easier with already incorporating proxy.conf into the
+setup::
+
+ proxy server {
+ synchronous = no
+ retry_delay = 5
+ retry_count = 3
+ dead_time = 120
+ servers_per_realm = 15
+ default_fallback = yes
+ }
+
+ realm NULL {
+ type = radius
+ authhost = LOCAL
+ accthost = LOCAL
+ #secret = testing123
+ }
+
+ realm DEFAULT {
+ type = radius
+ authhost = LOCAL
+ accthost = LOCAL
+ #secret = testing123
+ }
+
+The next module is files, which is commonly know as the users file. The users
+file will start with either a username to determine how to authorize a specific
+user, or a DEFAULT setting. In each line it will define what items must be
+present for there to be a match in the form of attribute == value. If all the
+required attributes are matched, then attributes specified with attribute :=
+value will be set for that user. If no match is found the users file will
+continue to be processed until there is a match. The last DEFAULT setting will
+be set as a catch-all, in case there is no previous match. If a match is made,
+the statement of Fall-Through determines if the users file should continue to
+be processed or if it should stop right there.
+
+The Ldap-Group corresponds to the LDAP attribute of radiusGroupName (see ldap
+configuration above). The user may be assigned multiple radiusGroupNames, one
+for each of the services that the user is authorized for. If the user does
+belong to the correct group, then the user will be authorized for that type of
+access. If the user does not belong to that group, then there will not be a
+match and the users file will continue to be processed. If a match is made and
+there is a User-Profile set, then the radius server will lookup the attributes
+that exist in that User-Profile in the LDAP directory. These are radius
+attributes that will be sent to the NAS as a reply-item.
+
+An example users file is below::
+
+ DEFAULT Ldap-Group == disabled, Auth-Type := Reject
+ Reply-Message = "Account disabled. Please call the helpdesk."
+
+ DEFAULT Huntgroup-Name == isdncombo, NAS-Port-Type == Async, Ldap-Group == dial,
+ User-Profile := "uid=dial,ou=profiles,ou=radius,dc=mydomain,dc=com"
+ Fall-Through = no
+
+ DEFAULT Huntgroup-Name == isdncombo, NAS-Port-Type == ISDN, Ldap-Group == isdn,
+ User-Profile := "uid=isdn,ou=profiles,ou=radius,dc=mydomain,dc=com"
+ Fall-Through = no
+
+ DEFAULT Huntgroup-Name == dial, Ldap-Group == dial,
+ User-Profile := "uid=dial,ou=profiles,ou=radius,dc=mydomain,dc=com"
+ Fall-Through = no
+
+ DEFAULT Auth-Type := Reject
+ Reply-Message = "Please call the helpdesk."
+
+Notice that the catchall DEFAULT is set to Reject the user. This will stop the
+authorization and immediately send back an access_reject message. Because
+business rules are applied above to each scenario where the user will be
+authorized for access, if no match is found, then we will want to stop the
+process immediately to save resources.
+
+By using the Ldap-Group feature we can limit user logins to only the services
+they are subscribed to. Some examples of possible user setups are below::
+
+ #user with access to dial-up
+ dn: uid=user1,ou=users,ou=radius,dc=mydomain,dc=com
+ objectclass: radiusprofile
+ uid: user1
+ userPassword: whatever
+ radiusgroupname: dial
+
+ #user with access to ISDN and dial
+ dn: uid=user2,ou=users,ou=radius,dc=mydomain,dc=com
+ objectclass: radiusprofile
+ uid: user2
+ userPassword: whatever
+ radiusgroupname: dial
+ radiusgroupname: isdn
+
+ #same user as above that was suspended for not paying
+ dn: uid=user2,ou=users,ou=radius,dc=mydomain,dc=com
+ objectclass: radiusprofile
+ uid: user2
+ userPassword: whatever
+ radiusgroupname: dial
+ radiusgroupname: isdn
+ radiusgroupname: disabled
+
+Now that we have authorized the user, the final piece is to authenticate the
+user. Authentication is currently done by checking if the password sent in the
+access_request packet is correct. This action will be done with an attempted
+bind to the LDAP server using the User-Name and User-Password attributes
+passed to it from the access_request. If the user is successfully authorized,
+then an access_accept message will be sent back to the NAS, with any reply
+items that were defined in the authorization section. If the user did not
+supply the correct password, then an access_reject message will be sent to the
+user.
+
+If the NAS is sent an access_accept packet then the user will be given access
+to the service and the NAS will then send an acct_request packet. This will be
+a request packet to start a radius accounting session. The way the server will
+log the accounting packets is determined in the detail module in the
+radiusd.conf file. Since we will be storing a local copy and forwarding on all
+accounting to the Accounting radius server, we will store two local copies on
+the machine. The first one is done in a regular detail file as defined in the
+following::
+
+ detail detail1 {
+ filename = ${radacctdir}/%{Client-IP-Address}/detail-%Y%m%d
+ permissions = 0600
+ dir_permissions = 0755
+ }
+
+The second detail file will be used by the program radrelay to relay a copy of
+all accounting packets to the Accounting radius server. This file is stored as
+a catchall for all accounting packets. The radrelay program will basically do
+a tail on that file and will then attempt to send a copy of each addition to it
+to the Accounting server. If the copy is successfully sent, then it will be
+deleted from this file. If the Accounting server were to go down, then this
+file will continue to build up entries. As soon as the Accounting server is
+back online, an attempt to re-send the packets to the Accounting server will
+made. This file is defined in the following section of radiusd.conf::
+
+ detail detail2 {
+ filename = ${radacctdir}/detail-combined
+ permissions = 0600
+ dir_permissions = 0755
+ locking = yes
+ }
+
+INSTALLATION
+------------
+
+The new radius servers are currently built on Freebsd 4.8. As the version may
+eventually change, these instructions may no longer apply. The steps for
+building the server are the following:
+
+* Install FreeBSD
+* Install other FreeBSD items
+* Install OpenLDAP *NOTE: this must be done before installing Freeradius*
+* Install FreeRadius
+
+Under the assumption that FreeBSD is already installed and the kernel rebuilt
+to the specifications needed for the machine, there are several other things
+that may be needed at this time and the purpose of this is just as a reminder.
+
+install cvsup-without-gui from the ports collection
+
+run cvsup on all to update the ports to the most recent versions
+
+might be a good idea to upgrade the src
+
+edit and run cvsup on /usr/share/examples/cvsup/standard-supfile
+
+cd /usr/src - vi Makefile and follow instructions
+
+install sendmail from ports to keep up to date with the most recent versions.
+In the ports collection /ports/mail/sendmail run make; make install; make
+mailer.conf. Then edit rc.conf and change to sendmail_enable=NO
+radius servers only need the local interface to send daily reports
+
+edit rc.conf to make sure inetd_enable=NO
+
+no reason to have extra services running
+
+if you rebuilt the kernel to add support for IPFIREWALL, then remember to add a
+firewall rule to rc.conf
+
+firewall_enable=YES
+firewall_type=OPEN (or actually create a real firewall rule)
+
+add crontab to keep date accurate for accounting::
+
+ 15 03 * * * /usr/sbin/ntpdate -s thetimeserver.mydomain.com
+
+install openldap from ports
+
+download the freeradius source as the ports collection is often outdated
+the default settings are /usr/local/etc/raddb, /var/log/radius.log, /var/log/radacct
+
+since openldap was installed first, you should not need any special flags to
+add ldap support
+
+Now its time to configure openlap and freeradius. First we will be looking at
+configuring OpenLDAP
+
+
+copy RADIUS-LDAPv3.schema to /usr/local/etc/openldap/schema
+
+edit /usr/local/etc/openldap/slapd.conf
+
+::
+
+ ----Begin slapd.conf----
+ # $OpenLDAP: pkg/ldap/servers/slapd/slapd.conf,v 1.23.2.7 2003/03/24 03:54:12
+ #kurt Exp $
+ #
+ # See slapd.conf(5) for details on configuration options.
+ # This file should NOT be world readable.
+ #
+ include /usr/local/etc/openldap/schema/core.schema
+ include /usr/local/etc/openldap/schema/RADIUS-LDAPv3.schema
+
+ # Define global ACLs to disable default read access.
+
+ # Do not enable referrals until AFTER you have a working directory
+ # service AND an understanding of referrals.
+ #referral ldap://root.openldap.org
+
+ loglevel 296
+
+ pidfile /var/run/slapd.pid
+ argsfile /var/run/slapd.args
+
+ # Load dynamic backend modules:
+ # modulepath /usr/local/libexec/openldap
+ # moduleload back_bdb.la
+ # moduleload back_ldap.la
+ # moduleload back_ldbm.la
+ # moduleload back_passwd.la
+ # moduleload back_shell.la
+
+ password-hash {SSHA}
+
+ access to attr=userPassword
+ by self write
+ by dn="cn=replica,ou=admins,ou=radius,dc=mydomain,dc=com" write
+ by anonymous auth
+ by * none
+
+ access to dn="ou=users,ou=radius,dc=mydomain,dc=com"
+ by dn="cn=replica,ou=admins,ou=radius,dc=mydomain,dc=com" write
+ by dn="cn=freeradius,ou=admins,ou=radius,dc=mydomain,dc=com" read
+ by anonymous auth
+ by * none
+
+ access to *
+ by self write
+ by dn="cn=replica,ou=admins,ou=radius,dc=mydomain,dc=com" write
+ by anonymous auth
+ by * none
+
+
+ #######################################################################
+ # ldbm database definitions
+ #######################################################################
+
+ database bdb
+ suffix "dc=mydomain,dc=com"
+ rootdn "cn=root,dc=mydomain,dc=com"
+ # Cleartext passwords, especially for the rootdn, should
+ # be avoid. See slappasswd(8) and slapd.conf(5) for details.
+ # Use of strong authentication encouraged.
+ rootpw {SSHA}Eu5EwPxTrwhEGrXQ9SaQZyfpu4iHt3NP
+ # The database directory MUST exist prior to running slapd AND
+ # should only be accessible by the slapd and slap tools.
+ # Mode 700 recommended.
+ directory /var/db/openldap-data
+ # Indices to maintain
+ index objectClass eq
+ index uid eq
+ mode 0600
+ cachesize 2000
+
+ # replica one for each
+ #replica host=radius1.mydomain.com
+ # binddn="cn=replica,ou=admins,ou=radius,dc=mydomain,dc=com"
+ # bindmethod=simple credentials=secret
+
+ replogfile /var/db/openldap-slurp/replog
+
+ ## REMEMBER TO ADD THIS TO THE SLAVES
+ updatedn "cn=freeradius,ou=admins,ou=radius,dc=mydomain,dc=com"
+ updateref ldap://ldapmaster.mydomain.com
+ ----End slapd.conf----
+
+
+To create a rootdn that is not stored in plain text, enter the following command::
+
+ $ slappasswd
+
+it will ask for password and verification::
+
+ New password:
+ Re-enter new password::
+
+while in the shell create the directory for the ldap database, this must be created before slapd can start::
+
+ $ mkdir /var/db/openldap-data
+
+move the slapd.sh.sample file to slapd.sh in /usr/local/etc/rc.d::
+
+ $ mv /usr/local/etc/rc.d/slapd.sh.sample slapd.sh
+
+enable logging in /etc/syslog.conf by adding the following::
+
+ local4.* /var/log/ldap.log
+ restart syslogd
+
+start it up on both the master and slave ldap servers::
+
+ $ /usr/local/etc/rc.d/slapd start
+
+create the structural ldif, schema.ldif::
+
+ ----Begin schema.ldif----
+ dn: dc=mydomain,dc=com
+ objectClass: dcObject
+ objectClass: organizationUnit
+ ou: Mydomain.com Radius
+ dc: mydomain
+
+ dn: ou=radius,dc=mydomain,dc=com
+ objectclass: organizationalunit
+ ou: radius
+
+ dn: ou=profiles,ou=radius,dc=mydomain,dc=com
+ objectclass: organizationalunit
+ ou: profiles
+
+ dn: ou=users,ou=radius,dc=mydomain,dc=com
+ objectclass: organizationalunit
+ ou: users
+
+ dn: ou=admins,ou=radius,dc=mydomain,dc=com
+ objectclass: organizationalunit
+ ou: admins
+
+ dn: uid=dial,ou=profiles,ou=radius,dc=mydomain,dc=com
+ objectclass: radiusprofile
+ uid: dial
+ radiusServiceType: Framed-User
+ radiusFramedProtocol: PPP
+ radiusFramedIPNetmask: 255.255.255.0
+ radiusFramedRouting: None
+
+ dn: uid=isdn,ou=profiles,ou=radius,dc=mydomain,dc=com
+ objectclass: radiusprofile
+ uid: isdn
+ radiusServiceType: Framed-User
+ radiusFramedProtocol: PPP
+ radiusFramedIPNetmask: 255.255.255.0
+ radiusFramedRouting: None
+
+ dn: uid=example,ou=users,ou=radius,dc=mydomain,dc=com
+ objectclass: radiusProfile
+ uid: example
+ userPassword: test
+ radiusGroupName: dial
+ radiusGroupName: isdn
+
+ dn: cn=freeradius,ou=admins,ou=radius,dc=mydomain,dc=com
+ objectclass: person
+ sn: freeradius
+ cn: freeradius
+ userPassword: freeradius
+
+ dn: cn=billing,ou=admins,ou=radius,dc=mydomain,dc=com
+ objectclass: person
+ sn: freeradius
+ cn: freeradius
+ userPassword: billing
+
+ dn: cn=replica,ou=admins,ou=radius,dc=mydomain,dc=com
+ objectclass: person
+ sn: replica
+ cn: replica
+ userPassword: replica
+ ----End schema.ldif----
+
+add the organizational structure to the master ldap database::
+
+ $ ldapadd -D uid=billing,ou=admins,ou=radius,dc=mydomain,dc=com -w billing -f
+ schema.ldif -h ldapmaster.mydomain.com
+
+run slapcat to see what the directory looks like::
+
+ $ slapcat
+
+If all went well the LDAP directory should be up and running and propagated to
+the slaves. Now you can add your users to the master.
+
+Now its time to setup FreeRadius. First cd into /usr/local/etc/raddb and take
+a look at all the configuration files, they are heavily documented so you may
+wish to read through them all before making and changes.
+
+
+edit huntgroups to specify a NAS to a huntgroup::
+
+ ----Begin huntgroups----
+ # dialup and isdn
+ isdncombo NAS-IP-Address == 10.10.10.1
+
+ # just dialup
+ dialup NAS-IP-Address == 10.10.10.2
+ dialup NAS-IP-Address == 10.10.10.3
+ ----End huntgroups----
+
+* edit proxy.conf to setup the different realms::
+
+ ----Begin proxy.conf----
+ proxy server {
+ synchronous = no
+ retry_delay = 5
+ retry_count = 3
+ dead_time = 120
+ servers_per_realm = 15
+ default_fallback = yes
+ }
+
+ realm NULL {
+ type = radius
+ authhost = LOCAL
+ accthost = LOCAL
+ #secret = testing123
+ }
+
+ realm DEFAULT {
+ type = radius
+ authhost = LOCAL
+ accthost = LOCAL
+ #secret = testing123
+ }
+ ----End proxy.conf----
+
+ -edit clients.conf to setup the NAS's that can talk to it
+
+
+ ----Begin clients.conf----
+ client 127.0.0.1 {
+ secret = example
+ shortname = localhost
+ nas_type = other
+ }
+
+
+ # isdn and dialup nas
+ client 10.10.10.1 {
+ secret = example
+ shortname = isdn
+ nas_type = cisco
+ }
+
+ #dialup only
+ client 10.10.10.2 {
+ secret = example
+ shortname = dialup1
+ nas_type = cisco
+ }
+
+ client 10.10.10.3 {
+ secret = example
+ shortname = dialup2
+ nas_type = cisco
+ }
+ ----End clients.conf----
+
+
+You may wish to look at the other files, but they should all be OK by default.
+
+create startup files in /usr/local/etc/rc.d
+
+radiusd.sh - the radiusd startup file::
+
+ ----Begin radiusd.sh----
+ #!/bin/sh
+ case "$1" in
+ start)
+ /usr/local/sbin/radiusd
+ echo -n ' radiusd'
+ ;;
+ stop)
+ if [ -f /usr/local/var/run/radiusd/radiusd.pid ]; then
+ kill -TERM `cat /usr/local/var/run/radiusd/radiusd.pid`
+ rm -f /usr/local/var/run/radiusd/radiusd.pid
+ echo -n ' radiusd'
+ fi
+ ;;
+ restart)
+ if [ -f /usr/local/var/run/radiusd/radiusd.pid ]; then
+ kill -HUP `cat /usr/local/var/run/radiusd/radiusd.pid`
+ echo 'radiusd restarted'
+ fi
+ ;;
+ *)
+ echo "Usage: ${0##*/}: { start | stop | restart }" 2>&1
+ exit 65
+ ;;
+ esac
+ ----End radiusd.sh----
+
+radrelay.sh - the radrelay startup file::
+
+
+ ----Begin radrelay.sh----
+ #!/bin/sh
+ case "$1" in
+
+ start)
+ /usr/local/bin/radrelay -a /var/log/radacct -d /usr/local/etc/raddb \
+ -S /usr/local/etc/raddb/radrelay_secret -f -r accounting.mydomain.com:1813 \
+ detail-combined
+ echo -n ' radrelay started'
+ ;;
+
+
+ stop)
+ /usr/bin/killall radrelay
+ echo ' radrelay stopped'
+ ;;
+
+ *)
+ echo "Usage: $[0##*/}: { start | stop }" 2>&1
+ exit 65
+ ;;
+
+ esac
+ ----End radrelay.sh----
+
+create radrelay_secret in /usr/local/etc/radddb
+This file will contain the secret to connect to the Accounting radius server::
+
+ ----Begin radrelay_secret----
+ example
+ ----End radrelay_secret----
+
+Now fire them up::
+ $ /usr/local/etc/rc.d/radiusd.sh start
+ $ /usr/local/etc/rc.d/radrelay.sh start
+
+You should be all set to start testing now.
+
+OTHER RANDOM NOTES AND THOUGHTS
+-------------------------------
+
+The client programs used to connect to the ldap directory are:
+
+ldapadd:
+ to add a record
+ldapmodify:
+ to modify a record
+ldapdelete:
+ to delete a record
+ldapsearch:
+ to search for a record
+slapcat:
+ to show the entire directory
+slappaswd:
+ to generate a crypted password
+
+Read the man pages on those commands, they tell you everything you
+need to know.
+
+They all follow this basic syntax::
+
+ $ ldapwhatever -D "uid=someone,ou=admins,ou=radius,dc=mydomain,dc=com" -w thesecret -andthenotherstuff
+
+Finally, if you are having trouble with LDAP, run it in debug mode by
+changing the following in slapd.sh::
+
+ slapd_args=
+
+to::
+
+ slapd_args= '-d 3'
+
+There is a program included with freeradius to test the radius server,
+its called radclient. Typing it alone will tell you all the options.
+You will need to create a file that contains radius attributes, such
+as::
+
+ User-Name = example
+ User-Password = test
+ Service-Type = Framed-User
+ NAS-IP-Address = 10.10.10.1
+ NAS-Port-Type = Async
+
+Then you fire that radius packet at the server by issuing::
+
+ $ radclient -f testradiusfile localhost auth thesecret
+
+-f = filename
+localhost is the server you are hitting
+auth or acct depending on the type of packet
+thesecret to connect to that server
+
+Finally, if you are having trouble you can run radius in debug mode
+and it will output everything that happens to the screen. To do that,
+kill the current process and run::
+
+ $ radiusd -X
+
+
+LINKS
+-----
+
+FREERADIUS
+++++++++++
+
+* _`FreeRADIUS`: http://www.freeradius.org
+* _`FreeRADIUS Documentation`: http://freeradius.org/documentation/
+* _`FreeRADIUS Wiki`: http://wiki.freeradius.org/
+
+OPENLDAP
+++++++++
+
+* _`OpenLDAP`: http://www.openldap.org
+* _`OpenLDAP Administrator's Guide`: http://www.openldap.org/doc/admin21
+
+RFCs
+++++
+
+* _`RFC2865: RADIUS Authentication`: http://freeradius.org/rfc/rfc2865.txt
+* _`RFC2866: RADIUS Accounting`: http://freeradius.org/rfc/rfc2866.txt
+* _`RFC2869: RADIUS Extentions`: http://freeradius.org/rfc/rfc2869.txt
+* _`RFC2251: LDAP v3`: http://www.ietf.org/rfc/rfc2251.txt
+* _`RFC2252: LDAP v3 Attribute Syntax Definitions`: http://www.ietf.org/rfc/rfc2252.txt
+* _`RFC2253: LDAP UTF-8 String Representation of Distinguishe d Names (DNs)`: http://www.ietf.org/rfc/rfc2252.txt
+* _`RFC2849: LDAP Data Interchange Fromat (LDIFs)`: http://www.ietf.org/rfc/rfc2849.txt
+* _`RFC3377: LDAP v3 Technical Specs`: http://www.ietf.org/rfc/rfc3377.txt
diff --git a/doc/modules/mschap.rst b/doc/modules/mschap.rst
new file mode 100644
index 0000000..37fcb9d
--- /dev/null
+++ b/doc/modules/mschap.rst
@@ -0,0 +1,196 @@
+rlm_mschap
+==========
+
+The mschap module provides support for MS-CHAPv1 and MS-CHAPv2, which is
+a common authentication mechanisms for Microsoft clients.
+
+If you want to support mschap, there are only 3 possibilities:
+
+ 1. You have access to the users plaintext password, and you configure
+ FreeRADIUS to read this, and set the Cleartext-Password control attribute.
+
+ 2. You have access to the NT (MS-CHAPv2) or LM (MS-CHAPv1) hashes,
+ and you configure FreeRADIUS to read this and set the NT/LM-Password
+ control attribute.
+
+ 3. You have Samba installed, joined into a windows domain, and use
+ the ntlm_auth helper binary to pass authentication onwards to
+ a domain controller.
+
+These are the ONLY possibilities; MS-CHAP is IMPOSSIBLE if you e.g. only
+have the unix/md5/sha crypt of your users password.
+
+For more info, see:
+
+ http://deployingradius.com/documents/protocols/compatibility.html
+
+EAP-MSCHAPv2
+============
+
+The EAP module provides MS-CHAPv2 support as well. It simply passes the
+data through to the mschap module, so you must configure mschap properly.
+
+ntlm_auth
+=========
+
+Method 3 above involves configuring the mschap module to call the Samba
+ntlm_auth helper:
+
+::
+
+ mschap {
+ ntlm_auth = "/path/to/bin ..."
+ }
+
+You need to be careful about setting this command line. There are several
+options for the arguments, in particular username and domain:
+
+ * --username=%{User-Name} - this will fail if you're using realms or host-based auth
+ * --username=%{mschap:User-Name} - this will fail if using using suffix i.e. user@domain
+
+You'll need to fit this to your local needs.
+
+Disabling ntlm_auth for some users
+----------------------------------
+
+You might have some users in the domain, and others in files or SQL that you
+want to authenticate locally. To do this, set::
+
+ MS-CHAP-Use-NTLM-Auth := 0
+
+This will disable ntlm_auth for that user/group. This is also obeyed
+for password changes (see below).
+
+Password changes
+================
+
+From FreeRADIUS version 3.0.0 the mschap module supports password changes.
+
+There are two options, ntlm_auth and local.
+
+ntlm_auth
+---------
+
+If you are using ntlm_auth to check passwords, you must also use
+ntlm_auth to change passwords. In modules/mschap you should configure::
+
+ mschap {
+ ntlm_auth = "...."
+ passchange {
+
+ # path to the binary
+ ntlm_auth = "/path/to/ntlm_auth --helper-protocol=ntlm-change-password-1"
+
+ # initial data to send
+ # this MUST be supplied
+ ntlm_auth_username = "username: %{mschap:User-Name}"
+ ntlm_auth_domain = "nt-domain: %{%{mschap:NT-Domain}:-YOURDOMAIN}"
+
+ # Or, you could try:
+ ntlm_auth_username = "full-username: %{User-Name}"
+ # ntlm_auth_domain - disabled
+
+ }
+
+
+If you are using ntlm_auth, then domain controllers might say
+"Password expired" if the user password is valid but has expired; the
+mschap module will detect this and return error 648 to the client,
+instructing it to try a password change.
+
+Note: if you have disabled ntlm_auth for a user/group, this will apply
+for password changes too - they will fall through to using the Local
+method.
+
+Local
+-----
+
+If you are performing mschap locally with Cleartext-Password/NT-Password, you
+can decrypt and process the password change locally. To do this, you configure
+the "local_cpw" string::
+
+ mschap {
+ passchange {
+ local_cpw = "%{xlat:...}
+ }
+ }
+
+To actually force a client to change passwords, you must set the expiry bit
+in the SMB-Account-Ctrl value - for example::
+
+ update control {
+ # U == user
+ # e == expired
+ SMB-Account-Ctrl-Text := '[Ue]'
+ }
+
+This will cause the client to receive "error 648 - password
+expired". Obviously you will need to ensure your local_cpw xlat clears
+this value, or else the client password will be expired the next time
+they log in. For example, you might use an SQL stored procedure to
+change passwords::
+
+ mschap {
+ passchange {
+ local_cpw = "%{sql:select change_password('%{SQL-User-Name}','%{MS-CHAP-New-NT-Password}')}"
+ }
+ }
+
+...and an example stored procedure for Postgres might be::
+
+ CREATE FUNCTION change_password(raduser text, ntpassword text) RETURNS text
+ LANGUAGE plpgsql
+ AS $$
+ BEGIN
+ update radcheck set value=ntpassword where username=raduser and attribute='NT-Password';
+ if not FOUND then
+ -- the user does not exist; die
+ return '';
+ end if;
+ update radcheck set value=replace(value,'e','') where username=raduser and attribute='SMB-Account-Ctrl-Text' and value like '%e%';
+ return 'ok';
+ END;
+ $$;
+
+
+The local_cpw xlat has access to two variables:
+
+ * MS-CHAP-New-NT-Password - the new value of NT-Password
+ * MS-CHAP-New-Cleartext-PAssword - the new value of Cleartext-Password
+
+This allows you to do things like::
+
+ # update via SQL
+ local_cpw = "%{sql:update radcheck set value='%{MS-CHAP-New-NT-Password}' where username='%{SQL-User-Name} and attribute='NT-Password'}"
+
+Or::
+
+ # update via exec/script
+ local_cpw = "%{exec:/my/script %{User-Name} %{MS-CHAP-New-Cleartext-Password}}"
+
+WARNING - wherever possible, you should use
+MS-CHAP-New-NT-Password. The reason is that cleartext passwords have
+undergone unicode transformation from the client encoding (utf-16) to
+the server encoding (utf-8) and the current code does this in a very
+ad-hoc way. The reverse transformation is also not done - when the
+server reads Cleartext-Password out of files/database, it assumes
+US-ASCII and thus international characters will fail.
+
+N.B. this could be fixed, if we wanted to pull in something like iconv.
+
+In addition, you should beware of Cleartext-Password when using SQL;
+any password character not in safe_characters will be encoded as a hex
+number, e.g. =20.
+
+Password changes over EAP
+=========================
+
+You must set the following in eap.conf::
+
+ eap {
+ mschapv2 {
+ send_error = yes
+ }
+ }
+
+Otherwise password changes for PEAP/MSCHAPv2 will not work.
diff --git a/doc/modules/rlm_dbm b/doc/modules/rlm_dbm
new file mode 100644
index 0000000..8ace2ff
--- /dev/null
+++ b/doc/modules/rlm_dbm
@@ -0,0 +1,195 @@
+Radius DBM module
+
+0. INTRODUCTION
+
+ rlm_dbm uses a Berkeley or GDBM <** database to store use information. It
+ is a lot faster than the files and passwd modules, takes less memory than
+ the fastusers module and does not require additional server software as
+ the LDAP and SQL modules does. In addition it supports groups, and of
+ course multiple entries per user or group.
+
+1. WHAT DOES IT DO
+
+ Basically, it opens the file you specifies in radiusd.conf and authenticates
+ users out of it. The file has to be a Berkeley or GDBM <** file database,
+ and may be created by rlm_dbm_parse or by a custom program of your choice.
+
+2. HOW TO USE IT
+
+ Put the module declaration in your radiusd.conf. It should in general look
+ like this:
+
+ dbm {
+ usersfile = ${confdir}/users.db
+ }
+ Note: some dbm libraries add .db suffix by itself.
+
+ Then put "dbm" in the "authorize {}" section of your radiusd.conf:
+
+ authorize {
+ preprocess
+ realms
+ dbm
+ }
+
+3. MODULE OPTIONS
+
+ The only option is "usersfile", which is the path and filename of the
+ database file you want rlm_dbm to look for users and groups in. This
+ file needs to be generated, either by the rlm_dbm_parse program or by
+ some custom program, for instance a Perl program using the DB_File or
+ GDBM_File <** modules.
+
+4. EXTERNAL UTILITIES
+
+ rlm_dbm_cat
+
+ rlm_dbm_cat: [-f file] [-w] [-i number] [-l number] [-v] [username ...]
+
+ rlm_dbm_cat simply lists the definition(s) of the username(s) or group
+ name(s), or the entire database. It takes the following options:
+
+ -f <filename>
+
+ The file name of the database to list.
+
+ -w
+ Long lines should be wrapped
+
+ -i <number>
+Set the left margin then wrapped.
+ -l <number>
+How long line should be to be wrapped (wrap threshold)
+
+ -v
+
+ Print the version number and exit.
+
+ rlm_dbm_parse
+
+ rlm_dbm_parser [-c] [-d raddb] [-i inputfile] [-o outputfile] [-x]
+ [-v] [-q] [username ...]
+
+ rlm_dbm_parses reads a file of the syntax defined below, and writes
+ a database file usable by rlm_dbm or edits current database.
+ It takes the following options:
+
+ -i <file>
+
+ Use <file> as the input file. If not defined then use standard input.
+
+ -o
+
+ Use <file> as the output file.
+
+ -c
+
+ Create a new database (empty output file before writing)
+
+ -x
+
+ Enable debug mode.
+; Multiple x flag increase debug level
+
+ -q
+
+ Do not print statistics (quiet).
+
+ -v
+
+ Print the version and exit.
+
+ -r
+
+ Remove a username or group name from the database.
+
+5. INPUT FORMAT
+
+ rlm_dbm_parse reads a format similar to the one used by the files
+ module. In incomplete RFC2234 ABNF, it looks like this:
+
+ entries = *entry
+ entry = identifier TAB definition
+ identifier = username / group-name
+ username = +PCHAR
+ groupname = +PCHAR
+ definition = (check-item ",")* LF ( *( reply-item ",") / ";" ) LF
+ check-item = AS IN FILES
+ reply-item = AS IN FILES
+
+*** need definition of username and groupname ***
+
+ As an example, these are the standard files definitions (files module).
+
+---8<---
+ DEFAULT Service-Type == Framed-User
+ Framed-IP-Address = 255.255.255.254,
+ Framed-MTU = 576,
+ Service-Type = Framed-User,
+ Fall-Through = Yes
+
+#except who call from number 555-666
+ DEFAULT Auth-Type := Reject,Service-Type ==Framed-User,
+ Calling-Station-ID == "555-666"
+
+#or call number 555-667
+ DEFAULT Auth-Type := Reject,Service-Type ==Framed-User,
+ Calling-Station-ID == "555-667"
+---8<---
+
+ To be a valid rlm_dbm input file, it should look like this:
+
+---8<---
+ DEFAULT Service-Type == Framed-User # (1)
+ Framed-IP-Address = 255.255.255.254, # comma, list cont'd
+ Framed-MTU = 576,
+ Service-Type = Framed-User,
+ Fall-Through = Yes # \n, end of list
+ Auth-Type := Reject,Service-Type ==Framed-User, # (2)
+ Calling-Station-ID == "555-666"
+ ; # ;, no reply items
+ Auth-Type := Reject,Service-Type ==Framed-User, # (3)
+ Calling-Station-ID == "555-667"
+ ; # ditto
+---8<---
+
+ This user (the DEFAULT user) contains three entries, 1, 2 and 3. The
+ first entry has a list of reply items, terminated by a reply item
+ without a trailing comma. Entries 2 and 3 has empty reply lists, as
+ indicated by the semicolon. This is necessary to separate an empty
+ line (which is ignored) from the empty list.
+ Definition Fall-Through = Yes used in order to say module to check next
+ record. By default Fall-Through = Yes.
+
+ Groups
+
+ This is implemented with the special User-Category attribute. Simply
+ set this as a reply item, and rlm_dbm will include the groups definition
+ when evaluating the check and reply items of the user. The group defined
+ the same way as users. Here is a short example:
+
+---8<---
+# group definitions
+gendialup
+ Service-Type = Framed-User,
+ Cisco-AVPair += "ip:addr-pool=SANDY",
+ Framed-Protocol = PPP
+
+locked Auth-Type := Reject
+ Reply-Message = "Your account has been disabled."
+
+# user definitions
+ssalex Auth-Type := Local, Password == "passs"
+ User-Category = "GenDialup"
+
+ssmike Auth-Type := Local, Password == "pass1"
+ User-Category = "Locked"
+---8<---
+
+6. ACKNOWLEDGMENTS
+
+ Author - Andrei Koulik <rlm_dbm@agk.nnov.ru>
+ Documentation - Bjørn Nordbø <bn@nextra.com>
+8. Bug reports:
+ rlm_dbm_bug@agk.nnov.ru
+
diff --git a/doc/modules/rlm_eap b/doc/modules/rlm_eap
new file mode 100644
index 0000000..4f903af
--- /dev/null
+++ b/doc/modules/rlm_eap
@@ -0,0 +1,395 @@
+
+
+ Extensible Authentication Protocol (EAP)
+
+
+INTRODUCTION
+
+ Extensible Authentication Protocol(EAP), rfc2284, is a general protocol
+ that allows network access points to support multiple authentication
+ methods. Each EAP-Type indicates a specific authentication mechanism.
+ 802.1x standard authenticates wireless LAN users trying to access
+ enterprise networks.
+
+ RADIUS attribute used for EAP is EAP-Message, 79(rfc2869). RADIUS
+ communicates all EAP messages by embedding them in this attribute.
+
+ General Terminology
+ Supplicant/EAP Client - is the software on the end-user/client machine
+ (machine with the wireless card).
+ Authenticator/NAS/Access Point(AP) - A network device providing users
+ with a point of entry into the network.
+ EAPOL - EAP over LAN as defined in 802.1x standard.
+ EAPOW - EAP over Wireless.
+
+
+ +----------+ +----------+ +----------+
+ | | EAPOL | | RADIUS | |
+ | EAP |<------>| Access |<------>| RADIUS |
+ | Client | EAPOW | Point | (EAP) | Server |
+ | | | | | |
+ +----------+ +----------+ +----------+
+
+
+ The sequence of events, for EAP-MD5, runs as follows:
+ 1. The end-user associates with the Access Point(AP).
+ 2. The supplicant specifies AP to use EAP by sending EAP-Start.
+ 3. AP requests the supplicant to Identify itself (EAP-Identity).
+ 4. Supplicant then sends its Identity (username) to the AP.
+ 5. AP forwards this EAP-response AS-IS to the RADIUS server.
+ (The supplicant and the RADIUS server mutually authenticate via AP.
+ AP just acts as a passthru till authentication is finished.)
+ 6. The server sends a challenge to the supplicant.
+ 7. The supplicant carries out a hash on the password and sends
+ this hashed password to the RADIUS server as its response.
+ 8. The RADIUS server performs a hash on the password for that supplicant
+ in its user database and compares the two hashed values and
+ authenticates the client if the two values match(EAP-Success/EAP-Failure)
+ 9. AP now opens a port to accept data from the end-user.
+
+ Currently, EAP is widely used in wireless networks than in wired networks.
+ In 802.11/wireless based networking, following sequence of events happen in
+ addition to the above EAP events.
+
+ 10. RADIUS server and the supplicant agree to a specific WEP key.
+ 11. The supplicant loads the key ready for logging on.
+ 12. The RADIUS server sends the key for this session (Session key) to the AP.
+ 13. The AP encrypts its Broadcast key with the Session key
+ 14. The AP sends the encypted key to the supplicant
+ 15. The supplicant decrypts the Broadcast key with the Session key and
+ the session continues using the Broadcast and Session keys until
+ the session ends.
+
+ References:
+ The Implementation of EAP over RADIUS is based on the following RFCs
+ rfc2869 -- RADIUS Extensions
+ rfc2284 -- PPP Extensible Authentication Protocol (EAP)
+ rfc2716 -- PPP EAP TLS Authentication Protocol
+
+ Following links help to understand HOW EAP works
+ www.ieee802.org/1/mirror/8021/docs2000/ieee_plenary.PDF
+
+
+EAP CODE ORGANIZATION
+
+ EAP is implemented as a module in freeradius
+ and the code is placed in src/modules/rlm_eap.
+ All EAP-Types are organized as subdirectories in rlm_eap/types/.
+
+ Each EAP-Type, like types/rlm_eap_md5, contains a chunk of code that
+ knows how to deal with a particular kind of authentication mechanism.
+
+ To add a new EAP-Type then a new directory should be created as
+ rlm_eap/types/rlm_eap_XXXX, where XXXX is EAP-Type name
+ ie for EAP-Type like ONE TIME PASSWORD (OTP) it would be rlm_eap_otp
+
+ src/modules/rlm_eap -- contains the basic EAP and generalized interfaces
+ to all the EAP-Types.
+ rlm_eap/types -- contains all the supported EAP-Types
+ rlm_eap/types/rlm_eap_md5 -- EAP-MD5 authentication.
+ rlm_eap/types/rlm_eap_tls -- EAP-TLS based authentication.
+ rlm_eap/types/rlm_eap_ttls -- TTLS based authentication.
+ rlm_eap/types/rlm_eap_peap -- Windows PEAP based authentication.
+ rlm_eap/types/rlm_eap_sim -- EAP-SIM (GSM) based authentication
+
+CONFIGURATION
+
+ Add the eap configuration stanza to the modules section in radiusd.conf
+ to load and control rlm_eap and all the supported EAP-Types:
+
+ For example:
+ modules {
+ ...
+ eap {
+ default_eap_type = md5
+
+ md5 {
+ }
+ ...
+ }
+ ...
+ }
+
+ NOTE: You cannot have empty eap stanza. At least one EAP-Type sub-stanza
+ should be defined as above, otherwise the server will not know what type
+ of eap authentication mechanism to be used and the server will exit
+ with error.
+
+ All the various options and their associated default values for each
+ EAP-Type are documented in the sample radiusd.conf that is provided
+ with the distribution.
+
+ Since the EAP requests may not contain a requested EAP type, the
+ 'default_eap_type' configuration options is used by the EAP module
+ to determine which EAP type to choose for authentication.
+
+ NOTE: EAP cannot authorize a user. It can only authenticate.
+ Other Freeradius modules authorize the user.
+
+
+EAP SIM server
+
+ To configure EAP-SIM authentication, the following attributes must be
+ set in the server. This can be done in the users file, but in many cases
+ will be taken from a database server, via one of the SQL interface.
+
+ If one has SIM cards that one controls (i.e. whose share secret you know),
+ one should be able to write a module to generate these attributes
+ (the triplets) in the server.
+
+ If one has access to the SS7 based settlement network, then a module to
+ fetch appropriate triplets could be written. This module would act as
+ an authorization only module.
+
+ The attributes are:
+ EAP-Sim-Rand1 16 bytes
+ EAP-Sim-SRES1 4 bytes
+ EAP-Sim-KC1 8 bytes
+ EAP-Sim-Rand2 16 bytes
+ EAP-Sim-SRES2 4 bytes
+ EAP-Sim-KC2 8 bytes
+ EAP-Sim-Rand3 16 bytes
+ EAP-Sim-SRES3 4 bytes
+ EAP-Sim-KC3 8 bytes
+
+ EAP-SIM will send WEP attributes to the resquestor.
+
+EAP CLIENTS
+
+ 1. eapol_test, from wpa_supplicant.
+
+ 2. Freeradius has an "radeapclient" that can do EAP-MD5 (passwords),
+ as well as EAP-SIM. It is in modules/rlm_eap/radeapclient.
+
+TESTING
+
+ You will find several test cases in src/tests/ for the EAP-SIM code.
+
+
+HOW DO I USE IT (FAQ/Examples)
+
+ 1. How can I enable EAP-MD5 authentication ?
+
+ In radiusd.conf
+
+ modules {
+ ...
+ eap {
+ default_eap_type = md5
+ md5 {
+ }
+ ...
+ }
+ ...
+ }
+
+ # eap sets the authenticate type as EAP
+ authorize {
+ ...
+ eap
+ }
+
+ # eap authentication takes place.
+ authenticate {
+ eap
+ }
+
+ # If you are proxying EAP-LEAP requests
+ # This is required to make LEAP work.
+ post-proxy {
+ eap
+ }
+
+ 2. My Userbase is in LDAP and I want to use EAP-MD5 authentication
+
+ In radiusd.conf
+
+ modules {
+ ...
+ eap {
+ default_eap_type = md5
+ md5 {
+ }
+ ...
+ }
+ ...
+ }
+
+ # ldap gets the Configured password.
+ # eap sets the authenticate type as EAP
+ authorize {
+ ...
+ ldap
+ eap
+ ...
+ }
+
+ # eap authentication takes place.
+ authenticate {
+ ...
+ eap
+ ...
+ }
+
+ 3. How can I Proxy EAP messages, with/without User-Name attribute
+ in the Access-Request packets
+
+ With User-Name attribute in Access-Request packet,
+ EAP-proxying is just same as RADIUS-proxying.
+
+ If User-Name attribute is not present in Access-Request packet,
+ Freeradius can proxy the request with the following configuration
+ in radiusd.conf
+
+ # eap module should be configured as the First module in
+ # the authorize stanza
+
+ authorize {
+ eap
+ ... other modules.
+ }
+
+ With this configuration, eap_authorize creates User-Name attribute
+ from EAP-Identity response, if it is not present.
+ Once User-Name attribute is created, RADIUS proxying takes care
+ of EAP proxying.
+
+ 4. How Freeradius can handle EAP-START messages ?
+
+ In most of the cases this is handled by the Authenticator.
+
+ Only if it is required then, in radiusd.conf
+
+ authorize {
+ eap
+ ... other modules.
+ }
+
+ With the above configuration, RADIUS server immediately responds with
+ EAP-Identity request.
+
+ NOTE: EAP does not check for any Identity or maintains any state in case
+ of EAP-START. It blindly responds with EAP-Identity request.
+ Proxying is handled only after EAP-Identity response is received.
+
+ 5. I want to enable multiple EAP-Types, how can I configure ?
+
+ In radiusd.conf
+
+ modules {
+ ...
+ eap {
+ default_eap_type = tls
+ md5 {
+ }
+ tls {
+ ...
+ }
+ ...
+ }
+ ...
+ }
+
+ The above configuration will let the server load all the EAP-Types,
+ but the server can have only one default EAP-Type, as above.
+
+ Once EAP-Identity response is received by the server, based on the
+ default_eap_type, the server will send a new request (MD5-Challenge
+ request incase of md5, TLS-START request incase of tls) to the supplicant.
+ If the supplicant is rfc2284 compliant and does not support the
+ EAP-Type sent by the server then it sends EAP-Acknowledge with the
+ supported EAP-Type. If this EAP-Type is supported by the server then it
+ will send the respective EAP-request.
+
+ Example: If the supplicant supports only EAP-MD5 but the server
+ default_eap_type is configured as EAP-TLS, as above, then the server
+ will send TLS-START after EAP-Identity is received. Supplicant will
+ respond with EAP-Acknowledge(EAP-MD5). Server now responds with
+ MD5-Challenge.
+
+
+INSTALLATION
+ EAP, EAP-MD5, and Cisco LEAP do not require any additional packages.
+ Freeradius contains all the required packages.
+
+ For EAP-TLS, EAP-TTLS, and PEAP, OPENSSL, <http://www.openssl.org/>,
+ is required to be installed.
+ Any version from 0.9.7, should fairly work with this module.
+
+ EAP-SIM should not require any additional packages.
+
+
+IMPLEMENTATION (For Developers)
+
+ The rlm_eap module only deals with EAP specific authentication mechanism
+ and the generic interface to interact with all the EAP-Types.
+
+ Currently, these are the existing interfaces,
+ int attach(CONF_SECTION *conf, void **type_arg);
+ int initiate(void *type_arg, EAP_HANDLER *handler);
+ int authenticate(void *type_arg, EAP_HANDLER *handler);
+ int detach(void **type_arg);
+
+ attach() and detach() functions allocate and deallocate all the
+ required resources.
+
+ initiate() function begins the conversation when EAP-Identity response
+ is received. Incase of EAP-MD5, initiate() function sends the challenge.
+
+ authenticate() function uses specific EAP-Type authentication mechanism
+ to authenticate the user. During authentication many EAP-Requests and
+ EAP-Responses takes place for each authentication. Hence authenticate()
+ function may be called many times. EAP_HANDLER contains the complete
+ state information required.
+
+
+HOW EAP WORKS
+ as posted to the list, by John Lindsay <jlindsay@internode.com.au>
+
+ To make it clear for everyone, the supplicant is the software on the
+ client (machine with the wireless card).
+
+ The EAP process doesn't start until the client has associated with
+ the Access Point using Open authentication. If this process isn't
+ crystal clear you need to go away and gain understanding.
+
+ Once the association is made the AP blocks all traffic that is not
+ 802.1x so although associated the connection only has value for EAP.
+ Any EAP traffic is passed to the radius server and any radius traffic
+ is passed back to the client.
+
+ So, after the client has associated to the Access Point, the
+ supplicant starts the process for using EAP over LAN by asking the
+ user for their logon and password.
+
+ Using 802.1x and EAP the supplicant sends the username and a one-way
+ hash of the password to the AP.
+
+ The AP encapsulates the request and sends it to the RADIUS server.
+
+ The radius server needs a plaintext password so that it can perform
+ the same one-way hash to determine that the password is correct. If
+ it is, the radius server issues an access challenge which goes back
+ via to the AP to the client. (my study guide says client but my
+ brain says 'supplicant')
+
+ The client sends the EAP response to the challenge via the AP to the
+ RADIUS server.
+
+ If the response is valid the RADIUS server sends a success message
+ and the session WEP key (EAP over wireless) to the client via the
+ AP. The same session WEP key is also sent to the AP in the success
+ packet.
+
+ The client and the AP then begin using session WEP keys. The WEP key
+ used for multicasts is then sent from the AP to the client. It is
+ encrypted using the session WEP key.
+
+ACKNOWLEDGEMENTS
+ Primary author - Raghu <raghud@mail.com>
+
+ EAP-SIM - Michael Richardson <mcr@sandelman.ottawa.on.ca>
+ The development of the EAP/SIM support was funded by
+ Internet Foundation Austria (http://www.nic.at/ipa).
+
+
diff --git a/doc/modules/rlm_expiration b/doc/modules/rlm_expiration
new file mode 100644
index 0000000..eb7918b
--- /dev/null
+++ b/doc/modules/rlm_expiration
@@ -0,0 +1,23 @@
+Module to expire user accounts.
+
+This module can be used to expire user accounts. Expired users receive
+an Access-Reject on every authentication attempt. Expiration is based
+on the Expiration attribute which should be present in the check item
+list for the user we wish to perform expiration checks.
+
+
+
+Expiration attribute format:
+
+You can use Expiration := "23 Sep 2004" and the user will
+no longer be able to connect at 00:00 (midnight) on September 23rd,
+2004. If you want a certain time (other than midnight) you can do
+use Expiration := "23 Sep 2004 12:00".
+The nas will receive a Session-Timeout attribute calculated to kick
+the user off when the Expiration time occurs.
+
+
+
+Example entry (users files):
+
+user1 Expiration := "23 Sep 2004"
diff --git a/doc/modules/rlm_krb5 b/doc/modules/rlm_krb5
new file mode 100644
index 0000000..d70017f
--- /dev/null
+++ b/doc/modules/rlm_krb5
@@ -0,0 +1,47 @@
+The `rlm_krb5` FreeRADIUS module enables the use of Kerberos 5 for
+authentication.
+
+Compilation issues
+==================
+
+MIT libraries
+-------------
+
+The `rlm_krb5` module, by default, presumes you have the MIT Kerberos 5
+distribution. Notes from that distribution:
+
+On linux, you may have to change:
+
+ deplibs_test_method="pass_all"
+
+in `../libtool`
+
+Otherwise, it complains if the krb5 libs aren't shared.
+
+Heimdal libraries
+-----------------
+
+If you are using the Heimdal Kerberos 5 distribution, pass an
+`--enable-heimdal-krb5` option to `configure`.
+
+Configuration parameters
+========================
+
+You can configure the module with the following parameters:
+
+ krb5 {
+ # Keytab containing the key used by rlm_krb5
+ keytab = /path/to/keytab
+
+ # Principal that is used by rlm_krb5
+ service_principal = radius/some.host.com
+ }
+
+Make sure the keytab is readable by the user that is used to run `radiusd` and
+that your authorization configuration really uses `rlm_krb5` to do the
+authentication. You will need to add the following to the 'authenticate'
+section of your radiusd.conf file:
+
+ Auth-Type Kerberos {
+ krb5
+ }
diff --git a/doc/modules/rlm_pam b/doc/modules/rlm_pam
new file mode 100644
index 0000000..8a6673c
--- /dev/null
+++ b/doc/modules/rlm_pam
@@ -0,0 +1,108 @@
+
+ PAM Support for FreeRadius
+
+
+0. INTRODUCTION
+
+ PAM support was done by Jeph Blaize. Miguel a.l. Paraz <map@iphil.net>
+ ported it to FreeRADIUS' parent, Cistron-Radius. Chris Dent <cdent@kiva.net>
+ added the Pam-Auth attribute.
+
+1. USAGE
+
+ Use Auth-Type = Pam in the users file. You cannot use User-Password = "PAM"
+ as in other radius servers. Sorry.
+
+ You can also use ``Pam-Auth = "somestring"'' to specify an entry in
+ /etc/pam.d. The default is "radius".
+
+ Compile and install freeradius with pam support (./configure --help
+ will tell you how)
+
+ Within your radiusd.conf file, in the 'modules' section, make sure
+ that the pam section is enabled:
+
+ pam {
+ #
+ # The name to use for PAM authentication.
+ # PAM looks in /etc/pam.d/${pam_auth_name}
+ # for it's configuration.
+ #
+ # Note that any Pam-Auth attribute set in the 'users'
+ # file over-rides this one.
+ #
+ pam_auth = radiusd
+ }
+
+ In the 'authenticate' section, do the same:
+
+ authenticate {
+ # Uncomment this if you want to use PAM (Auth-Type = PAM)
+ pam
+ ...
+
+
+ In your /etc/pam.d/ directory create a file called radiusd with the
+ following contents (or whatever you want for your pam configuration,
+ this seems to work for me):
+
+#%PAM-1.0
+auth required /lib/security/pam_unix_auth.so shadow md5 nullok
+auth required /lib/security/pam_nologin.so
+account required /lib/security/pam_unix_acct.so
+password required /lib/security/pam_cracklib.so
+password required /lib/security/pam_unix_passwd.so shadow md5 nullok use_authtok
+session required /lib/security/pam_unix_session.so
+
+
+ If you don't want to run your freeradius server in debug mode as
+ root (ie, run as an unpriviledged user) you will need to run
+ freeradius with a group membership that is able to read the
+ /etc/shadow file - otherwise pam will be unable to read the
+ /etc/shadow file and will fail. I suggest a group called 'shadow' or
+ the like.
+
+ $ chgrp /etc/shadow shadow
+ $ chmod g+w /etc/shadow
+
+ And in the radiusd.conf file:
+
+ # On systems with shadow passwords, you might have to set 'group = shadow'
+ # for the server to be able to read the shadow password file.
+ #
+ # Change below to suit your setup.
+ user = radius
+ group = shadow
+
+
+ Please understand that giving anything except root read permissions
+ to the /etc/shadow file is something that you want to think a bit
+ upon!!
+
+2. NOTES
+
+ None.
+
+3. TODO:
+
+ Real PAM support, figure out how we can write a module that will make
+ it blend in with PAM more seamlessly. With this, we can replace the
+ DENY_SHELL with something more flexible such as a database.
+
+4. EXAMPLE:
+
+DEFAULT Auth-Type = Pam, NAS-IP-Address = 206.97.64.5
+ Service-Type = Framed-User,
+ Framed-Protocol = PPP,
+ Framed-IP-Address = 255.255.255.254,
+ Filter-Id = "std.ppp",
+ Framed-MTU = 1500,
+ Framed-Compression = Van-Jacobson-TCP-IP
+DEFAULT Auth-Type = Pam, Pam-Auth = "radius2", NAS-IP-Address = 127.0.0.1
+ Service-Type = Framed-User,
+ Framed-Protocol = PPP,
+ Framed-IP-Address = 255.255.255.254,
+ Filter-Id = "std.ppp",
+ Framed-MTU = 1500,
+ Framed-Compression = Van-Jacobson-TCP-IP
+
diff --git a/doc/modules/rlm_passwd b/doc/modules/rlm_passwd
new file mode 100644
index 0000000..59f4a59
--- /dev/null
+++ b/doc/modules/rlm_passwd
@@ -0,0 +1,50 @@
+RADIUS rlm_passwd (passwd-like files authorization module)
+
+FAQ
+
+Q: Can I use rlm_passwd to authenticate user against Linux shadow password
+ file or BSD-style master.passwd?
+A: Yes, but you need RADIUS running as root. Hint: use Crypt-Password
+ attribute. You probably don't want to use this module with
+ FreeBSD to authenticate against system file, as it already takes care
+ of caching passwd file entries, but it may be helpfull to authenticate
+ against alternate file.
+
+Q: Can I use rlm_passwd to authenticate user against SAMBA smbpasswd?
+A: Yes, you can. Hint: use LM-Password/NT-Password attribute, set
+ authtype = MS-CHAP.
+
+Q: Can I use rlm_password to authenticate user against BLA-BLA-BLApasswd?
+A: Probably you can, if BLA-BLA-BLA stores password in some format supported
+ by RADIUS, for example cleartext, NT/LM hashes, crypt, Netscape MD5 format.
+ You have to set authtype to corresponding type, for example
+ authtype = NS-MTA-MD5
+ for Netscape MD5.
+
+Q: Are where are differences between rlm_passwd and rlm_unix?
+A: rlm_passwd supports passwd files in any format and may be used, for
+ example, to parse FreeBSD's master.passwd or SAMBA smbpasswd files, but
+ it can't perform system authentication (for example to authenticate
+ NIS user, like rlm_unix does). If you need system authentication you
+ need rlm_unix, if you have to authenticate against files only under
+ BSD you need rlm_passwd, if you need to authenticate against files only
+ under Linux, you can choose between rlm_unix and rlm_passwd, probably
+ you will have nearly same results in performance (I hope :) ).
+
+Q: I'm using realms with rlm_passwd. I see rlm_passwd do not strip realm
+ from user name. How to configure rlm_passwd to strip realm?
+
+A: In case you configured realm to strip username, User-Password attribute
+ is not changed. Instead, rlm_realm creates new attribute Stripped-User-Name.
+ All you need is to use Stripped-User-Name instead of User-Name as a key
+ field for passwd file.
+
+Q: How can I say passwd to add attribute even if it's value is empty?
+
+A: set ignore_empty to "no" in module configuration.
+
+
+5. Acknowlegements:
+
+ ZARAZA, <3APA3A@security.nnov.ru>
+ Michael Chernyakhovsky <mike@mgn.ru> - reply-items support
diff --git a/doc/modules/rlm_python b/doc/modules/rlm_python
new file mode 100644
index 0000000..ef35f1b
--- /dev/null
+++ b/doc/modules/rlm_python
@@ -0,0 +1,76 @@
+Python module for freeradius
+Copyright 2002 Miguel A Paraz <mparaz@mparaz.com>
+Copyright 2002 Imperium Technology, Inc.
+
+PURPOSE:
+To allow module writers to write modules in a high-level language,
+for implementation or for prototyping.
+
+REQUIRES:
+Python - tested with 2.2
+
+BUILDING:
+./configure --with-experimental-modules
+
+
+USAGE:
+Make your module available to the Python interpreter by either putting it
+in a standard location, or 'EXPORT PYTHONPATH=$location'.
+
+
+
+
+
+BUGS:
+1. Can't compile statically (./configure --enable-shared=no) - causes
+SIGSEGV on the first malloc() in main().
+
+Design:
+1. Support for all module functions.
+2. One module per function allowed, for example, from experimental.conf:
+
+ python {
+ mod_instantiate = radiusd_test
+ func_instantiate = instantiate
+
+ mod_authorize = radiusd_test
+ func_authorize = authorize
+
+ mod_accounting = radiusd_test
+ func_accounting = accounting
+
+ mod_preacct = radiusd_test
+ func_preacct = preacct
+
+ mod_detach = radiusd_test
+ func_detach = detach
+
+ }
+
+
+3. Different functions are wrappers around the same core.
+4. func_detach is passed no parameters, returns module return value.
+5. If functions returns None (plain 'return' no return), default to RLM_OK
+6. Python instantation function can return -1 to signal failure and abort
+ startup.
+
+Available to module:
+import radiusd
+radiusd.rad_log(radiusd.L_XXX, message_string)
+radiusd.RLM_XXX
+
+
+
+TODO:
+1. Do we need to support other pair operations beyond set (:=) ?
+2. Should we pass the value pair info as a dict and not a tuple? Faster?
+2. Give access to more radiusd variables like the dictionary.
+3. Give access to other C functions.
+ Let the Python module deal with the structures directly, instead of
+ letting our C code do it afterwards.
+ What's a good way to represent this?
+
+
+
+
+
diff --git a/doc/modules/rlm_soh b/doc/modules/rlm_soh
new file mode 100644
index 0000000..eda5c4c
--- /dev/null
+++ b/doc/modules/rlm_soh
@@ -0,0 +1,183 @@
+== Intro ==
+
+This release adds support for Microsoft Statement-of-Health (SoH), which is
+a form of network access protection.
+
+Client support is present in Windows XP SP3, Vista and 7.
+
+SoH data can come in from several places:
+
+ * inside EAP-PEAP packets for 802.1x wireless/wired connections
+ * inside a radius packet (Microsoft VSA #55, MS-Quarantine-SOH) - VPN and
+ terminal services gateways can act as the radius client
+ * inside a DHCP request, in vendor-specific options
+
+FreeRadius supports all three types. The SoH statement is decoded into
+radius-style attributes, and you can write a policy in "unlang" to act
+on them, and permit, restrict or deny network access.
+
+== PEAP support ==
+
+SoH support in peap is enabled in eap.conf using config like so:
+
+ eap {
+ peap {
+ soh = yes
+ soh_virtual_server = "soh-server"
+ }
+ }
+
+When SoH is enabled, an EAP-PEAP client will be challenged to provide an
+SoH statement after providing it's identity (or resuming a PEAP session via
+SSL session resumption). Clients which do not support PEAP will NAK the
+request, and clients which do will answer it.
+
+The client reply will be written into a fake radius request and sent to the
+virtual server specified above; it will either look like:
+
+ SoH-Supported = no
+
+...or (from a Vista machine):
+
+ SoH-Supported = yes
+ SoH-MS-Machine-OS-vendor = Microsoft
+ SoH-MS-Machine-OS-version = 6
+ SoH-MS-Machine-OS-release = 0
+ SoH-MS-Machine-OS-build = 6001
+ SoH-MS-Machine-SP-version = 1
+ SoH-MS-Machine-SP-release = 0
+ SoH-MS-Machine-Processor = x86_64
+ SoH-MS-Machine-Name = "netbios.example.com"
+ SoH-MS-Correlation-Id = 0x54468936cb494374b127a6a3cc3bb11c01ca78d858ee1ef0
+ SoH-MS-Machine-Role = client
+ SoH-MS-Windows-Health-Status = "firewall ok snoozed=0 microsoft=1 up2date=1 enabled=1"
+ SoH-MS-Windows-Health-Status = "antivirus error not-installed"
+ SoH-MS-Windows-Health-Status = "antispyware ok snoozed=0 microsoft=1 up2date=1 enabled=1"
+ SoH-MS-Windows-Health-Status = "auto-updates ok action=install"
+ SoH-MS-Windows-Health-Status = "security-updates warn some-missing"
+
+If you have "copy_request_to_tunnel = yes" set on the peap module, the
+request variables like NAS-IP-Address and so on will be copied to the fake
+request as well.
+
+Clients without SoH seem to just NAK the SoH request and continue with the inner
+EAP auth. This has been tested as working with Windows XP SP2 and lower, Linux
+clients using NetworkManager & wpa_supplicant, MacOS 10.5, Nokia/Symbian S60 and
+iPhone OS 3.x. It should therefore be safe to deploy.
+
+== Radius support ==
+
+If you are running a Microsoft VPN or Terminal Services Gateway, these can
+be configured to send the SoH data to an upstream radius server, in this
+case presumably FreeRadius. To take advantage of this you will need to add
+the "soh" module to the "authorize" section of your virtual server, like so:
+
+server tsgateway {
+ preprocess
+ soh
+ if () {
+ ... policy goes here
+ }
+}
+
+The SoH module simply looks for the Microsoft VSA #55 and decodes the SoH
+data, adding the SoH attributes to the request - see above for an example
+of the available attributes.
+
+The SoH module also does dynamic expansions - see below for more info.
+
+== DHCP support ==
+
+If you compile FreeRadius with DHCP support, the "soh" module can challenge
+a DHCP client for SoH data in the DHCPOFFER packet. As with normal radius,
+the SoH attributes are added to the request. You would use like so:
+
+server dhcp {
+ dhcp DHCP-Discover {
+ soh
+ # note - no SoH attributes are added here, the client hasn't sent them yet
+
+ # other DHCP config
+ }
+
+ dhcp DHCP-Request {
+ soh
+ if () {
+ # SoH policy
+ }
+ # other DHCP config
+ }
+}
+
+== soh module ==
+
+The "soh" module decodes the radius & DHCP payloads. It also makes some dynamic
+variables available, for example:
+
+authorize {
+ soh
+ update request {
+ Tmp-String-0 = "%{soh:OS}"
+ }
+}
+
+...will give you a string like "Windows Vista 6.1.100 sp 1.0" or "Windows XP 5.x.x sp 3.0"
+
+At the moment, this is the only dynamic expansion; in future, we will make
+various bits of info available, for example non-Microsoft SoH records (see below)
+
+== Non-microsoft SoH data ==
+
+The Windows SoH structure is extensible and, in principle, clients can be
+extended with .dll plugins to add vendor-specific info to the SoH, which
+can then be checked on the server.
+
+At the present time, few plugins are known and I have seen none, so can't
+add support for them.
+
+== Client configuration ==
+
+The code works fine with Win XP SP3 & Vista on both wired & wireless. However
+contrary to what some sites claim, the NAP service is disabled by default, as
+are the many NAP remediation agents. These can be enabled from the command prompt
+with (for XP; instructions may differ for other windows versions):
+
+ sc config napagent start= auto
+ sc start napagent
+
+ # optionally for wired 802.1x; the dot3svc should usually be made dependent
+ # on the napagent service, else the machine might attempt 802.1x before NAP
+ # has started...
+
+ sc config dot3svc start= auto depend= napagent
+ sc start dot3svc
+
+ # enable the EAP agent
+ netsh nap client show config
+
+ # get the "ID" value for the "EAP Quarantine Enforcement Client"
+ netsh nap client set enforce id=$ID admin=enable
+
+ # repeat for DHCP, VPN or Terminal Services agents
+
+This can be automated via Group Policy.
+
+You then need to enable EAP, PEAP, Quarantine Checks & the relevant auth method
+on the relevant adapters. This can be done with "netsh xml profiles" or Group
+Policy - google for the relevant terms, or see the MS article:
+
+ http://technet.microsoft.com/en-us/library/bb726965.aspx
+
+...and related links.
+
+== TODO ==
+
+Currently the code does not support sending the final SoH reply. This
+is because the SoH reply (see section 2.2.9 of MS-SOH version
+v20091104) needs various fields formatted in a manner which is not
+obvious to me, and I don't currently have access to a windows NAP
+server to look at a working example. The clients I have access don't
+seem to mind.
+
+ Phil Mayers <p.mayers@imperial.ac.uk>
+ December 2009
diff --git a/doc/modules/rlm_sql b/doc/modules/rlm_sql
new file mode 100644
index 0000000..0f06660
--- /dev/null
+++ b/doc/modules/rlm_sql
@@ -0,0 +1,283 @@
+ SQL Module
+
+0. Introduction
+
+ The SQL module is composed of two parts: a generic SQL front-end
+ (rlm_sql), and a series of database-dependent back-end drivers,
+ (rlm_sql_mysql, rlm_sql_postgresql, etc.)
+
+ In order to build the drivers, you MUST ALSO install the development
+ versions of the database. That is, you must have the appropriate
+ header files and client libraries for (say) MySQL. The
+ rlm_sql_mysql driver is NOT a complete MySQL client implementation.
+ Instead, it is a small 'shim' between the FreeRADIUS rlm_sql module,
+ and the MySQL client libraries.
+
+
+ In general, the SQL schemas mirror the layout of the 'users' file.
+ So for configuring check items and reply items, see 'man 5 users',
+ and the examples in the 'users' file.
+
+
+1. Schema and usage
+
+ The schemas are available in raddb/sql/<DB>/*, where <DB> is the
+ name of the database (mysql, postgresql, etc.)
+
+ The SQL module employs two sets of check and reply item tables for
+ processing in the authorization stage. One set of tables (radcheck and
+ radreply) are specific to a single user. The other set of tables
+ (radgroupcheck and radgroupreply) is used to apply check and reply items
+ to users that are members of a certain SQL group. The usergroup table
+ provides the list of groups each user is a member of along with a priority
+ field to control the order in which groups are processed.
+
+ When a request comes into the server and is processed by the SQL module,
+ the flow goes something like this:
+
+ 1. Search the radcheck table for any check attributes specific to the user
+ 2. If check attributes are found, and there's a match, pull the reply items
+ from the radreply table for this user and add them to the reply
+ 3. Group processing then begins if any of the following conditions are met:
+ a. The user IS NOT found in radcheck
+ b. The user IS found in radcheck, but the check items don't match
+ c. The user IS found in radcheck, the check items DO match AND
+ Fall-Through is set in the radreply table
+ d. The user IS found in radcheck, the check items DO match AND
+ the read_groups directive is set to 'yes'
+ 4. If groups are to be processed for this user, the first thing that is
+ done is the list of groups this user is a member of is pulled from the
+ usergroup table ordered by the priority field. The priority field of
+ the usergroup table allows us to control the order in which groups are
+ processed, so that we can emulate the ordering in the users file. This
+ can be important in many cases.
+ 5. For each group this user is a member of, the corresponding check items
+ are pulled from radgroupcheck table and compared with the request. If
+ there is a match, the reply items for this group are pulled from the
+ radgroupreply table and applied.
+ 6. Processing continues to the next group IF:
+ a. There was not a match for the last group's check items OR
+ b. Fall-Through was set in the last group's reply items
+ (The above is exactly the same as in the users file)
+ 7. Finally, if the user has a User-Profile attribute set or the Default
+ Profile option is set in the sql.conf, then steps 4-6 are repeated for
+ the groups that the profile is a member of.
+
+ For any fairly complex setup, it is likely that most of the actual
+ processing will be done in the groups. In these cases, the user entry in
+ radcheck will be of limited use except for things like setting the user's
+ password. So, one might have the following setup:
+
+ radcheck table:
+ joeuser Cleartext-Password := somepassword
+
+ radreply table:
+ joeuser Fall-Through = Yes
+
+ radgroupcheck table:
+ Check items for various connection scenarios
+
+ radgroupreply table:
+ reply items for the groups
+
+ usergroup table:
+ joeuser WLANgroup 1(this is the priority)
+ joeuser PPPgroup 2
+
+
+2. What NOT to do.
+
+ One of the fields of the SQL schema is named 'op' This is for the
+ 'operator' used by the attributes. e.g.:
+
+ Framed-IP-Address = 1.2.3.4
+ ^ ATTRIBUTE ----^ ^ OP ^ VALUE
+
+ If you want the server to be completely misconfigured, and to never
+ do what you want, leave the 'op' field blank. If you want to be
+ rudely told to RTFM, then post questions on the mailing list, asking
+
+ "why doesn't my SQL configuration work when I leave the 'op' field empty?"
+
+
+ The short answer is that with the op field empty, the server does
+ not know what you want it to do with the attribute. Should it be
+ added to the reply? Maybe you wanted to compare the operator to one
+ in the request? The server simply doesn't know.
+
+ So put a value in the field. The value is the string form of the
+ operator: "=", ">=", etc. See Section 4, below, for more details.
+
+
+3. Authentication versus Authorization
+
+ Many people ask if they can "authenticate" users to their SQL
+ database. The answer to this question is "You're asking the wrong
+ question."
+
+ An SQL database stores information. An SQL database is NOT an
+ authentication server. The ONLY users who should be able to
+ authenticate themselves to the database are the people who
+ administer it. Most administrators do NOT want every user to be
+ able to access the database, which means that most users will not be
+ able to "authenticate" themselves to the database.
+
+ Instead, the users will have their authorization information (name,
+ password, configuration) stored in the database. The configuration
+ files for FreeRADIUS contain a username and password used to
+ authenticate FreeRADIUS to the SQL server. (See raddb/sql.conf).
+ Once the FreeRADIUS authentication server is connected to the SQL
+ database server, then FreeRADIUS can pull user names and passwords
+ out of the database, and use that information to perform the
+ authentication.
+
+4. Operators
+
+ The list of operators is given below.
+
+ Op Example and documentation
+ -- -------------------------
+
+ = "Attribute = Value"
+
+ Not allowed as a check item for RADIUS protocol attributes. It is
+ allowed for server configuration attributes (Auth-Type, etc), and sets
+ the value of on attribute, only if there is no other item of the
+ same attribute.
+
+ As a reply item, it means "add the item to the reply list, but
+ only if there is no other item of the same attribute."
+
+
+ := "Attribute := Value"
+
+ Always matches as a check item, and replaces in the
+ configuration items any attribute of the same name. If no
+ attribute of that name appears in the request, then this
+ attribute is added.
+
+ As a reply item, it has an identical meaning, but for the
+ reply items, instead of the request items.
+
+ == "Attribute == Value"
+
+ As a check item, it matches if the named attribute is present
+ in the request, AND has the given value.
+
+ Not allowed as a reply item.
+
+
+ += "Attribute += Value"
+
+ Always matches as a check item, and adds the current attribute
+ with value to the list of configuration items.
+
+ As a reply item, it has an identical meaning, but the
+ attribute is added to the reply items.
+
+
+ != "Attribute != Value"
+
+ As a check item, matches if the given attribute is in the
+ request, AND does not have the given value.
+
+ Not allowed as a reply item.
+
+
+ > "Attribute > Value"
+
+ As a check item, it matches if the request contains an
+ attribute with a value greater than the one given.
+
+ Not allowed as a reply item.
+
+
+ >= "Attribute >= Value"
+
+ As a check item, it matches if the request contains an
+ attribute with a value greater than, or equal to the one
+ given.
+
+ Not allowed as a reply item.
+
+ < "Attribute < Value"
+
+ As a check item, it matches if the request contains an
+ attribute with a value less than the one given.
+
+ Not allowed as a reply item.
+
+
+ <= "Attribute <= Value"
+
+ As a check item, it matches if the request contains an
+ attribute with a value less than, or equal to the one given.
+
+ Not allowed as a reply item.
+
+
+ =~ "Attribute =~ Expression"
+
+ As a check item, it matches if the request contains an
+ attribute which matches the given regular expression. This
+ operator may only be applied to string attributes.
+
+ Not allowed as a reply item.
+
+
+ !~ "Attribute !~ Expression"
+
+ As a check item, it matches if the request contains an
+ attribute which does not match the given regular expression.
+ This operator may only be applied to string attributes.
+
+ Not allowed as a reply item.
+
+
+ =* "Attribute =* Value"
+
+ As a check item, it matches if the request contains the named
+ attribute, no matter what the value is.
+
+ Not allowed as a reply item.
+
+
+ !* "Attribute !* Value"
+
+ As a check item, it matches if the request does not contain
+ the named attribute, no matter what the value is.
+
+ Not allowed as a reply item.
+
+5. Instances
+
+ Just like any other module, multiple instances of the rlm_sql
+ module can be defined and used wherever you like.
+
+ The default .conf files for the different database types,
+ contain 1 instance without a name like so:
+ sql {
+ ...
+ }
+
+ You can create multiple named instances like so:
+ sql sql_instance1 {
+ ...
+ }
+ sql sql_instance2 {
+ ...
+ }
+
+ And then you can use a specific instance in radiusd.conf, like
+ so:
+ authorize {
+ ...
+ sql_instance1
+ ...
+ }
+ accounting {
+ ...
+ sql_instance1
+ sql_instance2
+ ...
+ }
diff --git a/doc/modules/rlm_sqlcounter b/doc/modules/rlm_sqlcounter
new file mode 100644
index 0000000..54ad170
--- /dev/null
+++ b/doc/modules/rlm_sqlcounter
@@ -0,0 +1,182 @@
+rlm_sqlcounter installation and running guide
+by Ram Narula ram@princess1.net
+Internet for Education (Thailand)
+
+*) Pre-requisites:
+Make sure to have configured radiusd with rlm_sqlcounter
+installed
+
+> make clean
+> ./configure --with-experimental-modules
+> make
+> make install
+
+Make sure to have radiusd running properly under sql
+and there must be a "sql" entry under accounting{ } section
+of radiusd.conf
+
+*) Configuration:
+
+[1] Create a text file called sqlcounter.conf in the same
+directory where radiusd.conf resides (usually /usr/local/etc/raddb)
+with the following content (for mysql):
+
+#-----#
+sqlcounter noresetcounter {
+ sql_module_instance = sqlcca3
+ counter_name = Max-All-Session-Time
+ check_name = Max-All-Session
+ reply_name = Session-Timeout
+ key = User-Name
+ reset = never
+
+ query = "SELECT SUM(AcctSessionTime) FROM radacct WHERE UserName='%{%k}'"
+
+ }
+
+
+sqlcounter dailycounter {
+ sql_module_instance = sqlcca3
+ driver = "rlm_sqlcounter"
+ counter_name = Daily-Session-Time
+ check_name = Max-Daily-Session
+ reply_name = Session-Timeout
+ key = User-Name
+ reset = daily
+
+ query = "SELECT SUM(AcctSessionTime - GREATEST((%b - UNIX_TIMESTAMP(AcctStartTime)), 0)) FROM radacct WHERE UserName='%{%k}' AND UNIX_TIMESTAMP(AcctStartTime) + AcctSessionTime > '%b'"
+
+ }
+
+sqlcounter monthlycounter {
+ sql_module_instance = sqlcca3
+ counter_name = Monthly-Session-Time
+ check_name = Max-Monthly-Session
+ reply_name = Session-Timeout
+ key = User-Name
+ reset = monthly
+
+ query = "SELECT SUM(AcctSessionTime - GREATEST((%b - UNIX_TIMESTAMP(AcctStartTime)), 0)) FROM radacct WHERE UserName='%{%k}' AND UNIX_TIMESTAMP(AcctStartTime) + AcctSessionTime > '%b'"
+
+ }
+
+#-----#
+
+The respective lines for postgresql are:
+
+query = "SELECT SUM(AcctSessionTime) FROM radacct WHERE UserName='%{%k}'"
+query = "SELECT SUM(AcctSessionTime - GREATEST((%b - EXTRACT(epoch FROM AcctStartTime)), 0)) FROM radacct WHERE UserName='%{%k}' AND EXTRACT(epoch FROM AcctStartTime) + AcctSessionTime > '%b'"
+query = "SELECT SUM(AcctSessionTime - GREATEST((%b - EXTRACT(epoch FROM AcctStartTime)), 0)) FROM radacct WHERE UserName='%{%k}' AND EXTRACT(epoch FROM AcctStartTime) + AcctSessionTime > '%b'"
+
+If you are running postgres 7.x, you may not have a GREATEST function.
+
+An example of one is:
+
+CREATE OR REPLACE FUNCTION "greater"(integer, integer) RETURNS integer AS '
+DECLARE
+ res INTEGER;
+ one INTEGER := 0;
+ two INTEGER := 0;
+BEGIN
+ one = $1;
+ two = $2;
+ IF one IS NULL THEN
+ one = 0;
+ END IF;
+ IF two IS NULL THEN
+ two = 0;
+ END IF;
+ IF one > two THEN
+ res := one;
+ ELSE
+ res := two;
+ END IF;
+ RETURN res;
+END;
+' LANGUAGE 'plpgsql';
+
+[2] Include the above file to radiusd.conf by adding a line in
+modules{ } section
+
+modules {
+
+$INCLUDE ${confdir}/sqlcounter.conf
+
+...some other entries here...
+
+[3] Make sure to have the sqlcounter names under authorize section
+like the followings:
+
+authorize {
+...some entries here...
+...some entries here...
+...some entries here...
+...some entries here...
+
+noresetcounter
+dailycounter
+monthlycounter
+}
+
+noresetcounter: the counter that never resets, can be used
+for real session-time cumulation
+
+dailycounter: the counter that resets everyday, can be used
+for limiting daily access time (eg. 3 hours a day)
+
+monthlycounter: the counter that resets monthly, can be used for
+limiting monthly access time (eg. 50 hours per month)
+
+You can make your own names and directives for resetting the counter
+by reading the sample sqlcounter configuration in
+raddb/experimental.conf
+
+
+
+*) Implementation:
+
+Add sqlcounter names to be used into radcheck or radgroupcheck
+table appropriately for sql. For users file just follow the
+example below.
+
+Note: The users in the example below must be able to login
+normally as the example will only show how to apply sqlcounter
+counters.
+
+Scenarios
+[1] username test0001 have total time limit of 15 hours
+(user can login as many times as needed but can be online for
+total time of 15 hours which is 54000 seconds)
+If using normal users file authentication the entry can look like:
+
+test0001 Max-All-Session := 54000, User-Password == "blah"
+ Service-Type = Framed-User,
+ Framed-Protocol = PPP
+
+or for sql make sure to have Max-All-Session entry under either
+radcheck or radgroup check table:
+> INSERT into radcheck VALUES ('','test0001','Max-All-Session','54000',':=');
+
+[2] username test0002 have total time limit of 3 hours a day
+
+test0002 Max-Daily-Session := 10800, User-Password == "blah"
+ Service-Type = Framed-User,
+ Framed-Protocol = PPP
+or in sql:
+> INSERT into radcheck VALUES ('','test0002','Max-Daily-Session','10800',':=');
+
+
+[3] username test0003 have total time limit of 90 hours a month
+
+test0003 Max-Monthly-Session := 324000, User-Password == "blah"
+ Service-Type = Framed-User,
+ Framed-Protocol = PPP
+in sql:
+> INSERT into radcheck VALUES ('','test0003','Max-Monthly-Session','10800',':=');
+
+
+Note that Max-All-Session, Max-Daily-Session and Max-Monthly-Session are
+definied in sqlcounter.conf
+
+VERY IMPORTANT:
+Accounting must be done via sql or this will not work.
diff --git a/doc/modules/rlm_sqlippool b/doc/modules/rlm_sqlippool
new file mode 100644
index 0000000..3d2840f
--- /dev/null
+++ b/doc/modules/rlm_sqlippool
@@ -0,0 +1,40 @@
+Welcome to the SQL Based IP Pool module.
+
+**********************************************************************
+As of September 2006 this module is still under some development and
+currently is only tested by the developers on PostgreSQL (Version 8.1)
+ Use it at your own risk!
+If plan to attempt to use a DB other than PostgreSQL please expect to
+have to do extra work which is not for SQL newbies.
+Having said that it works great for us in production and should (with
+some work) function correctly with other SQL server types.
+**********************************************************************
+
+
+To use the sqlipool module you simply need to have an IP-Pool Attribute
+(Keep in mind that its a **CHECK** item, not reply) in the required
+configuration file, which is either in files(users), sql or any other
+type of configuration schema.
+
+The initialization of the radippool table is left to the user instead of
+being handled inside the module. This allows pool management to be done
+from any sql capable programming language and pools can be created,
+resized, deleted at run time without radiusd needing to be restarted.
+
+The only required fields are, pool_name and ip_address. A pool consists
+of one or more rows in the table with the same pool_name and a different
+ip_address. There is no restriction on which ip addresses/ranges may be in
+the same pool, and addresses do not need to be concurrent.
+
+We are currently using the variable definitions of the xlat module, so
+before editing the sqlippool.conf file, please go and read the
+variables.rst in the doc/configuration directory. It will help you alot!..
+
+As you may noticed, there is a pool-key variable in the config file which
+allows you to select which attribute is unique according to your NAS setup.
+On a standard dialup NAS this is going to be "NAS-Port" but on an ethernet
+or wireless network it will probably be "Calling-Station-Id". Other more
+exotic options like "3GPP-IMSI" may also exist depending on your NAS.
+The only requirement is that the pool-key must be unique and must be
+received in both Access-Request and Accounting packages so that we know to
+clear the lease on the ip when the session disconnects.
diff --git a/doc/schemas/ldap/edir/freeradius-clients.ldif b/doc/schemas/ldap/edir/freeradius-clients.ldif
new file mode 100644
index 0000000..96a0f44
--- /dev/null
+++ b/doc/schemas/ldap/edir/freeradius-clients.ldif
@@ -0,0 +1,69 @@
+#
+# LDIF Novell eDirectory schema to load dynamic clients from LDAP
+#
+# copyright 2013 Olivier Beytrison <olivier@heliosnet.org>
+#
+# 1.3.6.1.4.1.11344.1.100 is the toplevel OID for this work
+# .1 = objectclasses
+# .2 = attributs
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributetypes: ( 1.3.6.1.4.1.11344.1.100.2.1
+ NAME 'radiusClientIdentifier'
+ DESC 'Client Identifier'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX '1.3.6.1.4.1.1466.115.121.1.15'
+ SINGLE-VALUE )
+attributetypes: ( 1.3.6.1.4.1.11344.1.100.2.2
+ NAME 'radiusClientSecret'
+ DESC 'Client Secret'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX '1.3.6.1.4.1.1466.115.121.1.15'
+ SINGLE-VALUE )
+attributetypes: ( 1.3.6.1.4.1.11344.1.100.2.3
+ NAME 'radiusClientShortname'
+ DESC 'Client Shortname'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX '1.3.6.1.4.1.1466.115.121.1.15'
+ SINGLE-VALUE )
+attributetypes: ( 1.3.6.1.4.1.11344.1.100.2.4
+ NAME 'radiusClientVirtualServer'
+ DESC 'VirtualServer'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX '1.3.6.1.4.1.1466.115.121.1.15'
+ SINGLE-VALUE )
+attributetypes: ( 1.3.6.1.4.1.11344.1.100.2.5
+ NAME 'radiusClientType'
+ DESC 'Client Type'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX '1.3.6.1.4.1.1466.115.121.1.15'
+ SINGLE-VALUE )
+attributetypes: ( 1.3.6.1.4.1.11344.1.100.2.6
+ NAME 'radiusClientRequireMa'
+ DESC 'Require Message Authenticator'
+ EQUALITY booleanMatch
+ SYNTAX '1.3.6.1.4.1.1466.115.121.1.7'
+ SINGLE-VALUE )
+attributetypes: ( 1.3.6.1.4.1.11344.1.100.2.7
+ NAME 'radiusClientComment'
+ DESC 'Client comment'
+ EQUALITY caseIgnoreMatch
+ SYNTAX '1.3.6.1.4.1.1466.115.121.1.15'
+ SINGLE-VALUE )
+
+
+dn: cn=schema
+changetype: modify
+add: objectclasses
+objectclasses: ( 1.3.6.1.4.1.11344.1.100.1.1
+ NAME 'radiusClient'
+ DESC 'radiusClient object class'
+ SUP top STRUCTURAL
+ MUST ( radiusClientIdentifier $ radiusClientSecret )
+ MAY ( radiusClientShortname $ radiusClientVirtualServer $ radiusClientType $ radiusClientRequireMa $radiusClientcomment ))
diff --git a/doc/schemas/ldap/iplanet/freeradius.ldif b/doc/schemas/ldap/iplanet/freeradius.ldif
new file mode 100644
index 0000000..3834cb3
--- /dev/null
+++ b/doc/schemas/ldap/iplanet/freeradius.ldif
@@ -0,0 +1,73 @@
+# This is a LDAPv3 schema for RADIUS attributes.
+# Converted for use with iPlanet/Sun Directory Servers 5.x by Arne Brutschy <abrutschy@xylon.de>
+#
+# Originally Tested on OpenLDAP 2.0.7
+# Posted by Javier Fernandez-Sanguino Pena <jfernandez@sgi.es>
+# LDAP v3 version by Jochen Friedrich <jochen@scram.de>
+# Updates by Adrian Pavlykevych <pam@polynet.lviv.ua>
+##############
+dn: cn=schema
+attributeTypes: ( 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 )
+attributeTypes: ( 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 )
+attributeTypes: ( 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 )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.44 NAME 'radiusAuthType' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.4 NAME 'radiusCallbackId' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.5 NAME 'radiusCallbackNumber' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.6 NAME 'radiusCalledStationId' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.7 NAME 'radiusCallingStationId' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.8 NAME 'radiusClass' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+attributeTypes: ( 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 )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.9 NAME 'radiusFilterId' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.10 NAME 'radiusFramedAppleTalkLink' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.11 NAME 'radiusFramedAppleTalkNetwork' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.12 NAME 'radiusFramedAppleTalkZone' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.13 NAME 'radiusFramedCompression' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.14 NAME 'radiusFramedIPAddress' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.15 NAME 'radiusFramedIPNetmask' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.16 NAME 'radiusFramedIPXNetwork' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.17 NAME 'radiusFramedMTU' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.18 NAME 'radiusFramedProtocol' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.19 NAME 'radiusFramedRoute' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.20 NAME 'radiusFramedRouting' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+attributeTypes: ( 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 )
+attributeTypes: ( 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 )
+attributeTypes: ( 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 )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.21 NAME 'radiusIdleTimeout' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.22 NAME 'radiusLoginIPHost' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.23 NAME 'radiusLoginLATGroup' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.24 NAME 'radiusLoginLATNode' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.25 NAME 'radiusLoginLATPort' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.26 NAME 'radiusLoginLATService' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.27 NAME 'radiusLoginService' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.28 NAME 'radiusLoginTCPPort' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+attributeTypes: ( 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 )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.30 NAME 'radiusPortLimit' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+attributeTypes: ( 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 )
+attributeTypes: ( 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 )
+attributeTypes: ( 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 )
+attributeTypes: ( 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 )
+attributeTypes: ( 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 )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.32 NAME 'radiusServiceType' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.33 NAME 'radiusSessionTimeout' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.34 NAME 'radiusTerminationAction' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+attributeTypes: ( 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 )
+attributeTypes: ( 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 )
+attributeTypes: ( 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 )
+attributeTypes: ( 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 )
+attributeTypes: ( 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 )
+attributeTypes: ( 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 )
+attributeTypes: ( 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 )
+attributeTypes: ( 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 )
+attributeTypes: ( 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 )
+#need to change asn1.id
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.53 NAME 'radiusSimultaneousUse' DESC '' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+attributeTypes: ( 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 )
+attributeTypes: ( 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 )
+attributeTypes: ( 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 )
+attributeTypes: ( 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 )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.58 NAME 'radiusExpiration' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.59 NAME 'radiusAttribute' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.60 NAME 'radiusControlAttribute' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.61 NAME 'radiusReplyAttribute' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.62 NAME 'radiusRequestAttribute' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+objectClasses: ( 1.3.6.1.4.1.11344.4.3.2.1 NAME 'radiusprofile' DESC '' SUP top AUXILIARY MUST ( cn ) 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 $ radiusControlAttribute $ radiusReplyAttribute $ radiusRequestAttribute ) )
diff --git a/doc/schemas/ldap/iplanet/freeradius.schema b/doc/schemas/ldap/iplanet/freeradius.schema
new file mode 100644
index 0000000..6392b02
--- /dev/null
+++ b/doc/schemas/ldap/iplanet/freeradius.schema
@@ -0,0 +1,78 @@
+# This is a LDAPv3 schema for RADIUS attributes.
+# Tested on Sun One Directory server 5.2
+# Created by Daniel Wilson (danielwilson_2k@yahoo.com)
+##############
+dn: cn=schema
+objectClass: top
+objectClass: ldapSubentry
+objectClass: subschema
+cn: schema
+#######################
+# aci to ensure that the standard schema attributes are visible to
+# all LDAP clients (anonymous access).
+#
+aci: (target="ldap:///cn=schema")(targetattr !="aci")(version 3.0;acl "anonymous, no acis"; allow (read, search, compare) userdn = "ldap:///anyone";
+#######################
+objectClasses: ( 1.3.6.1.4.1.11344.4.3.2.1 NAME 'radiusprofile' SUP top AUXILIARY DESC 'Free Radius schema for Directory Server 5.2' MUST (cn) 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 $ radiusControlAttribute $ radiusReplyAttribute $radiusRequestAttribute ) X-ORIGIN 'user defined')
+attributeTypes: ( 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 X-ORIGIN 'user defined')
+attributeTypes: ( 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 X-ORIGIN 'user defined')
+attributeTypes: ( 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 X-ORIGIN 'user defined')
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.44 NAME 'radiusAuthType' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'user defined' )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.4 NAME 'radiusCallbackId' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'user defined' )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.5 NAME 'radiusCallbackNumber' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'user defined' )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.6 NAME 'radiusCalledStationId' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'user defined' )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.7 NAME 'radiusCallingStationId' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'user defined' )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.8 NAME 'radiusClass' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+attributeTypes: ( 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 X-ORIGIN 'user defined' )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.9 NAME 'radiusFilterId' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'user defined' )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.10 NAME 'radiusFramedAppleTalkLink' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'user defined' )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.11 NAME 'radiusFramedAppleTalkNetwork' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'user defined' )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.12 NAME 'radiusFramedAppleTalkZone' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'user defined' )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.13 NAME 'radiusFramedCompression' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'user defined' )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.14 NAME 'radiusFramedIPAddress' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'user defined' )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.15 NAME 'radiusFramedIPNetmask' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'user defined' )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.16 NAME 'radiusFramedIPXNetwork' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'user defined' )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.17 NAME 'radiusFramedMTU' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'user defined' )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.18 NAME 'radiusFramedProtocol' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'user defined' )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.19 NAME 'radiusFramedRoute' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.20 NAME 'radiusFramedRouting' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'user defined' )
+attributeTypes: ( 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 )
+attributeTypes: ( 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 X-ORIGIN 'user defined' )
+attributeTypes: ( 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 )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.21 NAME 'radiusIdleTimeout' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'user defined' )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.22 NAME 'radiusLoginIPHost' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'user defined' )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.23 NAME 'radiusLoginLATGroup' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'user defined' )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.24 NAME 'radiusLoginLATNode' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'user defined' )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.25 NAME 'radiusLoginLATPort' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'user defined' )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.26 NAME 'radiusLoginLATService' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'user defined' )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.27 NAME 'radiusLoginService' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'user defined' )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.28 NAME 'radiusLoginTCPPort' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'user defined' )
+attributeTypes: ( 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 X-ORIGIN 'user defined' )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.30 NAME 'radiusPortLimit' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'user defined' )
+attributeTypes: ( 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 X-ORIGIN 'user defined' )
+attributeTypes: ( 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 X-ORIGIN 'user defined' )
+attributeTypes: ( 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 X-ORIGIN 'user defined' )
+attributeTypes: ( 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 X-ORIGIN 'user defined' )
+attributeTypes: ( 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 X-ORIGIN 'user defined' )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.32 NAME 'radiusServiceType' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'user defined' )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.33 NAME 'radiusSessionTimeout' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'user defined' )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.34 NAME 'radiusTerminationAction' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'user defined' )
+attributeTypes: ( 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 )
+attributeTypes: ( 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 )
+attributeTypes: ( 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 X-ORIGIN 'user defined' )
+attributeTypes: ( 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 )
+attributeTypes: ( 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 )
+attributeTypes: ( 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 )
+attributeTypes: ( 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 )
+attributeTypes: ( 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 )
+attributeTypes: ( 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 )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.53 NAME 'radiusSimultaneousUse' DESC '' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'user defined' )
+attributeTypes: ( 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 X-ORIGIN 'user defined' )
+attributeTypes: ( 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 X-ORIGIN 'user defined' )
+attributeTypes: ( 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 X-ORIGIN 'user defined' )
+attributeTypes: ( 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 X-ORIGIN 'user defined' )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.58 NAME 'radiusExpiration' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'user defined' )
+attributeTypes: ( 1.3.6.1.4.1.11344.4.3.1.59 NAME 'radiusAttribute' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+attributetypes: ( 1.3.6.1.4.1.11344.4.3.1.60 NAME 'radiusControlAttribute' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+attributetypes: ( 1.3.6.1.4.1.11344.4.3.1.61 NAME 'radiusReplyAttribute' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+attributetypes: ( 1.3.6.1.4.1.11344.4.3.1.62 NAME 'radiusRequestAttribute' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
diff --git a/doc/schemas/ldap/openldap/freeradius-clients.ldif b/doc/schemas/ldap/openldap/freeradius-clients.ldif
new file mode 100644
index 0000000..d591799
--- /dev/null
+++ b/doc/schemas/ldap/openldap/freeradius-clients.ldif
@@ -0,0 +1,17 @@
+#
+# LDIF Openldap schema to load dynamic clients from LDAP
+#
+# copyright 2013 Olivier Beytrison <olivier@heliosnet.org>
+#
+
+dn: cn=radiusClient,cn=schema,cn=config
+objectClass: olcSchemaConfig
+cn: radiusClient
+olcAttributeTypes: ( 1.3.6.1.4.1.11344.1.100.2.1 NAME 'radiusClientIdentifier' SINGLE-VALUE DESC 'Client identifier' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' )
+olcAttributeTypes: ( 1.3.6.1.4.1.11344.1.100.2.2 NAME 'radiusClientSecret' SINGLE-VALUE DESC 'Client secret' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' )
+olcAttributeTypes: ( 1.3.6.1.4.1.11344.1.100.2.3 NAME 'radiusClientShortname' SINGLE-VALUE DESC 'Client shortname' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' )
+olcAttributeTypes: ( 1.3.6.1.4.1.11344.1.100.2.4 NAME 'radiusClientVirtualServer' SINGLE-VALUE DESC 'VirtualServer' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' )
+olcAttributeTypes: ( 1.3.6.1.4.1.11344.1.100.2.5 NAME 'radiusClientType' SINGLE-VALUE DESC 'Client Type' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' )
+olcAttributeTypes: ( 1.3.6.1.4.1.11344.1.100.2.6 NAME 'radiusClientRequireMa' SINGLE-VALUE DESC 'Require Message Authenticator' EQUALITY booleanMatch SYNTAX '1.3.6.1.4.1.1466.115.121.1.7' )
+olcAttributeTypes: ( 1.3.6.1.4.1.11344.1.100.2.7 NAME 'radiusClientComment' SINGLE-VALUE DESC 'Client comment' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' )
+olcObjectClasses: ( 1.3.6.1.4.1.11344.1.100.1.1 NAME 'radiusClient' DESC 'radiusClient object class' SUP top STRUCTURAL MUST ( radiusClientIdentifier $ radiusClientSecret ) MAY ( radiusClientShortname $ radiusClientVirtualServer $ radiusClientType $ radiusClientRequireMa $ radiusClientComment ))
diff --git a/doc/schemas/ldap/openldap/freeradius-clients.schema b/doc/schemas/ldap/openldap/freeradius-clients.schema
new file mode 100644
index 0000000..b1fdd66
--- /dev/null
+++ b/doc/schemas/ldap/openldap/freeradius-clients.schema
@@ -0,0 +1,70 @@
+attributetype ( 1.3.6.1.4.1.11344.1.100.2.1
+ NAME 'radiusClientIdentifier'
+ DESC 'Client Identifier'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+ SINGLE-VALUE
+ )
+
+attributetype ( 1.3.6.1.4.1.11344.1.100.2.2
+ NAME 'radiusClientSecret'
+ DESC 'Client Secret'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+ SINGLE-VALUE
+ )
+
+attributetype ( 1.3.6.1.4.1.11344.1.100.2.3
+ NAME 'radiusClientShortname'
+ DESC 'Client Shortname'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+ SINGLE-VALUE
+ )
+
+attributetype ( 1.3.6.1.4.1.11344.1.100.2.4
+ NAME 'radiusClientVirtualServer'
+ DESC 'VirtualServer'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+ SINGLE-VALUE
+ )
+
+attributetype ( 1.3.6.1.4.1.11344.1.100.2.5
+ NAME 'radiusClientType'
+ DESC 'Client Type'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+ SINGLE-VALUE
+ )
+
+attributetype ( 1.3.6.1.4.1.11344.1.100.2.6
+ NAME 'radiusClientRequireMa'
+ DESC 'Require Message Authenticator'
+ EQUALITY booleanMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
+ SINGLE-VALUE
+ )
+
+attributetype ( 1.3.6.1.4.1.11344.1.100.2.7
+ NAME 'radiusClientComment'
+ DESC 'Client comment'
+ EQUALITY caseIgnoreMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+ SINGLE-VALUE
+ )
+
+objectclass ( 1.3.6.1.4.1.11344.1.100.1.1
+ NAME 'radiusClient'
+ DESC 'radiusClient object class'
+ SUP top
+ STRUCTURAL
+ MUST ( radiusClientIdentifier $ radiusClientSecret )
+ MAY ( radiusClientShortname $ radiusClientVirtualServer $ radiusClientType $ radiusClientRequireMa $ radiusClientComment )
+ )
+
diff --git a/doc/schemas/ldap/openldap/freeradius.ldif b/doc/schemas/ldap/openldap/freeradius.ldif
new file mode 100644
index 0000000..44d2cb9
--- /dev/null
+++ b/doc/schemas/ldap/openldap/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/doc/schemas/ldap/openldap/freeradius.schema b/doc/schemas/ldap/openldap/freeradius.schema
new file mode 100644
index 0000000..ab11984
--- /dev/null
+++ b/doc/schemas/ldap/openldap/freeradius.schema
@@ -0,0 +1,477 @@
+attributetype ( 1.3.6.1.4.1.11344.4.3.1.1
+ NAME 'radiusArapFeatures'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+attributetype ( 1.3.6.1.4.1.11344.4.3.1.2
+ NAME 'radiusArapSecurity'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+attributetype ( 1.3.6.1.4.1.11344.4.3.1.3
+ NAME 'radiusArapZoneAccess'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+attributetype ( 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
+ )
+
+attributetype ( 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
+ )
+
+attributetype ( 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
+ )
+
+attributetype ( 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
+ )
+
+attributetype ( 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
+ )
+
+attributetype ( 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
+ )
+
+attributetype ( 1.3.6.1.4.1.11344.4.3.1.45
+ NAME 'radiusClientIPAddress'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+attributetype ( 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
+ )
+
+attributetype ( 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
+ )
+
+attributetype ( 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
+ )
+
+attributetype ( 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
+ )
+
+attributetype ( 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
+ )
+
+attributetype ( 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
+ )
+
+attributetype ( 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
+ )
+
+attributetype ( 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
+ )
+
+attributetype ( 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
+ )
+
+attributetype ( 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
+ )
+
+attributetype ( 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
+ )
+
+attributetype ( 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
+ )
+
+attributetype ( 1.3.6.1.4.1.11344.4.3.1.46
+ NAME 'radiusGroupName'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ )
+
+attributetype ( 1.3.6.1.4.1.11344.4.3.1.47
+ NAME 'radiusHint'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+attributetype ( 1.3.6.1.4.1.11344.4.3.1.48
+ NAME 'radiusHuntgroupName'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ )
+
+attributetype ( 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
+ )
+
+attributetype ( 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
+ )
+
+attributetype ( 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
+ )
+
+attributetype ( 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
+ )
+
+attributetype ( 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
+ )
+
+attributetype ( 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
+ )
+
+attributetype ( 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
+ )
+
+attributetype ( 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
+ )
+
+attributetype ( 1.3.6.1.4.1.11344.4.3.1.29
+ NAME 'radiusPasswordRetry'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+attributetype ( 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
+ )
+
+attributetype ( 1.3.6.1.4.1.11344.4.3.1.49
+ NAME 'radiusProfileDN'
+ EQUALITY distinguishedNameMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
+ )
+
+attributetype ( 1.3.6.1.4.1.11344.4.3.1.31
+ NAME 'radiusPrompt'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+attributetype ( 1.3.6.1.4.1.11344.4.3.1.50
+ NAME 'radiusProxyToRealm'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+attributetype ( 1.3.6.1.4.1.11344.4.3.1.51
+ NAME 'radiusReplicateToRealm'
+ DESC 'control:Replicate-To-Realm'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+attributetype ( 1.3.6.1.4.1.11344.4.3.1.52
+ NAME 'radiusRealm'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+attributetype ( 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
+ )
+
+attributetype ( 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
+ )
+
+attributetype ( 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
+ )
+
+attributetype ( 1.3.6.1.4.1.11344.4.3.1.35
+ NAME 'radiusTunnelAssignmentId'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ )
+
+attributetype ( 1.3.6.1.4.1.11344.4.3.1.36
+ NAME 'radiusTunnelMediumType'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ )
+
+attributetype ( 1.3.6.1.4.1.11344.4.3.1.37
+ NAME 'radiusTunnelPassword'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ )
+
+attributetype ( 1.3.6.1.4.1.11344.4.3.1.38
+ NAME 'radiusTunnelPreference'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ )
+
+attributetype ( 1.3.6.1.4.1.11344.4.3.1.39
+ NAME 'radiusTunnelPrivateGroupId'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ )
+
+attributetype ( 1.3.6.1.4.1.11344.4.3.1.40
+ NAME 'radiusTunnelServerEndpoint'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ )
+
+attributetype ( 1.3.6.1.4.1.11344.4.3.1.41
+ NAME 'radiusTunnelType'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ )
+
+attributetype ( 1.3.6.1.4.1.11344.4.3.1.42
+ NAME 'radiusVSA'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ )
+
+attributetype ( 1.3.6.1.4.1.11344.4.3.1.43
+ NAME 'radiusTunnelClientEndpoint'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ )
+
+attributetype ( 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
+ )
+
+attributetype ( 1.3.6.1.4.1.11344.4.3.1.54
+ NAME 'radiusLoginTime'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+attributetype ( 1.3.6.1.4.1.11344.4.3.1.55
+ NAME 'radiusUserCategory'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+attributetype ( 1.3.6.1.4.1.11344.4.3.1.56
+ NAME 'radiusStripUserName'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
+ SINGLE-VALUE
+ )
+
+attributetype ( 1.3.6.1.4.1.11344.4.3.1.57
+ NAME 'dialupAccess'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+attributetype ( 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
+ )
+
+attributetype ( 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
+ )
+
+attributetype ( 1.3.6.1.4.1.11344.4.3.1.61
+ NAME 'radiusNASIpAddress'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ )
+
+attributetype ( 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
+ )
+
+attributetype ( 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
+ )
+
+attributetype ( 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
+ )
+
+attributetype ( 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
+ )
+
+objectclass ( 1.3.6.1.4.1.11344.4.3.2.1
+ NAME 'radiusprofile'
+ 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 )
+ )
+
+objectclass ( 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/doc/schemas/ldap/samba/README.txt b/doc/schemas/ldap/samba/README.txt
new file mode 100644
index 0000000..6c87461
--- /dev/null
+++ b/doc/schemas/ldap/samba/README.txt
@@ -0,0 +1,11 @@
+Change "dc=samba4,dc=internal" to your LDAP base DN,
+then install with:
+
+ldbmodify -H /usr/local/samba/private/sam.ldb freeradius-attrs.ldif \
+ --option="dsdb:schema update allowed"=true
+ldbmodify -H /usr/local/samba/private/sam.ldb freeradius-classes.ldif \
+ --option="dsdb:schema update allowed"=true
+
+These files were created by scripts/ldap/schema_to_samba.py, then
+split into two because the attributes must be loaded in a separate
+operation to the classes which use them.
diff --git a/doc/schemas/ldap/samba/freeradius-attrs.ldif b/doc/schemas/ldap/samba/freeradius-attrs.ldif
new file mode 100644
index 0000000..6edc614
--- /dev/null
+++ b/doc/schemas/ldap/samba/freeradius-attrs.ldif
@@ -0,0 +1,806 @@
+dn: CN=radiusArapFeatures,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.1
+isSingleValued: TRUE
+cn: radiusArapFeatures
+name: radiusArapFeatures
+lDAPDisplayName: radiusArapFeatures
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusArapSecurity,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.2
+isSingleValued: TRUE
+cn: radiusArapSecurity
+name: radiusArapSecurity
+lDAPDisplayName: radiusArapSecurity
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusArapZoneAccess,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.3
+isSingleValued: TRUE
+cn: radiusArapZoneAccess
+name: radiusArapZoneAccess
+lDAPDisplayName: radiusArapZoneAccess
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusAuthType,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.44
+isSingleValued: TRUE
+cn: radiusAuthType
+name: radiusAuthType
+lDAPDisplayName: radiusAuthType
+description: controlItem: Auth-Type
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusCallbackId,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.4
+isSingleValued: TRUE
+cn: radiusCallbackId
+name: radiusCallbackId
+lDAPDisplayName: radiusCallbackId
+description: replyItem: Callback-Id
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusCallbackNumber,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.5
+isSingleValued: TRUE
+cn: radiusCallbackNumber
+name: radiusCallbackNumber
+lDAPDisplayName: radiusCallbackNumber
+description: replyItem: Callback-Number
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusCalledStationId,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.6
+isSingleValued: TRUE
+cn: radiusCalledStationId
+name: radiusCalledStationId
+lDAPDisplayName: radiusCalledStationId
+description: controlItem: Called-Station-Id
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusCallingStationId,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.7
+isSingleValued: TRUE
+cn: radiusCallingStationId
+name: radiusCallingStationId
+lDAPDisplayName: radiusCallingStationId
+description: controlItem: Calling-Station-Id
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusClass,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.8
+isSingleValued: FALSE
+cn: radiusClass
+name: radiusClass
+lDAPDisplayName: radiusClass
+description: replyItem: Class
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusClientIPAddress,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.45
+isSingleValued: TRUE
+cn: radiusClientIPAddress
+name: radiusClientIPAddress
+lDAPDisplayName: radiusClientIPAddress
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusFilterId,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.9
+isSingleValued: FALSE
+cn: radiusFilterId
+name: radiusFilterId
+lDAPDisplayName: radiusFilterId
+description: replyItem: Filter-Id
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusFramedAppleTalkLink,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.10
+isSingleValued: TRUE
+cn: radiusFramedAppleTalkLink
+name: radiusFramedAppleTalkLink
+lDAPDisplayName: radiusFramedAppleTalkLink
+description: replyItem: Framed-AppleTalk-Link
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusFramedAppleTalkNetwork,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.11
+isSingleValued: FALSE
+cn: radiusFramedAppleTalkNetwork
+name: radiusFramedAppleTalkNetwork
+lDAPDisplayName: radiusFramedAppleTalkNetwork
+description: replyItem: Framed-AppleTalk-Network
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusFramedAppleTalkZone,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.12
+isSingleValued: TRUE
+cn: radiusFramedAppleTalkZone
+name: radiusFramedAppleTalkZone
+lDAPDisplayName: radiusFramedAppleTalkZone
+description: replyItem: Framed-AppleTalk-Zone
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusFramedCompression,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.13
+isSingleValued: FALSE
+cn: radiusFramedCompression
+name: radiusFramedCompression
+lDAPDisplayName: radiusFramedCompression
+description: replyItem: Framed-Compression
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusFramedIPAddress,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.14
+isSingleValued: TRUE
+cn: radiusFramedIPAddress
+name: radiusFramedIPAddress
+lDAPDisplayName: radiusFramedIPAddress
+description: replyItem: Framed-IP-Address
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusFramedIPNetmask,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.15
+isSingleValued: TRUE
+cn: radiusFramedIPNetmask
+name: radiusFramedIPNetmask
+lDAPDisplayName: radiusFramedIPNetmask
+description: replyItem: Framed-IP-Netmask
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusFramedIPXNetwork,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.16
+isSingleValued: TRUE
+cn: radiusFramedIPXNetwork
+name: radiusFramedIPXNetwork
+lDAPDisplayName: radiusFramedIPXNetwork
+description: replyItem: Framed-IPX-Network
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusFramedMTU,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.17
+isSingleValued: TRUE
+cn: radiusFramedMTU
+name: radiusFramedMTU
+lDAPDisplayName: radiusFramedMTU
+description: replyItem: Framed-MTU
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusFramedProtocol,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.18
+isSingleValued: TRUE
+cn: radiusFramedProtocol
+name: radiusFramedProtocol
+lDAPDisplayName: radiusFramedProtocol
+description: replyItem: Framed-Protocol
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusFramedRoute,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.19
+isSingleValued: FALSE
+cn: radiusFramedRoute
+name: radiusFramedRoute
+lDAPDisplayName: radiusFramedRoute
+description: replyItem: Framed-Route
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusFramedRouting,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.20
+isSingleValued: TRUE
+cn: radiusFramedRouting
+name: radiusFramedRouting
+lDAPDisplayName: radiusFramedRouting
+description: replyItem: Framed-Routing
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusGroupName,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.46
+isSingleValued: FALSE
+cn: radiusGroupName
+name: radiusGroupName
+lDAPDisplayName: radiusGroupName
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusHint,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.47
+isSingleValued: TRUE
+cn: radiusHint
+name: radiusHint
+lDAPDisplayName: radiusHint
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusHuntgroupName,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.48
+isSingleValued: FALSE
+cn: radiusHuntgroupName
+name: radiusHuntgroupName
+lDAPDisplayName: radiusHuntgroupName
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusIdleTimeout,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.21
+isSingleValued: TRUE
+cn: radiusIdleTimeout
+name: radiusIdleTimeout
+lDAPDisplayName: radiusIdleTimeout
+description: replyItem: Idle-Timeout
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusLoginIPHost,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.22
+isSingleValued: FALSE
+cn: radiusLoginIPHost
+name: radiusLoginIPHost
+lDAPDisplayName: radiusLoginIPHost
+description: replyItem: Login-IP-Host
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusLoginLATGroup,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.23
+isSingleValued: TRUE
+cn: radiusLoginLATGroup
+name: radiusLoginLATGroup
+lDAPDisplayName: radiusLoginLATGroup
+description: replyItem: Login-LAT-Group
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusLoginLATNode,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.24
+isSingleValued: TRUE
+cn: radiusLoginLATNode
+name: radiusLoginLATNode
+lDAPDisplayName: radiusLoginLATNode
+description: replyItem: Login-LAT-Node
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusLoginLATPort,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.25
+isSingleValued: TRUE
+cn: radiusLoginLATPort
+name: radiusLoginLATPort
+lDAPDisplayName: radiusLoginLATPort
+description: replyItem: Login-LAT-Port
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusLoginLATService,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.26
+isSingleValued: TRUE
+cn: radiusLoginLATService
+name: radiusLoginLATService
+lDAPDisplayName: radiusLoginLATService
+description: replyItem: Login-LAT-Service
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusLoginService,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.27
+isSingleValued: TRUE
+cn: radiusLoginService
+name: radiusLoginService
+lDAPDisplayName: radiusLoginService
+description: replyItem: Login-Service
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusLoginTCPPort,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.28
+isSingleValued: TRUE
+cn: radiusLoginTCPPort
+name: radiusLoginTCPPort
+lDAPDisplayName: radiusLoginTCPPort
+description: replyItem: Login-TCP-Port
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusPasswordRetry,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.29
+isSingleValued: TRUE
+cn: radiusPasswordRetry
+name: radiusPasswordRetry
+lDAPDisplayName: radiusPasswordRetry
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusPortLimit,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.30
+isSingleValued: TRUE
+cn: radiusPortLimit
+name: radiusPortLimit
+lDAPDisplayName: radiusPortLimit
+description: replyItem: Port-Limit
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusProfileDN,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.49
+isSingleValued: FALSE
+cn: radiusProfileDN
+name: radiusProfileDN
+lDAPDisplayName: radiusProfileDN
+attributeSyntax: 2.5.5.1
+oMSyntax: 127
+
+dn: CN=radiusPrompt,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.31
+isSingleValued: TRUE
+cn: radiusPrompt
+name: radiusPrompt
+lDAPDisplayName: radiusPrompt
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusProxyToRealm,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.50
+isSingleValued: TRUE
+cn: radiusProxyToRealm
+name: radiusProxyToRealm
+lDAPDisplayName: radiusProxyToRealm
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusReplicateToRealm,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.51
+isSingleValued: TRUE
+cn: radiusReplicateToRealm
+name: radiusReplicateToRealm
+lDAPDisplayName: radiusReplicateToRealm
+description: control:Replicate-To-Realm
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusRealm,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.52
+isSingleValued: TRUE
+cn: radiusRealm
+name: radiusRealm
+lDAPDisplayName: radiusRealm
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusServiceType,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.32
+isSingleValued: TRUE
+cn: radiusServiceType
+name: radiusServiceType
+lDAPDisplayName: radiusServiceType
+description: replyItem: Service-Type
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusSessionTimeout,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.33
+isSingleValued: TRUE
+cn: radiusSessionTimeout
+name: radiusSessionTimeout
+lDAPDisplayName: radiusSessionTimeout
+description: replyItem: Session-Timeout
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusTerminationAction,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.34
+isSingleValued: TRUE
+cn: radiusTerminationAction
+name: radiusTerminationAction
+lDAPDisplayName: radiusTerminationAction
+description: replyItem: Termination-Action
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusTunnelAssignmentId,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.35
+isSingleValued: FALSE
+cn: radiusTunnelAssignmentId
+name: radiusTunnelAssignmentId
+lDAPDisplayName: radiusTunnelAssignmentId
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusTunnelMediumType,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.36
+isSingleValued: FALSE
+cn: radiusTunnelMediumType
+name: radiusTunnelMediumType
+lDAPDisplayName: radiusTunnelMediumType
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusTunnelPassword,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.37
+isSingleValued: TRUE
+cn: radiusTunnelPassword
+name: radiusTunnelPassword
+lDAPDisplayName: radiusTunnelPassword
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusTunnelPreference,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.38
+isSingleValued: FALSE
+cn: radiusTunnelPreference
+name: radiusTunnelPreference
+lDAPDisplayName: radiusTunnelPreference
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusTunnelPrivateGroupId,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.39
+isSingleValued: FALSE
+cn: radiusTunnelPrivateGroupId
+name: radiusTunnelPrivateGroupId
+lDAPDisplayName: radiusTunnelPrivateGroupId
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusTunnelServerEndpoint,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.40
+isSingleValued: FALSE
+cn: radiusTunnelServerEndpoint
+name: radiusTunnelServerEndpoint
+lDAPDisplayName: radiusTunnelServerEndpoint
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusTunnelType,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.41
+isSingleValued: FALSE
+cn: radiusTunnelType
+name: radiusTunnelType
+lDAPDisplayName: radiusTunnelType
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusVSA,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.42
+isSingleValued: FALSE
+cn: radiusVSA
+name: radiusVSA
+lDAPDisplayName: radiusVSA
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusTunnelClientEndpoint,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.43
+isSingleValued: FALSE
+cn: radiusTunnelClientEndpoint
+name: radiusTunnelClientEndpoint
+lDAPDisplayName: radiusTunnelClientEndpoint
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusSimultaneousUse,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.53
+isSingleValued: TRUE
+cn: radiusSimultaneousUse
+name: radiusSimultaneousUse
+lDAPDisplayName: radiusSimultaneousUse
+description: controlItem: Simultaneous-Use
+attributeSyntax: 2.5.5.9
+oMSyntax: 10
+
+dn: CN=radiusLoginTime,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.54
+isSingleValued: TRUE
+cn: radiusLoginTime
+name: radiusLoginTime
+lDAPDisplayName: radiusLoginTime
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusUserCategory,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.55
+isSingleValued: TRUE
+cn: radiusUserCategory
+name: radiusUserCategory
+lDAPDisplayName: radiusUserCategory
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusStripUserName,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.56
+isSingleValued: TRUE
+cn: radiusStripUserName
+name: radiusStripUserName
+lDAPDisplayName: radiusStripUserName
+attributeSyntax: 2.5.5.8
+oMSyntax: 1
+
+dn: CN=dialupAccess,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.57
+isSingleValued: TRUE
+cn: dialupAccess
+name: dialupAccess
+lDAPDisplayName: dialupAccess
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusExpiration,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.58
+isSingleValued: TRUE
+cn: radiusExpiration
+name: radiusExpiration
+lDAPDisplayName: radiusExpiration
+description: controlItem: Expiration
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusAttribute,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.59
+isSingleValued: FALSE
+cn: radiusAttribute
+name: radiusAttribute
+lDAPDisplayName: radiusAttribute
+description: controlItem: $GENERIC$
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusNASIpAddress,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.61
+isSingleValued: TRUE
+cn: radiusNASIpAddress
+name: radiusNASIpAddress
+lDAPDisplayName: radiusNASIpAddress
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusReplyMessage,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.62
+isSingleValued: FALSE
+cn: radiusReplyMessage
+name: radiusReplyMessage
+lDAPDisplayName: radiusReplyMessage
+description: replyItem: Reply-Message
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusControlAttribute,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.63
+isSingleValued: FALSE
+cn: radiusControlAttribute
+name: radiusControlAttribute
+lDAPDisplayName: radiusControlAttribute
+description: controlItem: $GENERIC$
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusReplyAttribute,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.64
+isSingleValued: FALSE
+cn: radiusReplyAttribute
+name: radiusReplyAttribute
+lDAPDisplayName: radiusReplyAttribute
+description: replyItem: $GENERIC$
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
+dn: CN=radiusRequestAttribute,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.4.3.1.65
+isSingleValued: FALSE
+cn: radiusRequestAttribute
+name: radiusRequestAttribute
+lDAPDisplayName: radiusRequestAttribute
+description: requestItem: $GENERIC$
+attributeSyntax: 2.5.5.5
+oMSyntax: 22
+
diff --git a/doc/schemas/ldap/samba/freeradius-classes.ldif b/doc/schemas/ldap/samba/freeradius-classes.ldif
new file mode 100644
index 0000000..455069e
--- /dev/null
+++ b/doc/schemas/ldap/samba/freeradius-classes.ldif
@@ -0,0 +1,91 @@
+dn: CN=radiusprofile,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: classSchema
+governsID: 1.3.6.1.4.1.11344.4.3.2.1
+cn: radiusprofile
+name: radiusprofile
+lDAPDisplayName: radiusprofile
+subClassOf: top
+objectClassCategory: 3
+mayContain: radiusArapFeatures
+mayContain: radiusArapSecurity
+mayContain: radiusArapZoneAccess
+mayContain: radiusAuthType
+mayContain: radiusCallbackId
+mayContain: radiusCallbackNumber
+mayContain: radiusCalledStationId
+mayContain: radiusCallingStationId
+mayContain: radiusClass
+mayContain: radiusClientIPAddress
+mayContain: radiusFilterId
+mayContain: radiusFramedAppleTalkLink
+mayContain: radiusFramedAppleTalkNetwork
+mayContain: radiusFramedAppleTalkZone
+mayContain: radiusFramedCompression
+mayContain: radiusFramedIPAddress
+mayContain: radiusFramedIPNetmask
+mayContain: radiusFramedIPXNetwork
+mayContain: radiusFramedMTU
+mayContain: radiusFramedProtocol
+mayContain: radiusAttribute
+mayContain: radiusFramedRoute
+mayContain: radiusFramedRouting
+mayContain: radiusIdleTimeout
+mayContain: radiusGroupName
+mayContain: radiusHint
+mayContain: radiusHuntgroupName
+mayContain: radiusLoginIPHost
+mayContain: radiusLoginLATGroup
+mayContain: radiusLoginLATNode
+mayContain: radiusLoginLATPort
+mayContain: radiusLoginLATService
+mayContain: radiusLoginService
+mayContain: radiusLoginTCPPort
+mayContain: radiusLoginTime
+mayContain: radiusPasswordRetry
+mayContain: radiusPortLimit
+mayContain: radiusPrompt
+mayContain: radiusProxyToRealm
+mayContain: radiusRealm
+mayContain: radiusReplicateToRealm
+mayContain: radiusServiceType
+mayContain: radiusSessionTimeout
+mayContain: radiusStripUserName
+mayContain: radiusTerminationAction
+mayContain: radiusTunnelClientEndpoint
+mayContain: radiusProfileDN
+mayContain: radiusSimultaneousUse
+mayContain: radiusTunnelAssignmentId
+mayContain: radiusTunnelMediumType
+mayContain: radiusTunnelPassword
+mayContain: radiusTunnelPreference
+mayContain: radiusTunnelPrivateGroupId
+mayContain: radiusTunnelServerEndpoint
+mayContain: radiusTunnelType
+mayContain: radiusUserCategory
+mayContain: radiusVSA
+mayContain: radiusExpiration
+mayContain: dialupAccess
+mayContain: radiusNASIpAddress
+mayContain: radiusReplyMessage
+mayContain: radiusControlAttribute
+mayContain: radiusReplyAttribute
+mayContain: radiusRequestAttribute
+
+dn: CN=radiusObjectProfile,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: classSchema
+governsID: 1.3.6.1.4.1.11344.4.3.2.2
+cn: radiusObjectProfile
+name: radiusObjectProfile
+lDAPDisplayName: radiusObjectProfile
+description: A Container Objectclass to be used for creating radius profile object
+subClassOf: top
+objectClassCategory: 1
+mustContain: cn
+mayContain: uid
+mayContain: userPassword
+mayContain: description
+
diff --git a/doc/schemas/ldap/samba/freeradius-clients-attrs.ldif b/doc/schemas/ldap/samba/freeradius-clients-attrs.ldif
new file mode 100644
index 0000000..c523da4
--- /dev/null
+++ b/doc/schemas/ldap/samba/freeradius-clients-attrs.ldif
@@ -0,0 +1,91 @@
+dn: CN=radiusClientIdentifier,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.1.100.2.1
+isSingleValued: TRUE
+cn: radiusClientIdentifier
+name: radiusClientIdentifier
+lDAPDisplayName: radiusClientIdentifier
+description: Client Identifier
+attributeSyntax: 2.5.5.3
+oMSyntax: 27
+
+dn: CN=radiusClientSecret,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.1.100.2.2
+isSingleValued: TRUE
+cn: radiusClientSecret
+name: radiusClientSecret
+lDAPDisplayName: radiusClientSecret
+description: Client Secret
+attributeSyntax: 2.5.5.3
+oMSyntax: 27
+
+dn: CN=radiusClientShortname,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.1.100.2.3
+isSingleValued: TRUE
+cn: radiusClientShortname
+name: radiusClientShortname
+lDAPDisplayName: radiusClientShortname
+description: Client Shortname
+attributeSyntax: 2.5.5.3
+oMSyntax: 27
+
+dn: CN=radiusClientVirtualServer,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.1.100.2.4
+isSingleValued: TRUE
+cn: radiusClientVirtualServer
+name: radiusClientVirtualServer
+lDAPDisplayName: radiusClientVirtualServer
+description: VirtualServer
+attributeSyntax: 2.5.5.3
+oMSyntax: 27
+
+dn: CN=radiusClientType,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.1.100.2.5
+isSingleValued: TRUE
+cn: radiusClientType
+name: radiusClientType
+lDAPDisplayName: radiusClientType
+description: Client Type
+attributeSyntax: 2.5.5.3
+oMSyntax: 27
+
+dn: CN=radiusClientRequireMa,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.1.100.2.6
+isSingleValued: TRUE
+cn: radiusClientRequireMa
+name: radiusClientRequireMa
+lDAPDisplayName: radiusClientRequireMa
+description: Require Message Authenticator
+attributeSyntax: 2.5.5.8
+oMSyntax: 1
+
+dn: CN=radiusClientComment,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+attributeID: 1.3.6.1.4.1.11344.1.100.2.7
+isSingleValued: TRUE
+cn: radiusClientComment
+name: radiusClientComment
+lDAPDisplayName: radiusClientComment
+description: Client comment
+attributeSyntax: 2.5.5.3
+oMSyntax: 27
+
diff --git a/doc/schemas/ldap/samba/freeradius-clients-classes.ldif b/doc/schemas/ldap/samba/freeradius-clients-classes.ldif
new file mode 100644
index 0000000..24eade2
--- /dev/null
+++ b/doc/schemas/ldap/samba/freeradius-clients-classes.ldif
@@ -0,0 +1,19 @@
+dn: CN=radiusClient,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: add
+objectClass: top
+objectClass: classSchema
+governsID: 1.3.6.1.4.1.11344.1.100.1.1
+cn: radiusClient
+name: radiusClient
+lDAPDisplayName: radiusClient
+description: radiusClient object class
+subClassOf: top
+objectClassCategory: 1
+mustContain: radiusClientIdentifier
+mustContain: radiusClientSecret
+mayContain: radiusClientShortname
+mayContain: radiusClientVirtualServer
+mayContain: radiusClientType
+mayContain: radiusClientRequireMa
+mayContain: radiusClientComment
+
diff --git a/doc/schemas/ldap/samba/freeradius-user.ldif b/doc/schemas/ldap/samba/freeradius-user.ldif
new file mode 100644
index 0000000..d252a7c
--- /dev/null
+++ b/doc/schemas/ldap/samba/freeradius-user.ldif
@@ -0,0 +1,10 @@
+# Use this if you want to be able to apply radiusprofile
+# Auxiliary class directly to Users in the directory.
+# Install with:
+# ldbmodify -H /usr/local/samba/private/sam.ldb \
+# user.ldif \
+# --option="dsdb:schema update allowed"=true
+dn: CN=User,CN=Schema,CN=Configuration,dc=samba4,dc=internal
+changetype: modify
+add: auxiliaryClass
+auxiliaryClass: radiusprofile
diff --git a/doc/schemas/logstash/README b/doc/schemas/logstash/README
new file mode 100644
index 0000000..2f36eb6
--- /dev/null
+++ b/doc/schemas/logstash/README
@@ -0,0 +1,95 @@
+Example configuration for logstash/elasticsearch
+================================================
+
+So you've got all these RADIUS logs, but how do you analyse them? What is the
+easiest way to query the logs, find out when a client connected or disconnected,
+or view the top ten clients logging into the system over the last six hours?
+
+The elastic stack is designed and built to do just that. elasticsearch is a
+search engine; logstash is commonly used to feed data in, and kibana the web
+interface to query the logs in near real time.
+
+Installing the elastic stack is beyond the scope of this document, but can be done
+in a short amount of time by any competent sysadmin. Then comes getting the
+logs in.
+
+This directory contains the following files as a starting point for feeding
+RADIUS logs into elasticsearch via logstash, then sample dashboards for Kibana
+to explore the data.
+
+Files
+-----
+
+Please note that all files should be reviewed before use to determine if they
+are suitable for your configuration/system, especially if you are integrating
+this into an existing logstash/elasticsearch setup.
+
+radius-mapping.sh
+
+ Each elasticsearch index needs a mapping to describe how fields are stored.
+ If one is not provided then all is not lost as elasticsearch will build one
+ on the fly. However, this may not be optimal, especially for RADIUS data, as
+ all fields will be analyzed making some visualisations hard or impossible
+ (such as showing top N clients).
+
+ This shell script (which just runs curl) pushes a template mapping into the
+ elasticsearch cluster.
+
+logstash-radius.conf
+
+ A sample configuration file for logstash that parses RADIUS 'detail' files.
+ It processes these by joining each record onto one line, then splitting the
+ tab-delimited key-value pairs out. Some additional data is then extracted
+ from certain key attributes.
+
+ The logstash config will need to be edited at least to set the input method:
+ for experimentation the given input (file) may be used. If logstash is running
+ on the RADIUS server itself then this example input may be appropriate,
+ otherwise a different input such as log-courier or filebeat may be better to
+ get the data over the network to logstash.
+
+ It would be best to use an input method that can join the multiple lines of
+ the detail file together and feed them to logstash as a single entry, rather
+ than using the logstash multiline codec.
+
+log-courier.conf
+
+ An example configuration for the log-courier feeder.
+
+kibana4-dashboard.json
+
+ Basic RADIUS dashboard (for Kibana 4 to Kibana 6).
+
+ To import the dashboard first create a new index called "radius-*" in
+ Settings/Indices. Then go to Kibana's Settings page, "Objects" and "Import".
+ Once imported open the "RADIUS detail" dashboard.
+
+
+Example usage
+-------------
+
+Install mapping (only needs to be done once):
+
+ $ ./radius-mapping.sh
+
+Edit logstash-radius.conf to point to the correct file, then feed a detail file
+in:
+
+ # /usr/share/logstash/bin/logstash --path.settings=/etc/logstash -f logstash-radius.conf
+
+To view debug output, append `--log.level=debug`.
+
+
+See also
+--------
+
+elasticsearch web site: http://www.elastic.co/
+
+The configuration examples presented here have been tested with the
+following software versions:
+
+ elasticsearch 6.7.0
+ logstash 6.7.0
+ kibana 6.7.0
+ kibana 5.1.2
+ kibana 4.1.11
diff --git a/doc/schemas/logstash/kibana4-dashboard.json b/doc/schemas/logstash/kibana4-dashboard.json
new file mode 100644
index 0000000..6c379df
--- /dev/null
+++ b/doc/schemas/logstash/kibana4-dashboard.json
@@ -0,0 +1,123 @@
+[
+ {
+ "_id": "RADIUS-data",
+ "_type": "search",
+ "_source": {
+ "title": "RADIUS data",
+ "description": "",
+ "hits": 0,
+ "columns": [
+ "User-Name",
+ "Calling-Station-Id",
+ "Called-Station-Id",
+ "Framed-IP-Address",
+ "NAS-Identifier"
+ ],
+ "sort": [
+ "@timestamp",
+ "desc"
+ ],
+ "version": 1,
+ "kibanaSavedObjectMeta": {
+ "searchSourceJSON": "{\"index\":\"radius-*\",\"query\":{\"query_string\":{\"analyze_wildcard\":true,\"query\":\"*\"}},\"highlight\":{\"pre_tags\":[\"@kibana-highlighted-field@\"],\"post_tags\":[\"@/kibana-highlighted-field@\"],\"fields\":{\"*\":{}},\"fragment_size\":2147483647},\"filter\":[]}"
+ }
+ }
+ },
+ {
+ "_id": "RADIUS-detail",
+ "_type": "dashboard",
+ "_source": {
+ "title": "RADIUS detail",
+ "hits": 0,
+ "description": "",
+ "panelsJSON": "[{\"col\":5,\"id\":\"RADIUS-unique-User-Name-by-day\",\"row\":1,\"size_x\":4,\"size_y\":4,\"type\":\"visualization\"},{\"col\":1,\"columns\":[\"User-Name\",\"Calling-Station-Id\",\"Called-Station-Id\",\"Framed-IP-Address\",\"NAS-Identifier\"],\"id\":\"RADIUS-data\",\"row\":5,\"size_x\":8,\"size_y\":4,\"sort\":[\"@timestamp\",\"desc\"],\"type\":\"search\"},{\"col\":1,\"id\":\"RADIUS-accounting-packets-histogram\",\"row\":1,\"size_x\":4,\"size_y\":4,\"type\":\"visualization\"},{\"col\":9,\"id\":\"RADIUS-table-topN-data-transferred-by-User-Name\",\"row\":1,\"size_x\":4,\"size_y\":4,\"type\":\"visualization\"},{\"id\":\"RADIUS-Sessions-per-NAS\",\"type\":\"visualization\",\"size_x\":4,\"size_y\":4,\"col\":9,\"row\":5}]",
+ "version": 1,
+ "timeRestore": true,
+ "timeTo": "now",
+ "timeFrom": "now-7d",
+ "kibanaSavedObjectMeta": {
+ "searchSourceJSON": "{\"filter\":[{\"query\":{\"query_string\":{\"analyze_wildcard\":true,\"query\":\"*\"}}}]}"
+ }
+ }
+ },
+ {
+ "_id": "RADIUS-Accounting-Start-data",
+ "_type": "search",
+ "_source": {
+ "title": "RADIUS Accounting-Start data",
+ "description": "",
+ "hits": 0,
+ "columns": [
+ "User-Name",
+ "Calling-Station-Id",
+ "Called-Station-Id",
+ "Framed-IP-Address",
+ "NAS-Identifier"
+ ],
+ "sort": [
+ "@timestamp",
+ "desc"
+ ],
+ "version": 1,
+ "kibanaSavedObjectMeta": {
+ "searchSourceJSON": "{\"index\":\"radius-*\",\"query\":{\"query_string\":{\"analyze_wildcard\":true,\"query\":\"*\"}},\"highlight\":{\"pre_tags\":[\"@kibana-highlighted-field@\"],\"post_tags\":[\"@/kibana-highlighted-field@\"],\"fields\":{\"*\":{}},\"fragment_size\":2147483647},\"filter\":[{\"meta\":{\"negate\":false,\"index\":\"radius-*\",\"key\":\"Acct-Status-Type\",\"value\":\"Start\",\"disabled\":false},\"query\":{\"match\":{\"Acct-Status-Type\":{\"query\":\"Start\",\"type\":\"phrase\"}}}}]}"
+ }
+ }
+ },
+ {
+ "_id": "RADIUS-unique-User-Name-by-day",
+ "_type": "visualization",
+ "_source": {
+ "title": "RADIUS unique User-Name by day",
+ "visState": "{\n \"type\": \"histogram\",\n \"params\": {\n \"shareYAxis\": true,\n \"addTooltip\": true,\n \"addLegend\": true,\n \"scale\": \"linear\",\n \"mode\": \"stacked\",\n \"times\": [],\n \"addTimeMarker\": false,\n \"defaultYExtents\": false,\n \"setYExtents\": false,\n \"yAxis\": {}\n },\n \"aggs\": [\n {\n \"id\": \"1\",\n \"type\": \"cardinality\",\n \"schema\": \"metric\",\n \"params\": {\n \"field\": \"User-Name\"\n }\n },\n {\n \"id\": \"2\",\n \"type\": \"date_histogram\",\n \"schema\": \"segment\",\n \"params\": {\n \"field\": \"@timestamp\",\n \"interval\": \"d\",\n \"customInterval\": \"2h\",\n \"min_doc_count\": 1,\n \"extended_bounds\": {}\n }\n },\n {\n \"id\": \"3\",\n \"type\": \"terms\",\n \"schema\": \"group\",\n \"params\": {\n \"field\": \"User-Name\",\n \"size\": 50,\n \"order\": \"desc\",\n \"orderBy\": \"1\"\n }\n }\n ],\n \"listeners\": {}\n}",
+ "description": "",
+ "version": 1,
+ "kibanaSavedObjectMeta": {
+ "searchSourceJSON": "{\n \"filter\": []\n}"
+ },
+ "savedSearchId": "RADIUS-data"
+ }
+ },
+ {
+ "_id": "RADIUS-accounting-packets-histogram",
+ "_type": "visualization",
+ "_source": {
+ "title": "RADIUS accounting packets histogram",
+ "visState": "{\"type\":\"histogram\",\"params\":{\"shareYAxis\":true,\"addTooltip\":true,\"addLegend\":true,\"scale\":\"linear\",\"mode\":\"stacked\",\"times\":[],\"addTimeMarker\":false,\"defaultYExtents\":false,\"setYExtents\":false,\"yAxis\":{}},\"aggs\":[{\"id\":\"1\",\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"@timestamp\",\"interval\":\"auto\",\"customInterval\":\"2h\",\"min_doc_count\":1,\"extended_bounds\":{}}},{\"id\":\"3\",\"type\":\"terms\",\"schema\":\"group\",\"params\":{\"field\":\"Acct-Status-Type\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"1\"}}],\"listeners\":{}}",
+ "description": "",
+ "savedSearchId": "RADIUS-data",
+ "version": 1,
+ "kibanaSavedObjectMeta": {
+ "searchSourceJSON": "{\"filter\":[]}"
+ }
+ }
+ },
+ {
+ "_id": "RADIUS-table-topN-data-transferred-by-User-Name",
+ "_type": "visualization",
+ "_source": {
+ "title": "RADIUS table topN data transferred by User-Name",
+ "visState": "{\"type\":\"table\",\"params\":{\"perPage\":10,\"showPartialRows\":false,\"showMeticsAtAllLevels\":false},\"aggs\":[{\"id\":\"1\",\"type\":\"max\",\"schema\":\"metric\",\"params\":{\"field\":\"Acct-Output-Octets_long\"}},{\"id\":\"2\",\"type\":\"terms\",\"schema\":\"bucket\",\"params\":{\"field\":\"User-Name\",\"size\":10,\"order\":\"desc\",\"orderBy\":\"1\"}},{\"id\":\"3\",\"type\":\"max\",\"schema\":\"metric\",\"params\":{\"field\":\"Acct-Input-Octets_long\"}}],\"listeners\":{}}",
+ "description": "",
+ "savedSearchId": "RADIUS-data",
+ "version": 1,
+ "kibanaSavedObjectMeta": {
+ "searchSourceJSON": "{\"filter\":[]}"
+ }
+ }
+ },
+ {
+ "_id": "RADIUS-Sessions-per-NAS",
+ "_type": "visualization",
+ "_source": {
+ "title": "RADIUS Sessions per NAS",
+ "visState": "{\"type\":\"pie\",\"params\":{\"shareYAxis\":true,\"addTooltip\":true,\"addLegend\":true,\"isDonut\":false},\"aggs\":[{\"id\":\"1\",\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"NAS-Identifier\",\"size\":20,\"order\":\"desc\",\"orderBy\":\"1\"}}],\"listeners\":{}}",
+ "description": "",
+ "savedSearchId": "RADIUS-Accounting-Start-data",
+ "version": 1,
+ "kibanaSavedObjectMeta": {
+ "searchSourceJSON": "{\"filter\":[]}"
+ }
+ }
+ }
+]
diff --git a/doc/schemas/logstash/log-courier.conf b/doc/schemas/logstash/log-courier.conf
new file mode 100644
index 0000000..20d106f
--- /dev/null
+++ b/doc/schemas/logstash/log-courier.conf
@@ -0,0 +1,56 @@
+# Example log-courier configuration file for RADIUS detail files.
+#
+# This has been tested with log-courier version 2.0.4
+#
+{
+ "general": {
+ "persist directory": "/var/lib/log-courier",
+ "log syslog": true,
+ "log stdout": false
+ },
+
+ "network": {
+ "transport": "tcp",
+
+ # Servers to connect to.
+ #
+ "servers": [
+ "logstash1.example:5140",
+ "logstash2.example:5140"
+ ]
+ },
+
+ "files": [
+ {
+ # Match RADIUS detail files, but not anything that has
+ # been gzipped.
+ #
+ "paths": [ "/var/log/radius/radacct/*/detail-????????" ],
+
+ # Add a type:"radiusdetail" field to the data so that
+ # logstash can tell what type of data this is (in case
+ # log-courier is being used for other data as well).
+ #
+ "fields": {
+ "type": "radiusdetail"
+ },
+
+ # Stop watching a file if nothing has been written in 12h.
+ #
+ "dead time": "12h",
+
+ # Process multilines. If this is being used then the
+ # "multiline" section should be commented out from the
+ # logstash configuration. Logstash can then also be run
+ # with multiple workers (using -w).
+ #
+ "codecs": [
+ {
+ "name": "multiline",
+ "patterns": [ "^[A-Z\t]" ],
+ "what": "next"
+ }
+ ]
+ }
+ ]
+}
diff --git a/doc/schemas/logstash/logstash-radius.conf b/doc/schemas/logstash/logstash-radius.conf
new file mode 100644
index 0000000..f473179
--- /dev/null
+++ b/doc/schemas/logstash/logstash-radius.conf
@@ -0,0 +1,256 @@
+# logstash configuration to process RADIUS detail files
+#
+# Matthew Newton
+# April 2019
+#
+# This config has been tested with logstash version 6.7.0
+#
+# RADIUS "detail" files are textual representations of the RADIUS
+# packets, and are written to disk by e.g. FreeRADIUS. They look
+# something like the following, with the timestamp on the first
+# line then all attributes/values tab-indented.
+#
+# Tue Mar 10 15:32:24 2015
+# Packet-Type = Access-Request
+# User-Name = "test@example.com"
+# Calling-Station-Id = "01-02-03-04-05-06"
+# Called-Station-Id = "aa-bb-cc-dd-ee-ff:myssid"
+# NAS-Port = 10
+# NAS-IP-Address = 10.9.0.4
+# NAS-Identifier = "Wireless-Controller-1"
+# Service-Type = Framed-User
+# NAS-Port-Type = Wireless-802.11
+#
+
+
+
+# Example input - read data from a file. For example, to read in a
+# detail file with this input you could use:
+#
+# # /usr/share/logstash/bin/logstash --path.settings=/etc/logstash -f logstash-radius.conf --log.level=debug
+#
+
+input {
+ file {
+ path => "/var/log/radius/radacct/*/detail-*"
+ exclude => "*.gz"
+
+ # Note when testing that logstash will remember where
+ # it got to and continue from there.
+ start_position => "beginning"
+
+ # Set the type, for below.
+ type => radiusdetail
+
+ # It is preferable to use a log feeder that can join
+ # multiple lines together, rather than using multiline
+ # here. For an example, see the log-courier
+ # configuration in this directory.
+
+ # If you didn't read the above, go back and read it again.
+
+ # If that is not possible you may be able to use the
+ # following section. Note that if you are using the
+ # "stdin" input, the file is chunked into 16k blobs,
+ # so every 16k a detail record is likely to be chopped
+ # in half. If you are using the "file" input (as in this
+ # example), the blank links between records are not
+ # passed through so the regex here has to be aware of
+ # that. Basically, do multiline as early as possible
+ # in your log feeder client not here and you'll avoid
+ # most issues that are likely to come up.
+
+ codec => multiline {
+ pattern => "^\t"
+ negate => false
+ what => "previous"
+ }
+
+ # If you really want to use the "stdin" input, this
+ # will work better, but be aware of the comments
+ # above.
+
+ #codec => multiline {
+ # pattern => "^[A-Z\t]"
+ # negate => false
+ # what => "next"
+ #}
+ }
+}
+
+# Moving into production will likely need something more reliable.
+# There are many input methods, an example here using log-courier
+# (which supports client-site multiline processing and does not
+# lose log events if logstash is restarted). You could also
+# investigate e.g. filebeat from Elastic.
+
+# input {
+# courier {
+# port => 5140
+# transport => "tcp"
+#
+# # Don't set the type here, as it's set in the
+# # log-courier config instead.
+# #type => radiusdetail
+# }
+# }
+
+
+
+# Filter stage. Here we take the raw logs and process them into
+# something structured ready to index. Each attribute is stored as
+# a separate field in the output document.
+
+filter {
+
+ if [type] == "radiusdetail" {
+
+ # Pull off the timestamp at the start of the
+ # detail record. Note there may be additional data
+ # after it that has been added by the local admin,
+ # so stop at a newline OR a tab.
+
+ grok {
+ match => [ "message", "^(?<timestamp>[^\n\t]+)[\n\t]" ]
+ }
+
+ # Create the @timestamp field.
+
+ date {
+ match => [ "timestamp", "EEE MMM dd HH:mm:ss yyyy",
+ "EEE MMM d HH:mm:ss yyyy" ]
+ }
+
+ # Split the attributes and values into fields.
+ # This is the bulk of processing that adds all of
+ # the RADIUS attributes as elasticsearch fields.
+
+ # Note issue https://github.com/logstash-plugins/logstash-filter-kv/issues/10
+ # currently means that all spaces will be stripped
+ # from all fields. If this is a problem, adjust the
+ # trim setting.
+
+ kv {
+ field_split => "\n"
+ source => "message"
+ trim_value => "\" "
+ trim_key => "\t "
+ }
+
+ # Now we try and add some useful additional
+ # information. If certain fields can be broken
+ # down into components then do that here and add
+ # the data as sub-fields. For example,
+ # Called-Station-Id might be able to be broken
+ # down to Called-Station-Id_mac and Called-Station-Id_ssid
+ # on some wireless systems, or to _ip and _port
+ # with a VPN.
+
+ # Multiple calls to grok otherwise it can stop
+ # processing once it has matched one field, but
+ # e.g. you want to pull both IP and port out of
+ # the same field in two different regex's.
+
+ # Pull out some IP addresses as field_ip:
+
+ grok {
+ break_on_match => false
+ tag_on_failure => []
+ match => [
+ "Framed-IP-Address", "^(?<Framed-IP-Address_ip>\d+\.\d+\.\d+\.\d+$)",
+ "NAS-IP-Address", "^(?<NAS-IP-Address_ip>\d+\.\d+\.\d+\.\d+$)",
+ "Calling-Station-Id", "^(?<Calling-Station-Id_ip>\d+\.\d+\.\d+\.\d+)",
+ "Called-Station-Id", "^(?<Called-Station-Id_ip>\d+\.\d+\.\d+\.\d+)"
+ ]
+ }
+
+ # Split User-Name, Operator-Name, and pull out
+ # some IP ports if they are there:
+
+ grok {
+ break_on_match => false
+ tag_on_failure => []
+ match => [
+ "User-Name", "^(?<User-Name_username>[^@]+)?(?:@(?<User-Name_realm>[^@]+))$",
+ "Operator-Name", "^(?<Operator-Name_id>.)(?<Operator-Name_value>.+)$",
+
+ "Calling-Station-Id", "\[(?<Calling-Station-Id_port>\d+)\]$",
+ "Called-Station-Id", "\[(?<Called-Station-Id_port>\d+)\]$"
+ ]
+ }
+
+ # Extract MAC addresses (and SSIDs if there).
+ # MAC address matching here is lazy, but should be
+ # good enough.
+
+ grok {
+ break_on_match => false
+ tag_on_failure => []
+ match => [
+ "Calling-Station-Id", "^(?<Calling-Station-Id_mac>[a-fA-F0-9:-]{17})$",
+ "Calling-Station-Id", "^(?<Calling-Station-Id_mac>[a-fA-F0-9\.]{14})$",
+ "Calling-Station-Id", "^(?<Calling-Station-Id_mac>[a-fA-F0-9]{12})$",
+
+ "Called-Station-Id", "^(?<Called-Station-Id_mac>[a-fA-F0-9:-]{17})(?::(?<Called-Station-Id_ssid>.*))?$",
+ "Called-Station-Id", "^(?<Called-Station-Id_mac>[a-fA-F0-9\.]{14})(?::(?<Called-Station-Id_ssid>.*))?$",
+ "Called-Station-Id", "^(?<Called-Station-Id_mac>[a-fA-F0-9]{12})(?::(?<Called-Station-Id_ssid>.*))?$"
+ ]
+ }
+
+ # With the optional sanitize_mac plugin, it's
+ # possible to make sure all MAC addresses look the
+ # same, which has obvious benefits.
+ #
+ # https://github.com/mcnewton/logstash-filter-sanitize_mac
+
+ # sanitize_mac {
+ # match => {
+ # "Called-Station-Id_mac" => "Called-Station-Id_mac"
+ # "Calling-Station-Id_mac" => "Calling-Station-Id_mac"
+ # }
+ # separator => "-"
+ # fixcase => "lower"
+ # }
+
+
+ # Gigawords presents an issue because the 64-bit
+ # value is split across two attributes. Combine
+ # them both back into a single attribute so that
+ # the full value is available to use.
+
+ if ([Acct-Input-Octets]) {
+ ruby {
+ code => "event.set('Acct-Input-Octets_long', event.get('Acct-Input-Octets').to_i +
+ (event.get('Acct-Input-Gigawords') ? (event.get('Acct-Input-Gigawords').to_i * (2**32)) : 0))"
+ }
+ }
+
+ if ([Acct-Output-Octets]) {
+ ruby {
+ code => "event.set('Acct-Output-Octets_long', event.get('Acct-Output-Octets').to_i +
+ (event.get('Acct-Output-Gigawords') ? (event.get('Acct-Output-Gigawords').to_i * (2**32)) : 0))"
+ }
+ }
+
+
+ # Remove the original "message" field.
+
+ mutate {
+ remove_field => ["message"]
+ }
+
+ }
+}
+
+
+
+# Output data to the local elasticsearch cluster
+# using type "detail" in index "radius-DATE".
+
+output {
+ if [type] == "radiusdetail" {
+ elasticsearch {
+ index => "radius-%{+YYYY.MM.dd}"
+ }
+ }
+}
diff --git a/doc/schemas/logstash/radius-mapping.sh b/doc/schemas/logstash/radius-mapping.sh
new file mode 100755
index 0000000..0ee9a3f
--- /dev/null
+++ b/doc/schemas/logstash/radius-mapping.sh
@@ -0,0 +1,100 @@
+#! /bin/sh
+
+# Create an elasticsearch template mapping for RADIUS data
+# Matthew Newton
+# April 2019
+
+# This should be run on an elasticsearch node. Alternatively,
+# adjust the curl URI below.
+
+# This version has been tested on elasticsearch 6.7.0
+
+# The template will be called "radius", and will apply to all
+# indices prefixed with "radius-".
+#
+# As not all RADIUS attributes are known to begin with it has the
+# following starting point that can be modified to suit the local
+# configuration:
+#
+# Acct-Input- or Acct-Output- attributes are numbers;
+# Acct-Session-Time is a number;
+# Everything else is a keyword, which is a non-analysed string.
+
+# Additionally, the supplied logstash config will try and extract
+# MAC addresses, IP addresses and ports from the data. These are
+# stored with suffixes on the respective attribute. For example,
+# an attribute
+#
+# Called-Station-Id := "10.0.4.6[4500]"
+#
+# will be broken down into the following fields in elasticsearch:
+#
+# Called-Station-Id = "10.0.4.6[4500]"
+# Called-Station-Id_ip = "10.0.4.6"
+# Called-Station-Id_port = "4500"
+#
+# This mapping ensures that these have an appropriate data type.
+
+
+curl -s -XPUT -H 'Content-Type: application/json' '127.0.0.1:9200/_template/radius' -d '
+{
+ "template":"radius-*",
+ "order":0,
+ "mappings":{
+ "doc":{
+
+ "properties": {
+ "@timestamp": { "format" : "date_optional_time", "type" : "date" },
+ "@version": { "type" : "keyword" },
+ "message": { "type" : "text" },
+ "Acct-Session-Time": { "type" : "long" },
+ "offset": { "type" : "long" }
+ },
+
+ "dynamic_templates": [
+
+ { "acct_io_numbers": {
+ "match_pattern": "regex",
+ "match": "^Acct-(Input|Output)-.*$",
+ "mapping": {
+ "type": "long"
+ }
+ }
+ },
+
+ { "ipv4_address": {
+ "path_match": "*_ip",
+ "mapping": {
+ "type": "ip"
+ }
+ }
+ },
+
+ { "network_port": {
+ "path_match": "*_port",
+ "mapping": {
+ "type": "integer"
+ }
+ }
+ },
+
+ { "long_number": {
+ "path_match": "*_long",
+ "mapping": {
+ "type": "long"
+ }
+ }
+ },
+
+ { "no_analyze_strings": {
+ "match": "*",
+ "mapping": {
+ "type": "keyword"
+ }
+ }
+ }
+
+ ]
+ }
+ }
+}'
diff --git a/doc/schemas/sql b/doc/schemas/sql
new file mode 100644
index 0000000..b3ba35f
--- /dev/null
+++ b/doc/schemas/sql
@@ -0,0 +1,8 @@
+SQL Schemas
+===========
+
+SQL Schemas are included in raddb/<sql_module>/<sql_dialect>/schema.sql.
+
+It seemed like too much of a pain to split them out and put them here,
+especially in the case of SQLite where they're sometimes used for
+bootstrap.
diff --git a/doc/source/.gitignore b/doc/source/.gitignore
new file mode 100644
index 0000000..8683fe4
--- /dev/null
+++ b/doc/source/.gitignore
@@ -0,0 +1,4 @@
+html
+latex
+man
+*.tmp
diff --git a/doc/source/Doxyfile b/doc/source/Doxyfile
new file mode 100644
index 0000000..0d3c301
--- /dev/null
+++ b/doc/source/Doxyfile
@@ -0,0 +1,2313 @@
+# Doxyfile 1.8.9
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME = FreeRADIUS
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER = $Id$
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF =
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO = ./extra/freeradius.png
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY =
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = YES
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 2
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = YES
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO, these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS = YES
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = YES
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = ../../src \
+ extra
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
+
+FILE_PATTERNS = *.c \
+ *.h
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS = NO
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = YES
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 1
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH = http://www.mathjax.org/mathjax
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE = plain
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sf.net) file that captures the
+# structure of the code including all documentation. Note that this feature is
+# still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH = ./../../src/include
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS = *.h
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED = WITH_PROXY \
+ WITH_UNLANG \
+ WITH_ACCOUNTING \
+ WITH_DETAIL \
+ WITH_SESSION_MGMT \
+ WITH_DYNAMIC_CLIENTS \
+ WITH_STATS \
+ WITH_COMMAND_SOCKET \
+ WITH_COA \
+ WITH_COA_TUNNEL \
+ WITH_TCP \
+ WITH_DHCP \
+ WITH_VMPS \
+ WITH_THREADS \
+ HAVE_JSON
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT = YES
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH = YES
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH = YES
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT = svg
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG = YES
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES = 150
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH = 4
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT = YES
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS = YES
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP = YES
diff --git a/doc/source/extra/client.c b/doc/source/extra/client.c
new file mode 100644
index 0000000..b7775c4
--- /dev/null
+++ b/doc/source/extra/client.c
@@ -0,0 +1,12 @@
+/**
+ * @cond skip
+ * vim:syntax=doxygen
+ * @endcond
+ *
+ *
+@page client_doc
+
+@section client_intro Introduction
+
+*/
+~
diff --git a/doc/source/extra/core.c b/doc/source/extra/core.c
new file mode 100644
index 0000000..c3af04c
--- /dev/null
+++ b/doc/source/extra/core.c
@@ -0,0 +1,31 @@
+/**
+ * @cond skip
+ * vim:syntax=doxygen
+ * @endcond
+ *
+ *
+@page server_doc
+
+@section server_intro Introduction
+
+FreeRADIUS uses a thread pool to serve requests. Each request is processed
+synchronously, and processing passes through a series of stages, and a list
+of modules in each stage.
+
+The request is processed as follows
+
+- The radius packet is received by a listener - see listen.c
+- The radius packet is parsed and validated into a request - see ?
+- The request is processed - see process.c
+- The server passes through each authentication stage
+ - authorize
+ - if Proxy-To-Realm is set:
+ - pre-proxy
+ - send proxy request
+ - post-proxy
+ - else
+ - authenticate
+ - post-auth
+- Authentication stages are lists of modules - see modcall.c
+
+*/
diff --git a/doc/source/extra/freeradius.png b/doc/source/extra/freeradius.png
new file mode 100644
index 0000000..45e96a4
--- /dev/null
+++ b/doc/source/extra/freeradius.png
Binary files differ
diff --git a/doc/source/extra/module.c b/doc/source/extra/module.c
new file mode 100644
index 0000000..74071bd
--- /dev/null
+++ b/doc/source/extra/module.c
@@ -0,0 +1,17 @@
+/**
+ * @cond skip
+ * vim:syntax=doxygen
+ * @endcond
+ *
+ *
+@page module_doc
+
+@section module_intro Introduction
+
+FreeRADIUS uses a pluggable module infrastructure to extend the
+basic functionality of the server.
+
+Modules in 3.0 are dynamically linked at runtime using dlopen.
+
+@defgroup module_safe module_safe - Internal API functions that are safe for use by modules
+*/
diff --git a/doc/source/extra/toc.c b/doc/source/extra/toc.c
new file mode 100644
index 0000000..3a96fa7
--- /dev/null
+++ b/doc/source/extra/toc.c
@@ -0,0 +1,102 @@
+/**
+ * @cond skip
+ * vim:syntax=doxygen
+ * @endcond
+ *
+ *
+@mainpage
+
+@section main_intro Introduction
+
+FreeRADIUS is a high-performance modular RADIUS server, supporting PAP, CHAP,
+EAP (including EAP-TLS, EAP-TTLS, EAP-PEAP with EAP-MSCHAP) and a very flexible
+configuration model, including conditional request processing, querying of
+LDAP and SQL databases, exection of external scripts and more.
+
+FreeRADIUS uses a thread pool to serve requests. Each request is processed
+synchronously, and processing passes through a series of stages, and a list
+of modules in each stage.
+
+@section main_toc Table of Contents
+
+- @subpage server_doc "1. Core server APIs"
+- @subpage module_doc "2. Server modules"
+- @subpage client_doc "3. Client APIs"
+
+@section main_branches GIT Branch
+
+@subsection branch_master Master (v4) feature branch
+
+@code
+git clone git@github.com:FreeRADIUS/freeradius-server.git
+@endcode
+- Web: http://github.com/FreeRADIUS/freeradius-server/tree/master
+
+@subsection branch_32x 3.2.x stable branch
+
+Minor bug fixes, documentation updatews, etc. go into this branch.
+
+@code
+git clone git@github.com:FreeRADIUS/freeradius-server.git
+cd freeradius-server
+git fetch origin v3.2.x:v3.2.x
+git checkout v3.2.x
+@endcode
+- Web: http://github.com/FreeRADIUS/freeradius-server/tree/v3.2.x
+
+@subsection branch_2xx 2.x.x EOL branch
+
+@note This branch is now permanently feature frozen. New features or modules
+ should be submitted against the master branch.
+
+@code
+git clone git@github.com:FreeRADIUS/freeradius-server.git
+cd freeradius-server
+git fetch origin v2.x.x:v2.x.x
+git checkout v2.x.x
+@endcode
+- Web: http://github.com/FreeRADIUS/freeradius-server/tree/v2.x.x
+
+@subsection branch_1xx 1.1.x EOL branch
+
+@note This branch is now permanently feature frozen. New features or modules
+ should be submitted against the master branch.
+
+@code
+git clone git@github.com:FreeRADIUS/freeradius-server.git
+cd freeradius-server
+git fetch origin v2.x.x:v2.x.x
+git checkout v2.x.x
+@endcode
+- Web: http://github.com/FreeRADIUS/freeradius-server/tree/v1.1.x
+
+@section main_website Website
+
+- http://www.freeradius.org
+
+@section mailinglist Mailing lists
+
+@subsection main_list FreeRADIUS-users
+
+This list is for users of the server
+
+@code
+freeradius-users@lists.freeradius.org
+@endcode
+- Archives: http://lists.freeradius.org/pipermail/freeradius-users/
+- List info: http://freeradius.org/list/users.html
+
+@subsection dev_list FreeRADIUS-devel
+
+This list is for development of the server, including patches, and
+new features. PLEASE DO NOT post questions related to the operation
+of the server here - use the "users" list. Most of the developers
+read both, and will answer your questions there if they have the time.
+
+@code
+freeradius-devel@lists.freeradius.org
+@endcode
+- Archives: http://lists.freeradius.org/pipermail/freeradius-devel/
+- List info: http://freeradius.org/list/devel.html
+
+*/
diff --git a/doc/vendor/ascend b/doc/vendor/ascend
new file mode 100644
index 0000000..57a44be
--- /dev/null
+++ b/doc/vendor/ascend
@@ -0,0 +1,57 @@
+ Ascend Radius Options
+ or
+ What happens when a big vendor ignores an RFC
+
+
+ FreeRADIUS uses Vendor-Specific attributes to send the Ascend attributes.
+By default, Ascend NASes send the Ascend specific attributes as NON VSA's,
+which conflict with new RADIUS attributes assigned by the IETF. This was
+a very bad screw-up by Ascend that still causes many headaches, but sometimes
+we have to live with it, so we try to cope the best we can.
+
+ If you see a large number of messages about invalid Message-Authenticator
+attribute, you most likely are affected by this problem, and should implement
+the first option.
+
+You have two options:
+
+o Enable VSA's on the Ascend/Lucent MAX:
+
+ This is by far the preferred method ( as it solves many other problems ).
+
+ Max6000/4000 Series TAOS with Menued Interface:
+
+ Go to Ethernet->Mod Config->Auth.
+ At the bottom of the menu, change Auth-Compat from "OLD" to "VSA".
+ Save your changes, no reboot is needed.
+
+ Go to Ethernet->Mod Config->Acct.
+ At the bottom of the menu, change Acct-Compat from "OLD" to "VSA".
+ Save your changes, no reboot is needed.
+
+ Max TNT/Apex 8000 Series TAOS with CLI:
+
+ nas> read external-auth
+ nas> set rad-auth-client auth-radius-compat = vendor-specific
+ nas> set rad-acct-client acct-radius-compat = vendor-specific
+ nas> write
+
+o Enable OLD attributes in FreeRADIUS
+
+ One note on this, Ciscos have an Ascend compatibility mode that
+ accepts only the OLD style Ascend attributes, just to make life more
+ interesting. :)
+
+ You can make FreeRADIUS send the OLD style attributes by prefixing the
+ Ascend attributes with 'X-' in the 'users' file, sql table, ldap directory,
+ attr_filter module, etc...
+
+ Thus the VSA Ascend attribute:
+
+ Ascend-Data-Filter
+
+ becomes the OLD Ascend attribute:
+
+ X-Ascend-Data-Filter
+
+$Id$
diff --git a/doc/vendor/bay b/doc/vendor/bay
new file mode 100644
index 0000000..a23cacd
--- /dev/null
+++ b/doc/vendor/bay
@@ -0,0 +1,11 @@
+ All versions of the BAY software prior to 18.0.2 are broken in
+regards to the Message-Authenticator. They send a strictly MD5
+encoded secret instead of the encoding required by the RFC. This has
+been fixed in 18.0.2 and only 18.0.2.
+
+ If you see messages in the radius log like:
+
+Received packet from xxx.xxx.xxx.xxx with invalid Message-Authenticator!
+
+ and you are using a Bay Annex, then you MUST upgrade the software on
+your Annex. There is NO other solution to the problem.
diff --git a/doc/vendor/cisco.rst b/doc/vendor/cisco.rst
new file mode 100644
index 0000000..12270cb
--- /dev/null
+++ b/doc/vendor/cisco.rst
@@ -0,0 +1,168 @@
+Cisco IOS and Radius
+====================
+
+Introduction
+------------
+
+Cisco NAS equipment has become quite popular of late, but being Cisco
+equipment running IOS, the configuration can be a bit non-obvious to the
+unfamiliar. This document aims to describe the most common configuration
+options to make your Ciscos interoperate with radius as you would expect a
+well-behaved NAS to do.
+
+IOS 12.x
+--------
+
+For Cisco 12.x ( 12.0 and 12.1 ), the following AAA configuration directives
+are suggested:
+
+::
+
+ aaa new-model
+ aaa authentication login default group radius local
+ aaa authentication login localauth local
+ aaa authentication ppp default if-needed group radius local
+ aaa authorization exec default group radius local
+ aaa authorization network default group radius local
+ aaa accounting delay-start
+ aaa accounting exec default start-stop group radius
+ aaa accounting network default start-stop group radius
+ aaa processes 6
+
+this configuration works very well with most radius servers. One of the more
+important configurations is:
+
+::
+
+ aaa accounting delay-start
+
+This directive will delay the sending of the Accounting Start packet until
+after an IP address has been assigned during the PPP negotiation process.
+This will supersede the need to enable the sending of "Alive" packets as
+described below for IOS versions 11.x
+
+*Note* with the above it will use the radius server to authenticate
+your inbound 'telnet' connections. You will need to create an entry
+in your users file similar to the following to allow access:
+
+::
+
+ !root Cleartext-Password := "somepass" Service-Type = NAS-Prompt-User
+
+This will let a user in for the first level of access to your Cisco. You
+will still need to 'enable' ( using the locally configured enable secret )
+to perform any configuration changes or anything requiring a higher level
+of access. The username '!root' was used as an example here, you can make
+this any username you want, of course.
+
+Unique Acct-Session-Id's
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+From: http://isp-lists.isp-planet.com/isp-australia/0201/msg05143.html
+
+Just a note to all cisco ISPs out there who want RFC2866 compliance need to
+enable the hidden command ``radius-server unique-ident <n>``
+
+Minimum IOS: 12.1(4.1)T.
+
+Acct-Session-Id should be unique and wrap after every 256 reboots.
+
+You must reboot after entering this command to take effect. If not, you
+will observe after 10 minutes
+of entering this command, the following message.
+
+::
+
+ %RADIUS-3-IDENTFAIL: Save of unique accounting ident aborted.
+
+IOS 11.x
+--------
+
+For Cisco 11.1, you normally use
+
+::
+
+ aaa new-model
+ aaa authentication ppp radppp if-needed radius
+ aaa authorization network radius none
+ aaa accounting network wait-start radius
+
+to get the Cisco to talk to a radius server.
+
+With IOS 11.3
+^^^^^^^^^^^^^
+
+::
+
+ aaa accounting update newinfo
+
+If you want the IP address of the user to show up in the radutmp file
+(and thus, the output of "radwho").
+
+This is because with IOS 11.3, the Cisco first sends a "Start" accounting
+packet without the IP address included. By setting "update newinfo" it
+will send an account "Alive" packet which updates the information.
+
+Also you might see a lot of "duplicates" in the logfile. That can be
+fixed by:
+
+::
+
+ aaa accounting network wait radius
+ radius-server timeout 3
+
+To disable the Ascend style attributes (which is a VERY good idea!):
+
+::
+
+ radius-server host X.Y.Z.A auth-port 1645 acct-port 1646
+
+To enable the Ascend style attributes (which we do NOT recommend!):
+
+::
+
+ radius-server host X.Y.Z.A auth-port 1645 acct-port 1646 non-standard
+
+To see Cisco-AVPair attributes in the Cisco debugging log:
+
+ radius-server vsa accounting
+
+Cisco 36xx & 26xx, keeping the NAS IP static
+--------------------------------------------
+
+The Cisco 36/26 by default selects (it seems at random) any IP address
+assigned to it (serial, ethernet etc.) as it's RADIUS client source
+address, thus the access request may be dropped by the RADIUS server,
+because it can not verify the client. To make the cisco box always use
+one fixed address, add the following to your configuration:
+
+::
+
+ ip radius source-interface Loopback0
+
+and configure the loopback interface on your router as follows:
+
+::
+
+ interface Loopback0
+ ip address 192.0.2.250 255.255.255.255
+
+Use a real world IP address and check the Cisco documentation for why
+it is a good idea to have working loopback interface configured on
+your router.
+
+If you don't want to use the loopback interface of course you can set
+the source-interface to any interface on your Cisco box which has an
+IP address.
+
+Credits
+-------
+
+Original - Alan DeKok <aland@ox.org>
+12.x Info - Chris Parker <cparker@starnetusa.net> 2000-10-12
+
+More Information
+----------------
+For more information, the following page on Cisco's web site may help:
+
+http://www.cisco.com/univercd/cc/td/doc/product/access/acs_serv/vapp_dev/vsaig3.htm
diff --git a/doc/vendor/proxim b/doc/vendor/proxim
new file mode 100644
index 0000000..3a8f2b9
--- /dev/null
+++ b/doc/vendor/proxim
@@ -0,0 +1,12 @@
+Proxim
+^^^^^^
+
+Proxim AP-2000 NASes up to and including firmware version 2.4.5 ignore
+the Session-Timeout attribute, despite the fact that Proxim's firmware
+release notes specifically state that it is supported. On top of
+this, firmware version 2.4.5 (the latest as of this writing) has a bug
+in which the reauthentication interval on the AP cannot be set to any
+value less than 2 hours. As such, fine-grained control of client
+session times is not currently possible with this NAS. Note that this
+NAS is OEMed to several vendors, including Avaya, and may be listed
+under different names with different vendors.
diff --git a/install-sh b/install-sh
new file mode 100755
index 0000000..aaa016e
--- /dev/null
+++ b/install-sh
@@ -0,0 +1,251 @@
+#!/bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5 (mit/util/scripts/install.sh).
+#
+# Copyright 1991 by the Massachusetts Institute of Technology
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission. M.I.T. makes no representations about the
+# suitability of this software for any purpose. It is provided "as is"
+# without express or implied warranty.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch. It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+ case $1 in
+ -c) instcmd="$cpprog"
+ shift
+ continue;;
+
+ -d) dir_arg=true
+ shift
+ continue;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd="$stripprog"
+ shift
+ continue;;
+
+ -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+ shift
+ continue;;
+
+ -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+ shift
+ continue;;
+
+ *) if [ x"$src" = x ]
+ then
+ src=$1
+ else
+ # this colon is to work around a 386BSD /bin/sh bug
+ :
+ dst=$1
+ fi
+ shift
+ continue;;
+ esac
+done
+
+if [ x"$src" = x ]
+then
+ echo "install: no input file specified"
+ exit 1
+else
+ true
+fi
+
+if [ x"$dir_arg" != x ]; then
+ dst=$src
+ src=""
+
+ if [ -d $dst ]; then
+ instcmd=:
+ chmodcmd=""
+ else
+ instcmd="$mkdirprog -p"
+ fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad
+# if $src (and thus $dsttmp) contains '*'.
+
+ if [ -f $src -o -d $src ]
+ then
+ true
+ else
+ echo "install: $src does not exist"
+ exit 1
+ fi
+
+ if [ x"$dst" = x ]
+ then
+ echo "install: no destination specified"
+ exit 1
+ else
+ true
+ fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+ if [ -d $dst ]
+ then
+ dst="$dst"/`basename $src`
+ else
+ true
+ fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+# this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+ pathcomp="${pathcomp}${1}"
+ shift
+
+ if [ ! -d "${pathcomp}" ] ;
+ then
+ $mkdirprog -p "${pathcomp}"
+ else
+ true
+ fi
+
+ pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+ ([ -d $dst ] || $doit $instcmd $dst) &&
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+ if [ x"$transformarg" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ dstfile=`basename $dst $transformbasename |
+ sed $transformarg`$transformbasename
+ fi
+
+# don't allow the sed command to completely eliminate the filename
+
+ if [ x"$dstfile" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ true
+ fi
+
+# Make a temp file name in the proper directory.
+
+ dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+ $doit $instcmd $src $dsttmp &&
+
+ trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing. If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+ $doit $rmcmd -f $dstdir/$dstfile &&
+ $doit $mvcmd $dsttmp $dstdir/$dstfile
+
+fi &&
+
+
+exit 0
diff --git a/m4/ac_prog_cc_sunpro.m4 b/m4/ac_prog_cc_sunpro.m4
new file mode 100644
index 0000000..b8bdbcf
--- /dev/null
+++ b/m4/ac_prog_cc_sunpro.m4
@@ -0,0 +1,17 @@
+dnl Checks to see if this is SUNPro we're building with
+dnl Usage:
+dnl AC_PROG_CC_SUNPRO
+
+AC_DEFUN([AC_PROG_CC_SUNPRO],
+[AC_CACHE_CHECK(whether we are using SUNPro C, ac_cv_prog_suncc,
+[dnl The semicolon is to pacify NeXT's syntax-checking cpp.
+cat > conftest.c <<EOF
+#ifdef __SUNPRO_C
+ yes;
+#endif
+EOF
+if AC_TRY_COMMAND(${CC-cc} -E conftest.c) | egrep yes >/dev/null 2>&1; then
+ ac_cv_prog_suncc=yes
+else
+ ac_cv_prog_suncc=no
+fi])])
diff --git a/m4/ax_cc.m4 b/m4/ax_cc.m4
new file mode 100644
index 0000000..88b6987
--- /dev/null
+++ b/m4/ax_cc.m4
@@ -0,0 +1,493 @@
+dnl #
+dnl # check if were compiling with CLANG, autoconf GCC macro identifies CLANG as GCC
+dnl #
+AC_DEFUN([AX_CC_IS_CLANG],[
+ AC_CACHE_CHECK([if compiler is clang], [ax_cv_cc_clang],[
+
+ AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM([], [[
+ #ifndef __clang__
+ not clang
+ #endif
+ ]])],
+ [ax_cv_cc_clang=yes],
+ [ax_cv_cc_clang=no])
+ ])
+])
+
+dnl #
+dnl # clang and gcc originally used different flags to specify c11 support
+dnl #
+AC_DEFUN([AX_CC_STD_C11],[
+ AC_CACHE_CHECK([for the compiler flag to enable C11 support], [ax_cv_cc_std_c11_flag],[
+ ax_cv_cc_std_c11_flag=
+
+ CFLAGS_SAVED=$CFLAGS
+ CFLAGS="$CFLAGS -Werror -std=c11"
+
+ AC_LANG_PUSH(C)
+ AC_TRY_COMPILE(
+ [],
+ [
+ struct foo {
+ union {
+ int a;
+ int b;
+ };
+ } bar;
+ ],
+ [ax_cv_cc_std_c11_flag="-std=c11"])
+
+ if test "x$ax_cv_cc_std_c11_flag" = x; then
+ CFLAGS="$CFLAGS_SAVED -std=c1x"
+ AC_TRY_COMPILE(
+ [],
+ [
+ struct foo {
+ union {
+ int a;
+ int b;
+ };
+ } bar;
+ ],
+ [ax_cv_cc_std_c11_flag="-std=c1x"])
+ fi
+
+ AC_LANG_POP
+ CFLAGS="$CFLAGS_SAVED"
+ ])
+])
+
+dnl #
+dnl # clang and gcc originally used different flags to specify c11 support
+dnl #
+AC_DEFUN([AX_CC_UNWINDLIB_ARG],[
+ AC_CACHE_CHECK([if the compiler accepts --unwindlib], [ax_cv_cc_unwindlib_arg],[
+ LDFLAGS_SAVED=$LDFLAGS
+ LDFLAGS="$LDFLAGS -Werror --rtlib=compiler-rt --unwindlib=libunwind"
+
+ AC_LINK_IFELSE(
+ [
+ AC_LANG_SOURCE(
+ [
+ int main(int argc, char **argv) {
+ return 0;
+ }
+ ])
+ ],
+ [ax_cv_cc_unwindlib_arg=yes],
+ [ax_cv_cc_unwindlib_arg=no]
+ )
+
+ LDFLAGS="$LDFLAGS_SAVED"
+ ])
+])
+
+
+dnl #
+dnl # Check if we have the _Generic construct
+dnl #
+AC_DEFUN([AX_CC_HAVE_C11_GENERIC],
+[
+AC_CACHE_CHECK([for _Generic support in compiler], [ax_cv_cc_c11_generic],[
+ AC_COMPILE_IFELSE(
+ [
+ AC_LANG_SOURCE(
+ [
+ int main(int argc, char **argv) {
+ int foo = 1;
+ return _Generic(foo, int: 0, char: 1);
+ }
+ ])
+ ],
+ [ax_cv_cc_c11_generic=yes],
+ [ax_cv_cc_c11_generic=no]
+ )
+])
+if test "x$ax_cv_cc_c11_generic" = "xyes"; then
+ AC_DEFINE([HAVE_C11_GENERIC],1,[Define if the compiler supports the C11 _Generic construct])
+fi
+])
+
+AC_DEFUN([AX_CC_QUNUSED_ARGUMENTS_FLAG],[
+ AC_CACHE_CHECK([for the compiler flag "-Qunused-arguments"], [ax_cv_cc_qunused_arguments_flag],[
+
+ CFLAGS_SAVED=$CFLAGS
+ CFLAGS="$CFLAGS -Werror -Qunused-arguments -foobar"
+
+ AC_LANG_PUSH(C)
+ AC_TRY_COMPILE(
+ [],
+ [return 0;],
+ [ax_cv_cc_qunused_arguments_flag="yes"],
+ [ax_cv_cc_qunused_arguments_flag="no"])
+ AC_LANG_POP
+
+ CFLAGS="$CFLAGS_SAVED"
+ ])
+])
+
+AC_DEFUN([AX_CC_NO_UNKNOWN_WARNING_OPTION_FLAG],[
+ AC_CACHE_CHECK([for the compiler flag "-Wno-unknown-warning-option"], [ax_cv_cc_no_unknown_warning_option_flag],[
+
+ CFLAGS_SAVED=$CFLAGS
+ CFLAGS="-Werror -Wno-unknown-warning-option"
+
+ AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM([], [[
+ /*
+ * gcc will happily accept -Wno-unknown-warning-option
+ * only emitting an error about it, if an error ocurrs in the source file.
+ */
+ #if defined(__GNUC__) && !defined(__clang__)
+ gcc sucks
+ #endif
+
+ return 0;
+ ]])],
+ [ax_cv_cc_no_unknown_warning_option_flag=yes],
+ [ax_cv_cc_no_unknown_warning_option_flag=no])
+
+ CFLAGS="$CFLAGS_SAVED"
+ ])
+])
+
+AC_DEFUN([AX_CC_WDECLARATION_AFTER_STATEMENT_FLAG],[
+ AC_CACHE_CHECK([for the compiler flag "-Wdeclaration-after-statement"], [ax_cv_cc_wdeclaration_after_statement_flag],[
+
+ CFLAGS_SAVED=$CFLAGS
+ CFLAGS="$CFLAGS -Werror -Wdeclaration-after-statement"
+
+ AC_LANG_PUSH(C)
+ AC_TRY_COMPILE(
+ [],
+ [return 0;],
+ [ax_cv_cc_wdeclaration_after_statement_flag="yes"],
+ [ax_cv_cc_wdeclaration_after_statement_flag="no"])
+ AC_LANG_POP
+
+ CFLAGS="$CFLAGS_SAVED"
+ ])
+])
+
+AC_DEFUN([AX_CC_WEVERYTHING_FLAG],[
+ AC_CACHE_CHECK([for the compiler flag "-Weverything"], [ax_cv_cc_weverything_flag],[
+
+ CFLAGS_SAVED=$CFLAGS
+ CFLAGS="$CFLAGS -Werror -Weverything -Wno-reserved-id-macro -Wno-unused-macros -Wno-unreachable-code-return -Wno-poison-system-directories"
+
+ AC_LANG_PUSH(C)
+ AC_TRY_COMPILE(
+ [],
+ [return 0;],
+ [ax_cv_cc_weverything_flag="yes"],
+ [ax_cv_cc_weverything_flag="no"])
+ AC_LANG_POP
+
+ CFLAGS="$CFLAGS_SAVED"
+ ])
+])
+
+AC_DEFUN([AX_CC_WDOCUMENTATION_FLAG],[
+ AC_CACHE_CHECK([for the compiler flag "-Wdocumentation"], [ax_cv_cc_wdocumentation_flag],[
+
+ CFLAGS_SAVED=$CFLAGS
+ CFLAGS="$CFLAGS -Werror -Wdocumentation"
+
+ AC_LANG_PUSH(C)
+ AC_TRY_COMPILE(
+ [],
+ [return 0;],
+ [ax_cv_cc_wdocumentation_flag="yes"],
+ [ax_cv_cc_wdocumentation_flag="no"])
+ AC_LANG_POP
+
+ CFLAGS="$CFLAGS_SAVED"
+ ])
+])
+
+AC_DEFUN([AX_CC_IMPLICIT_FALLTHROUGH_FLAG],[
+ AC_CACHE_CHECK([for the compiler flag "-Wimplicit-fallthrough"], [ax_cv_cc_wimplicit_fallthrough_flag],[
+
+ CFLAGS_SAVED=$CFLAGS
+ CFLAGS="$CFLAGS -Werror -Wimplicit-fallthrough"
+
+ AC_LANG_PUSH(C)
+ AC_TRY_COMPILE(
+ [],
+ [return 0;],
+ [ax_cv_cc_wimplicit_fallthrough_flag="yes"],
+ [ax_cv_cc_wimplicit_fallthrough_flag="no"])
+ AC_LANG_POP
+
+ CFLAGS="$CFLAGS_SAVED"
+ ])
+])
+
+AC_DEFUN([AX_CC_NO_DATE_TIME_FLAG],[
+ AC_CACHE_CHECK([for the compiler flag "-Wno-date-time"], [ax_cv_cc_no_date_time_flag],[
+
+ CFLAGS_SAVED=$CFLAGS
+ CFLAGS="$CFLAGS -Werror -Wno-date-time"
+
+ AC_LANG_PUSH(C)
+ AC_TRY_COMPILE(
+ [],
+ [return 0;],
+ [ax_cv_cc_no_date_time_flag="yes"],
+ [ax_cv_cc_no_date_time_flag="no"])
+ AC_LANG_POP
+
+ CFLAGS="$CFLAGS_SAVED"
+ ])
+])
+
+AC_DEFUN([AX_CC_PTHREAD_FLAG],[
+ AC_CACHE_CHECK([for the compiler flag "-pthread"], [ax_cv_cc_pthread_flag],[
+
+ CFLAGS_SAVED=$CFLAGS
+ CFLAGS="$CFLAGS -Werror -pthread"
+
+ AC_LANG_PUSH(C)
+ AC_TRY_COMPILE(
+ [],
+ [return 0;],
+ [ax_cv_cc_pthread_flag="yes"],
+ [ax_cv_cc_pthread_flag="no"])
+ AC_LANG_POP
+
+ CFLAGS="$CFLAGS_SAVED"
+ ])
+])
+
+AC_DEFUN([AX_CC_SANITZE_ADDRESS_USE_AFTER_SCOPE_FLAG],[
+ AC_CACHE_CHECK([for the compiler flag "-fsanitize-address-use-after-scope"], [ax_cv_cc_sanitize_address_use_after_scope],[
+
+ dnl # Need -fsanitize=address else we get an unused argument error
+ CFLAGS_SAVED=$CFLAGS
+ CFLAGS="$CFLAGS -Werror -fsanitize=address -fsanitize-address-use-after-scope"
+
+ AC_LANG_PUSH(C)
+ AC_TRY_COMPILE(
+ [],
+ [return 0;],
+ [ax_cv_cc_sanitize_address_use_after_scope="yes"],
+ [ax_cv_cc_sanitize_address_use_after_scope="no"])
+ AC_LANG_POP
+
+ CFLAGS="$CFLAGS_SAVED"
+ ])
+])
+
+dnl #
+dnl # Check if we have the choose expr builtin
+dnl #
+AC_DEFUN([AX_CC_BUILTIN_CHOOSE_EXPR],
+[
+AC_CACHE_CHECK([for __builtin_choose_expr support in compiler], [ax_cv_cc_builtin_choose_expr],[
+ AC_COMPILE_IFELSE(
+ [
+ AC_LANG_SOURCE(
+ [
+ int main(int argc, char **argv) {
+ if ((argc < 0) || !argv) return 1; /* -Werror=unused-parameter */
+ return __builtin_choose_expr(0, 1, 0);
+ }
+ ])
+ ],
+ [ax_cv_cc_builtin_choose_expr=yes],
+ [ax_cv_cc_builtin_choose_expr=no]
+ )
+])
+if test "x$ax_cv_cc_builtin_choose_expr" = "xyes"; then
+ AC_DEFINE([HAVE_BUILTIN_CHOOSE_EXPR],1,[Define if the compiler supports __builtin_choose_expr])
+fi
+])
+
+dnl #
+dnl # Check if we have the types compatible p builtin
+dnl #
+AC_DEFUN([AX_CC_BUILTIN_TYPES_COMPATIBLE_P],
+[
+AC_CACHE_CHECK([for __builtin_types_compatible_p support in compiler], [ax_cv_cc_builtin_types_compatible_p],[
+ AC_COMPILE_IFELSE(
+ [
+ AC_LANG_SOURCE(
+ [
+ int main(int argc, char **argv) {
+ if ((argc < 0) || !argv) return 1; /* -Werror=unused-parameter */
+ return !(__builtin_types_compatible_p(char *, char *));
+ }
+ ])
+ ],
+ [ax_cv_cc_builtin_types_compatible_p=yes],
+ [ax_cv_cc_builtin_types_compatible_p=no]
+ )
+])
+if test "x$ax_cv_cc_builtin_types_compatible_p" = "xyes"; then
+ AC_DEFINE([HAVE_BUILTIN_TYPES_COMPATIBLE_P],1,[Define if the compiler supports __builtin_types_compatible_p])
+fi
+])
+
+dnl #
+dnl # Check if we have the bwsap64 builtin
+dnl #
+AC_DEFUN([AX_CC_BUILTIN_BSWAP64],
+[
+AC_CACHE_CHECK([for __builtin_bswap64 support in compiler], [ax_cv_cc_builtin_bswap64],[
+ AC_COMPILE_IFELSE(
+ [
+ AC_LANG_SOURCE([
+ int main(int argc, char **argv) {
+ if ((argc < 0) || !argv) return 1; /* -Werror=unused-parameter */
+ return (__builtin_bswap64(0));
+ }
+ ])
+ ],
+ [ax_cv_cc_builtin_bswap64=yes],
+ [ax_cv_cc_builtin_bswap64=no]
+ )
+])
+if test "x$ax_cv_cc_builtin_bswap64" = "xyes"; then
+ AC_DEFINE([HAVE_BUILTIN_BSWAP64],1,[Define if the compiler supports __builtin_bswap64])
+fi
+])
+
+dnl #
+dnl # Check if we have the clzll builtin
+dnl #
+AC_DEFUN([AX_CC_BUILTIN_CLZLL],
+[
+AC_CACHE_CHECK([for __builtin_clzll support in compiler], [ax_cv_cc_builtin_clzll],[
+ AC_COMPILE_IFELSE(
+ [
+ AC_LANG_SOURCE([
+ int main(int argc, char **argv) {
+ if ((argc < 0) || !argv) return 1; /* -Werror=unused-parameter */
+ return (__builtin_clzll(0) - (sizeof(unsigned long long) * 8));
+ }
+ ])
+ ],
+ [ax_cv_cc_builtin_clzll=yes],
+ [ax_cv_cc_builtin_clzll=no]
+ )
+])
+if test "x$ax_cv_cc_builtin_clzll" = "xyes"; then
+ AC_DEFINE([HAVE_BUILTIN_CLZLL],1,[Define if the compiler supports __builtin_clzll])
+fi
+])
+
+dnl #
+dnl # Check if size_t and int64_t are identical
+dnl #
+AC_DEFUN([AX_CC_SIZE_SAME_AS_UINT64],
+[
+AC_CACHE_CHECK([if size_t == uint64_t], [ax_cv_cc_size_same_as_uint64],[
+ AC_COMPILE_IFELSE(
+ [
+ AC_LANG_SOURCE([
+ #include <stdint.h>
+ #include <stddef.h>
+
+ int main(int argc, char **argv) {
+ return _Generic((size_t)(0), uint64_t: 1, size_t: 0);
+ }
+ ])
+ ],
+ [ax_cv_cc_size_same_as_uint64=no],
+ [ax_cv_cc_size_same_as_uint64=yes]
+ )
+])
+if test "x$ax_cv_cc_size_same_as_uint64" = "xyes"; then
+ AC_DEFINE([SIZE_SAME_AS_UINT64],1,[Define if the compiler supports size_t has the same underlying type as uint64])
+fi
+])
+
+dnl #
+dnl # Check if ssize_t and int64_t are identical
+dnl #
+AC_DEFUN([AX_CC_SSIZE_SAME_AS_INT64],
+[
+AC_CACHE_CHECK([if ssize_t == int64_t], [ax_cv_cc_ssize_same_as_int64],[
+ AC_COMPILE_IFELSE(
+ [
+ AC_LANG_SOURCE([
+ #include <stdint.h>
+ #include <stddef.h>
+ #include <sys/types.h>
+
+ int main(int argc, char **argv) {
+ return _Generic((ssize_t)(0), int64_t: 1, ssize_t: 0);
+ }
+ ])
+ ],
+ [ax_cv_cc_ssize_same_as_int64=no],
+ [ax_cv_cc_ssize_same_as_int64=yes]
+ )
+])
+if test "x$ax_cv_cc_ssize_same_as_int64" = "xyes"; then
+ AC_DEFINE([SSIZE_SAME_AS_INT64],1,[Define if the compiler supports ssize_t has the same underlying type as int64])
+fi
+])
+
+dnl #
+dnl # Determine the number of system cores we have
+dnl #
+AC_DEFUN([AX_SYSTEM_CORES],[
+ AC_CACHE_CHECK([number of system cores], [ax_cv_system_cores],
+ [
+ AC_LANG_PUSH(C)
+ AC_TRY_RUN(
+ [
+ #include <stdio.h>
+ #include <stdint.h>
+ #ifdef _WIN32
+ # include <windows.h>
+ #elif MACOS
+ # include <sys/param.h>
+ # include <sys/sysctl.h>
+ #else
+ # include <unistd.h>
+ #endif
+
+ int main (int argc, char *argv[])
+ {
+ uint32_t count;
+
+ #ifdef WIN32
+ SYSTEM_INFO sysinfo;
+ GetSystemInfo(&sysinfo);
+
+ count = sysinfo.dwNumberOfProcessors;
+
+ #elif MACOS
+ int nm[2];
+ size_t len = 4;
+
+ nm[0] = CTL_HW;
+ nm[1] = HW_AVAILCPU;
+ sysctl(nm, 2, &count, &len, NULL, 0);
+
+ if(count < 1) {
+ nm[1] = HW_NCPU;
+ sysctl(nm, 2, &count, &len, NULL, 0);
+ if(count < 1) {
+ count = 1;
+ }
+ }
+
+ #else
+ count = sysconf(_SC_NPROCESSORS_ONLN);
+ #endif
+
+ return count;
+ }
+ ],
+ [ax_cv_system_cores=$?],
+ [ax_cv_system_cores=$?],
+ [ax_cv_system_cores=]
+ )
+ AC_LANG_POP
+ ])
+])
+
diff --git a/m4/ax_compare_version.m4 b/m4/ax_compare_version.m4
new file mode 100644
index 0000000..74dc0fd
--- /dev/null
+++ b/m4/ax_compare_version.m4
@@ -0,0 +1,177 @@
+# ===========================================================================
+# http://www.gnu.org/software/autoconf-archive/ax_compare_version.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_COMPARE_VERSION(VERSION_A, OP, VERSION_B, [ACTION-IF-TRUE], [ACTION-IF-FALSE])
+#
+# DESCRIPTION
+#
+# This macro compares two version strings. Due to the various number of
+# minor-version numbers that can exist, and the fact that string
+# comparisons are not compatible with numeric comparisons, this is not
+# necessarily trivial to do in a autoconf script. This macro makes doing
+# these comparisons easy.
+#
+# The six basic comparisons are available, as well as checking equality
+# limited to a certain number of minor-version levels.
+#
+# The operator OP determines what type of comparison to do, and can be one
+# of:
+#
+# eq - equal (test A == B)
+# ne - not equal (test A != B)
+# le - less than or equal (test A <= B)
+# ge - greater than or equal (test A >= B)
+# lt - less than (test A < B)
+# gt - greater than (test A > B)
+#
+# Additionally, the eq and ne operator can have a number after it to limit
+# the test to that number of minor versions.
+#
+# eq0 - equal up to the length of the shorter version
+# ne0 - not equal up to the length of the shorter version
+# eqN - equal up to N sub-version levels
+# neN - not equal up to N sub-version levels
+#
+# When the condition is true, shell commands ACTION-IF-TRUE are run,
+# otherwise shell commands ACTION-IF-FALSE are run. The environment
+# variable 'ax_compare_version' is always set to either 'true' or 'false'
+# as well.
+#
+# Examples:
+#
+# AX_COMPARE_VERSION([3.15.7],[lt],[3.15.8])
+# AX_COMPARE_VERSION([3.15],[lt],[3.15.8])
+#
+# would both be true.
+#
+# AX_COMPARE_VERSION([3.15.7],[eq],[3.15.8])
+# AX_COMPARE_VERSION([3.15],[gt],[3.15.8])
+#
+# would both be false.
+#
+# AX_COMPARE_VERSION([3.15.7],[eq2],[3.15.8])
+#
+# would be true because it is only comparing two minor versions.
+#
+# AX_COMPARE_VERSION([3.15.7],[eq0],[3.15])
+#
+# would be true because it is only comparing the lesser number of minor
+# versions of the two values.
+#
+# Note: The characters that separate the version numbers do not matter. An
+# empty string is the same as version 0. OP is evaluated by autoconf, not
+# configure, so must be a string, not a variable.
+#
+# The author would like to acknowledge Guido Draheim whose advice about
+# the m4_case and m4_ifvaln functions make this macro only include the
+# portions necessary to perform the specific comparison specified by the
+# OP argument in the final configure script.
+#
+# LICENSE
+#
+# Copyright (c) 2008 Tim Toolan <toolan@ele.uri.edu>
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
+
+#serial 11
+
+dnl #########################################################################
+AC_DEFUN([AX_COMPARE_VERSION], [
+ AC_REQUIRE([AC_PROG_AWK])
+
+ # 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.
+ AS_VAR_PUSHDEF([A],[ax_compare_version_A])
+ A=`echo "$1" | 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'`
+
+ AS_VAR_PUSHDEF([B],[ax_compare_version_B])
+ B=`echo "$3" | 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'`
+
+ dnl # In the case of le, ge, lt, and gt, the strings are sorted as necessary
+ dnl # then the first line is used to determine if the condition is true.
+ dnl # The sed right after the echo is to remove any indented white space.
+ m4_case(m4_tolower($2),
+ [lt],[
+ ax_compare_version=`echo "x$A
+x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/false/;s/x${B}/true/;1q"`
+ ],
+ [gt],[
+ ax_compare_version=`echo "x$A
+x$B" | sed 's/^ *//' | sort | sed "s/x${A}/false/;s/x${B}/true/;1q"`
+ ],
+ [le],[
+ ax_compare_version=`echo "x$A
+x$B" | sed 's/^ *//' | sort | sed "s/x${A}/true/;s/x${B}/false/;1q"`
+ ],
+ [ge],[
+ ax_compare_version=`echo "x$A
+x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/true/;s/x${B}/false/;1q"`
+ ],[
+ dnl Split the operator from the subversion count if present.
+ m4_bmatch(m4_substr($2,2),
+ [0],[
+ # A count of zero means use the length of the shorter version.
+ # Determine the number of characters in A and B.
+ ax_compare_version_len_A=`echo "$A" | $AWK '{print(length)}'`
+ ax_compare_version_len_B=`echo "$B" | $AWK '{print(length)}'`
+
+ # Set A to no more than B's length and B to no more than A's length.
+ A=`echo "$A" | sed "s/\(.\{$ax_compare_version_len_B\}\).*/\1/"`
+ B=`echo "$B" | sed "s/\(.\{$ax_compare_version_len_A\}\).*/\1/"`
+ ],
+ [[0-9]+],[
+ # A count greater than zero means use only that many subversions
+ A=`echo "$A" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"`
+ B=`echo "$B" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"`
+ ],
+ [.+],[
+ AC_WARNING(
+ [illegal OP numeric parameter: $2])
+ ],[])
+
+ # Pad zeros at end of numbers to make same length.
+ ax_compare_version_tmp_A="$A`echo $B | sed 's/./0/g'`"
+ B="$B`echo $A | sed 's/./0/g'`"
+ A="$ax_compare_version_tmp_A"
+
+ # Check for equality or inequality as necessary.
+ m4_case(m4_tolower(m4_substr($2,0,2)),
+ [eq],[
+ test "x$A" = "x$B" && ax_compare_version=true
+ ],
+ [ne],[
+ test "x$A" != "x$B" && ax_compare_version=true
+ ],[
+ AC_WARNING([illegal OP parameter: $2])
+ ])
+ ])
+
+ AS_VAR_POPDEF([A])dnl
+ AS_VAR_POPDEF([B])dnl
+
+ dnl # Execute ACTION-IF-TRUE / ACTION-IF-FALSE.
+ if test "$ax_compare_version" = "true" ; then
+ m4_ifvaln([$4],[$4],[:])dnl
+ m4_ifvaln([$5],[else $5])dnl
+ fi
+]) dnl AX_COMPARE_VERSION
diff --git a/m4/ax_prog_perl_modules.m4 b/m4/ax_prog_perl_modules.m4
new file mode 100644
index 0000000..70b3230
--- /dev/null
+++ b/m4/ax_prog_perl_modules.m4
@@ -0,0 +1,77 @@
+# ===========================================================================
+# https://www.gnu.org/software/autoconf-archive/ax_prog_perl_modules.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_PROG_PERL_MODULES([MODULES], [ACTION-IF-TRUE], [ACTION-IF-FALSE])
+#
+# DESCRIPTION
+#
+# Checks to see if the given perl modules are available. If true the shell
+# commands in ACTION-IF-TRUE are executed. If not the shell commands in
+# ACTION-IF-FALSE are run. Note if $PERL is not set (for example by
+# calling AC_CHECK_PROG, or AC_PATH_PROG), AC_CHECK_PROG(PERL, perl, perl)
+# will be run.
+#
+# MODULES is a space separated list of module names. To check for a
+# minimum version of a module, append the version number to the module
+# name, separated by an equals sign.
+#
+# Example:
+#
+# AX_PROG_PERL_MODULES( Text::Wrap Net::LDAP=1.0.3, ,
+# AC_MSG_WARN(Need some Perl modules)
+#
+# LICENSE
+#
+# Copyright (c) 2009 Dean Povey <povey@wedgetail.com>
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
+
+#serial 8
+
+AU_ALIAS([AC_PROG_PERL_MODULES], [AX_PROG_PERL_MODULES])
+AC_DEFUN([AX_PROG_PERL_MODULES],[dnl
+
+m4_define([ax_perl_modules])
+m4_foreach([ax_perl_module], m4_split(m4_normalize([$1])),
+ [
+ m4_append([ax_perl_modules],
+ [']m4_bpatsubst(ax_perl_module,=,[ ])[' ])
+ ])
+
+# Make sure we have perl
+if test -z "$PERL"; then
+AC_CHECK_PROG(PERL,perl,perl)
+fi
+
+if test "x$PERL" != x; then
+ ax_perl_modules_failed=0
+ for ax_perl_module in ax_perl_modules; do
+ AC_MSG_CHECKING(for perl module $ax_perl_module)
+
+ # Would be nice to log result here, but can't rely on autoconf internals
+ $PERL -e "use $ax_perl_module; exit" > /dev/null 2>&1
+ if test $? -ne 0; then
+ AC_MSG_RESULT(no);
+ ax_perl_modules_failed=1
+ else
+ AC_MSG_RESULT(ok);
+ fi
+ done
+
+ # Run optional shell commands
+ if test "$ax_perl_modules_failed" = 0; then
+ :
+ $2
+ else
+ :
+ $3
+ fi
+else
+ AC_MSG_WARN(could not find perl)
+fi])dnl
diff --git a/m4/ax_prog_ruby_version.m4 b/m4/ax_prog_ruby_version.m4
new file mode 100644
index 0000000..e14ca60
--- /dev/null
+++ b/m4/ax_prog_ruby_version.m4
@@ -0,0 +1,66 @@
+# ===========================================================================
+# http://www.gnu.org/software/autoconf-archive/ax_prog_ruby_version.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_PROG_RUBY_VERSION([VERSION],[ACTION-IF-TRUE],[ACTION-IF-FALSE])
+#
+# DESCRIPTION
+#
+# Makes sure that ruby supports the version indicated. If true the shell
+# commands in ACTION-IF-TRUE are executed. If not the shell commands in
+# ACTION-IF-FALSE are run. Note if $RUBY is not set (for example by
+# running AC_CHECK_PROG or AC_PATH_PROG) the macro will fail.
+#
+# Example:
+#
+# AC_PATH_PROG([RUBY],[ruby])
+# AC_PROG_RUBY_VERSION([1.8.0],[ ... ],[ ... ])
+#
+# This will check to make sure that the ruby you have supports at least
+# version 1.6.0.
+#
+# NOTE: This macro uses the $RUBY variable to perform the check.
+# AX_WITH_PROG([RUBY],[ruby],[VALUE-IF-NOT-FOUND],[PATH]) can be used to
+# set that variable prior to running this macro. The $RUBY_VERSION
+# variable will be valorized with the detected version.
+#
+# LICENSE
+#
+# Copyright (c) 2009 Francesco Salvestrini <salvestrini@users.sourceforge.net>
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
+
+#serial 11
+
+AC_DEFUN([AX_PROG_RUBY_VERSION],[
+ AC_REQUIRE([AC_PROG_SED])
+ AC_REQUIRE([AC_PROG_GREP])
+
+ AS_IF([test -n "$RUBY"],[
+ ax_ruby_version="$1"
+
+ AC_MSG_CHECKING([for ruby version])
+ changequote(<<,>>)
+ ruby_version=`$RUBY --version 2>&1 | $GREP "^ruby " | $SED -e 's/^.* \([0-9]*\.[0-9]*\.[0-9]*\) .*/\1/'`
+ changequote([,])
+ AC_MSG_RESULT($ruby_version)
+
+ AC_SUBST([RUBY_VERSION],[$ruby_version])
+
+ AX_COMPARE_VERSION([$ax_ruby_version],[le],[$ruby_version],[
+ :
+ $2
+ ],[
+ :
+ $3
+ ])
+ ],[
+ AC_MSG_WARN([could not find the ruby interpreter])
+ $3
+ ])
+])
diff --git a/m4/ax_ruby_devel.m4 b/m4/ax_ruby_devel.m4
new file mode 100644
index 0000000..d39e1d3
--- /dev/null
+++ b/m4/ax_ruby_devel.m4
@@ -0,0 +1,214 @@
+# ===========================================================================
+# http://autoconf-archive.cryp.to/ax_ruby_devel.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_RUBY_DEVEL([version])
+#
+# DESCRIPTION
+#
+# This macro checks for Ruby and tries to get the include path to
+# 'ruby.h'. It provides the $(RUBY_CFLAGS) and $(RUBY_LDFLAGS) output
+# variables. It also exports $(RUBY_EXTRA_LIBS) for embedding Ruby in your
+# code.
+#
+# You can search for some particular version of Ruby by passing a
+# parameter to this macro, for example "1.8.6".
+#
+# LICENSE
+#
+# Copyright (c) 2008 Rafal Rzepecki <divided.mind@gmail.com>
+# Copyright (c) 2008 Sebastian Huber <sebastian-huber@web.de>
+# Copyright (c) 2008 Alan W. Irwin <irwin@beluga.phys.uvic.ca>
+# Copyright (c) 2008 Rafael Laboissiere <rafael@laboissiere.net>
+# Copyright (c) 2008 Andrew Collier <colliera@ukzn.ac.za>
+# Copyright (c) 2008 Matteo Settenvini <matteo@member.fsf.org>
+# Copyright (c) 2008 Horst Knorr <hk_classes@knoda.org>
+#
+# 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 3 of the License, or (at your
+# option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception, the respective Autoconf Macro's copyright owner
+# gives unlimited permission to copy, distribute and modify the configure
+# scripts that are the output of Autoconf when processing the Macro. You
+# need not follow the terms of the GNU General Public License when using
+# or distributing such scripts, even though portions of the text of the
+# Macro appear in them. The GNU General Public License (GPL) does govern
+# all other use of the material that constitutes the Autoconf Macro.
+#
+# This special exception to the GPL applies to versions of the Autoconf
+# Macro released by the Autoconf Archive. When you make and distribute a
+# modified version of the Autoconf Macro, you may extend this special
+# exception to the GPL to apply to your modified version as well.
+AC_DEFUN([AX_RUBY_DEVEL],[
+ AC_REQUIRE([AX_WITH_RUBY])
+ AS_IF([test -n "$1"], [AX_PROG_RUBY_VERSION([$1])])
+
+ #
+ # Check if you have mkmf, else fail
+ #
+ AC_MSG_CHECKING([for the mkmf Ruby package])
+ ac_mkmf_result=`$RUBY -rmkmf -e ";" 2>&1`
+ if test -z "$ac_mkmf_result"; then
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ AC_MSG_WARN([cannot import Ruby module "mkmf".
+Please check your Ruby installation. The error was:
+$ac_distutils_result])
+ fi
+
+ #
+ # Check for Ruby include path
+ #
+ if test -z "$RUBY_CFLAGS"; then
+ #
+ # Check for Ruby cflags
+ #
+ AC_MSG_CHECKING([for Ruby cflags])
+ if test -z "$RUBY_CFLAGS"; then
+ RUBY_CFLAGS=`$RUBY -rmkmf -e 'print RbConfig::CONFIG.fetch(%q(CFLAGS))'`
+ fi
+ AC_MSG_RESULT([$RUBY_CFLAGS])
+
+ #
+ # Check for Ruby include path
+ #
+ AC_MSG_CHECKING([for Ruby include path])
+ ruby_path=`$RUBY -rmkmf -e 'c = RbConfig::CONFIG; print c.has_key?(%q(rubyhdrdir)) ? \
+ c.fetch(%q(rubyhdrdir)) : c.fetch(%q(archdir))'`
+
+ ruby_arch=`$RUBY -rmkmf -e 'print RbConfig::CONFIG.fetch(%q(arch))'`
+
+ if test -n "${ruby_path}"; then
+ #
+ # For some reason ruby 1.9.1 on linux seems to put its
+ # config.h file in ${ruby_path}/${ruby_arch}/ruby/config.h
+ # Aside from the fact that it is WRONG to include your own
+ # config.h file, it means we can't use the headers unless we
+ # add both paths.
+ #
+ if test -d "${ruby_path}/${ruby_arch}"; then
+ ruby_path=" -I${ruby_path} -I${ruby_path}/${ruby_arch}"
+ else
+ ruby_path=" -I${ruby_path}"
+ fi
+ fi
+
+ RUBY_CFLAGS="$RUBY_CFLAGS $ruby_path"
+ AC_MSG_RESULT([$ruby_path])
+ fi
+
+ AC_SUBST([RUBY_CFLAGS])
+
+ if test -z "$RUBY_LDFLAGS"; then
+ #
+ # Check for Ruby library path
+ #
+ AC_MSG_CHECKING([for Ruby library path])
+ if test -z "$RUBY_LIBRARY_PATH"; then
+ RUBY_LIBRARY_PATH=`$RUBY -rmkmf -e 'print RbConfig::CONFIG.fetch(%q(libdir))'`
+ if test -n "${RUBY_LIBRARY_PATH}"; then
+ RUBY_LIBRARY_PATH=" -L$RUBY_LIBRARY_PATH"
+ fi
+ fi
+
+ AC_MSG_RESULT([$RUBY_LIBRARY_PATH])
+
+ #
+ # Check for Ruby linking flags
+ #
+ AC_MSG_CHECKING([for Ruby linking flags])
+
+ RUBY_LDFLAGS=`$RUBY -rmkmf -e 'print RbConfig::CONFIG.fetch(%q(LIBRUBYARG_SHARED))'`
+ AC_MSG_RESULT([$RUBY_LDFLAGS])
+
+ RUBY_LDFLAGS="${RUBY_LIBRARY_PATH} ${RUBY_LDFLAGS}"
+ fi
+
+ AC_SUBST([RUBY_LDFLAGS])
+
+ #
+ # Check for site packages
+ #
+ AC_MSG_CHECKING([for Ruby site-packages path])
+ if test -z "$RUBY_SITE_PKG"; then
+ RUBY_SITE_PKG=`$RUBY -rmkmf -e 'print RbConfig::CONFIG.fetch(%q(sitearchdir))'`
+ fi
+ AC_MSG_RESULT([$RUBY_SITE_PKG])
+ AC_SUBST([RUBY_SITE_PKG])
+
+ #
+ # libraries which must be linked in when embedding
+ #
+ AC_MSG_CHECKING([for Ruby extra libraries])
+ if test -z "$RUBY_EXTRA_LIBS"; then
+ RUBY_EXTRA_LIBS=`$RUBY -rmkmf -e 'print RbConfig::CONFIG.fetch(%q(SOLIBS))'`
+ fi
+ AC_MSG_RESULT([$RUBY_EXTRA_LIBS])
+ AC_SUBST(RUBY_EXTRA_LIBS)
+
+ #
+ # 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
+ #
+ AC_MSG_CHECKING([consistency of all components of ruby development environment])
+ AC_LANG_PUSH([C])
+ # save current global flags
+ ac_save_LIBS="$LIBS"
+ LIBS="$ac_save_LIBS $RUBY_LDFLAGS"
+ ac_save_CFLAGS="$CFLAGS"
+ CFLAGS="$ac_save_CFLAGS $RUBY_CFLAGS"
+ AC_LINK_IFELSE(
+ [AC_LANG_PROGRAM([#include <ruby.h>],[ruby_init()])],
+ [rubyexists=yes],
+ [rubyexists=no])
+
+ AC_MSG_RESULT([$rubyexists])
+
+ if test ! "$rubyexists" = "yes"; then
+ AC_MSG_WARN([
+ 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.
+ ============================================================================
+ ])
+ RUBY_VERSION=""
+ fi
+ AC_LANG_POP
+ # turn back to default flags
+ CFLAGS="$ac_save_CFLAGS"
+ LIBS="$ac_save_LIBS"
+
+ #
+ # all done!
+ #
+])
+
diff --git a/m4/ax_with_prog.m4 b/m4/ax_with_prog.m4
new file mode 100644
index 0000000..f337c05
--- /dev/null
+++ b/m4/ax_with_prog.m4
@@ -0,0 +1,70 @@
+# ===========================================================================
+# http://www.gnu.org/software/autoconf-archive/ax_with_prog.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_WITH_PROG([VARIABLE],[program],[VALUE-IF-NOT-FOUND],[PATH])
+#
+# DESCRIPTION
+#
+# Locates an installed program binary, placing the result in the precious
+# variable VARIABLE. Accepts a present VARIABLE, then --with-program, and
+# failing that searches for program in the given path (which defaults to
+# the system path). If program is found, VARIABLE is set to the full path
+# of the binary; if it is not found VARIABLE is set to VALUE-IF-NOT-FOUND
+# if provided, unchanged otherwise.
+#
+# A typical example could be the following one:
+#
+# AX_WITH_PROG(PERL,perl)
+#
+# NOTE: This macro is based upon the original AX_WITH_PYTHON macro from
+# Dustin J. Mitchell <dustin@cs.uchicago.edu>.
+#
+# LICENSE
+#
+# Copyright (c) 2008 Francesco Salvestrini <salvestrini@users.sourceforge.net>
+# Copyright (c) 2008 Dustin J. Mitchell <dustin@cs.uchicago.edu>
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
+
+#serial 16
+
+AC_DEFUN([AX_WITH_PROG],[
+ AC_PREREQ([2.61])
+
+ pushdef([VARIABLE],$1)
+ pushdef([EXECUTABLE],$2)
+ pushdef([VALUE_IF_NOT_FOUND],$3)
+ pushdef([PATH_PROG],$4)
+
+ AC_ARG_VAR(VARIABLE,Absolute path to EXECUTABLE executable)
+
+ AS_IF(test -z "$VARIABLE",[
+ AC_MSG_CHECKING(whether EXECUTABLE executable path has been provided)
+ AC_ARG_WITH(EXECUTABLE,AS_HELP_STRING([--with-EXECUTABLE=[[[PATH]]]],absolute path to EXECUTABLE executable), [
+ AS_IF([test "$withval" != yes && test "$withval" != no],[
+ VARIABLE="$withval"
+ AC_MSG_RESULT($VARIABLE)
+ ],[
+ VARIABLE=""
+ AC_MSG_RESULT([no])
+ AS_IF([test "$withval" != no], [
+ AC_PATH_PROG([]VARIABLE[],[]EXECUTABLE[],[]VALUE_IF_NOT_FOUND[],[]PATH_PROG[])
+ ])
+ ])
+ ],[
+ AC_MSG_RESULT([no])
+ AC_PATH_PROG([]VARIABLE[],[]EXECUTABLE[],[]VALUE_IF_NOT_FOUND[],[]PATH_PROG[])
+ ])
+ ])
+
+ popdef([PATH_PROG])
+ popdef([VALUE_IF_NOT_FOUND])
+ popdef([EXECUTABLE])
+ popdef([VARIABLE])
+])
diff --git a/m4/fr_check_struct_has_member.m4 b/m4/fr_check_struct_has_member.m4
new file mode 100644
index 0000000..57d8b02
--- /dev/null
+++ b/m4/fr_check_struct_has_member.m4
@@ -0,0 +1,36 @@
+dnl #
+dnl # Look for a header file in a number of places.
+dnl #
+dnl # Usage: FR_CHECK_STRUCT_HAS_MEMBER([#include <foo.h>], [struct foo], member)
+dnl # If the member is defined, then the variable
+dnl # ac_cv_type_struct_foo_has_member is set to 'yes'
+dnl #
+AC_DEFUN([FR_CHECK_STRUCT_HAS_MEMBER], [
+ AC_MSG_CHECKING([for $3 in $2])
+
+dnl BASED on 'offsetof':
+dnl #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+dnl
+
+ AC_TRY_COMPILE([
+$1
+#ifdef HAVE_STDDEF_H
+#include <stddef.h>
+#endif
+#ifndef offsetof
+#define offsetof(TYPE, MEMBER) ((int) &((TYPE *)0)->MEMBER)
+#endif
+],
+ [ int foo = offsetof($2, $3) ],
+ has_element=" ",
+ has_element=)
+
+ ac_safe_type=`echo "$2" | sed 'y% %_%'`
+ if test "x$has_element" != "x"; then
+ AC_MSG_RESULT(yes)
+ eval "ac_cv_type_${ac_safe_type}_has_$3=yes"
+ else
+ AC_MSG_RESULT(no)
+ eval "ac_cv_type_${ac_safe_type}_has_$3="
+ fi
+])
diff --git a/m4/fr_check_type_include.m4 b/m4/fr_check_type_include.m4
new file mode 100644
index 0000000..66aa532
--- /dev/null
+++ b/m4/fr_check_type_include.m4
@@ -0,0 +1,21 @@
+dnl #
+dnl # FR_CHECK_TYPE_INCLUDE([#includes ...], type, default-C-types)
+dnl #
+dnl # This function is like AC_CHECK_TYPE, but you can give this one
+dnl # a list of include files to check.
+dnl #
+AC_DEFUN([FR_CHECK_TYPE_INCLUDE],
+[
+ AC_CACHE_CHECK(for $2, ac_cv_type_$2,
+ [ ac_cv_type_$2=no
+ AC_TRY_COMPILE($1,
+ [$2 foo],
+ ac_cv_type_$2=yes,
+ )
+ ]
+ )
+
+ if test "$ac_cv_type_$2" != "yes"; then
+ AC_DEFINE($2, $3, $4)
+ fi
+])
diff --git a/m4/fr_have_bounded_attribute.m4 b/m4/fr_have_bounded_attribute.m4
new file mode 100644
index 0000000..50c3305
--- /dev/null
+++ b/m4/fr_have_bounded_attribute.m4
@@ -0,0 +1,26 @@
+dnl #
+dnl # Check if we have __attribute__((__bounded__)) (usually only OpenBSD with GCC)
+dnl #
+AC_DEFUN([FR_HAVE_BOUNDED_ATTRIBUTE],[
+ AC_CACHE_CHECK([for __attribute__((__bounded__)) support in compiler], [ax_cv_cc_bounded_attribute],[
+ CFLAGS_SAVED=$CFLAGS
+ CFLAGS="$CFLAGS -Werror"
+ AC_RUN_IFELSE(
+ [
+ AC_LANG_SOURCE([
+ void test(char *buff) __attribute__ ((__bounded__ (__string__, 1, 1)));
+ int main(int argc, char **argv) {
+ if ((argc < 0) || !argv) return 1; /* -Werror=unused-parameter */
+ return 0;
+ }
+ ])
+ ],
+ [ax_cv_cc_bounded_attribute=yes],
+ [ax_cv_cc_bounded_attribute=no]
+ )
+ CFLAGS="$CFLAGS_SAVED"
+ ])
+ if test "x$ax_cv_cc_bounded_attribute" = "xyes"; then
+ AC_DEFINE(HAVE_ATTRIBUTE_BOUNDED, 1, [Define if your compiler supports the __bounded__ attribute (usually OpenBSD gcc).])
+ fi
+])
diff --git a/m4/fr_have_builtin_bswap64.m4 b/m4/fr_have_builtin_bswap64.m4
new file mode 100644
index 0000000..ab205c9
--- /dev/null
+++ b/m4/fr_have_builtin_bswap64.m4
@@ -0,0 +1,23 @@
+dnl #
+dnl # Check if we have the bwsap64 builtin
+dnl #
+AC_DEFUN([FR_HAVE_BUILTIN_BSWAP64],
+[
+ AC_CACHE_CHECK([for __builtin_bswap64 support in compiler], [ax_cv_cc_builtin_bswap64],[
+ AC_RUN_IFELSE(
+ [
+ AC_LANG_SOURCE([
+ int main(int argc, char **argv) {
+ if ((argc < 0) || !argv) return 1; /* -Werror=unused-parameter */
+ return (__builtin_bswap64(0));
+ }
+ ])
+ ],
+ [ax_cv_cc_builtin_bswap64=yes],
+ [ax_cv_cc_builtin_bswap64=no]
+ )
+ ])
+ if test "x$ax_cv_cc_builtin_bswap64" = "xyes"; then
+ AC_DEFINE([HAVE_BUILTIN_BSWAP_64],1,[Define if the compiler supports __builtin_bswap64])
+ fi
+])
diff --git a/m4/fr_have_builtin_choose_expr.m4 b/m4/fr_have_builtin_choose_expr.m4
new file mode 100644
index 0000000..950bc55
--- /dev/null
+++ b/m4/fr_have_builtin_choose_expr.m4
@@ -0,0 +1,24 @@
+dnl #
+dnl # Check if we have the choose expr builtin
+dnl #
+AC_DEFUN([FR_HAVE_BUILTIN_CHOOSE_EXPR],
+[
+ AC_CACHE_CHECK([for __builtin_choose_expr support in compiler], [ax_cv_cc_builtin_choose_expr],[
+ AC_RUN_IFELSE(
+ [
+ AC_LANG_SOURCE(
+ [
+ int main(int argc, char **argv) {
+ if ((argc < 0) || !argv) return 1; /* -Werror=unused-parameter */
+ return __builtin_choose_expr(0, 1, 0);
+ }
+ ])
+ ],
+ [ax_cv_cc_builtin_choose_expr=yes],
+ [ax_cv_cc_builtin_choose_expr=no]
+ )
+ ])
+ if test "x$ax_cv_cc_builtin_choose_expr" = "xyes"; then
+ AC_DEFINE([HAVE_BUILTIN_CHOOSE_EXPR],1,[Define if the compiler supports __builtin_choose_expr])
+ fi
+])
diff --git a/m4/fr_have_builtin_types_compatible_p.m4 b/m4/fr_have_builtin_types_compatible_p.m4
new file mode 100644
index 0000000..6e5b02c
--- /dev/null
+++ b/m4/fr_have_builtin_types_compatible_p.m4
@@ -0,0 +1,24 @@
+dnl #
+dnl # Check if we have the types compatible p builtin
+dnl #
+AC_DEFUN([FR_HAVE_BUILTIN_TYPES_COMPATIBLE_P],
+[
+ AC_CACHE_CHECK([for __builtin_types_compatible_p support in compiler], [ax_cv_cc_builtin_types_compatible_p],[
+ AC_RUN_IFELSE(
+ [
+ AC_LANG_SOURCE(
+ [
+ int main(int argc, char **argv) {
+ if ((argc < 0) || !argv) return 1; /* -Werror=unused-parameter */
+ return !(__builtin_types_compatible_p(char *, char *));
+ }
+ ])
+ ],
+ [ax_cv_cc_builtin_types_compatible_p=yes],
+ [ax_cv_cc_builtin_types_compatible_p=no]
+ )
+ ])
+ if test "x$ax_cv_cc_builtin_types_compatible_p" = "xyes"; then
+ AC_DEFINE([HAVE_BUILTIN_TYPES_COMPATIBLE_P],1,[Define if the compiler supports __builtin_types_compatible_p])
+ fi
+])
diff --git a/m4/fr_init_module.m4 b/m4/fr_init_module.m4
new file mode 100644
index 0000000..91ac4ff
--- /dev/null
+++ b/m4/fr_init_module.m4
@@ -0,0 +1,16 @@
+dnl Macro to set the module name and other useful common functions
+dnl
+dnl Usages:
+dnl FR_INIT_MODULE([rlm_example])
+dnl FR_INIT_MODULE([rlm_example], [the example module])
+dnl
+AC_DEFUN([FR_INIT_MODULE],
+[
+ AC_DEFUN([modname],$1)
+ AC_DEFUN([modname_useropt],[m4_bpatsubst([]modname,[[-+.]],[_])])
+
+ AC_ARG_WITH([$1],
+ [AS_HELP_STRING([--without-$1],[build without ]ifelse([$2],[],[$1],[$2]))])
+])
+
+AC_DEFUN([FR_INIT_LIBRARY], m4_defn([FR_INIT_MODULE]))
diff --git a/m4/fr_module_start_tests.m4 b/m4/fr_module_start_tests.m4
new file mode 100644
index 0000000..e4117c4
--- /dev/null
+++ b/m4/fr_module_start_tests.m4
@@ -0,0 +1,250 @@
+dnl Where module/library report is stored
+AC_DEFUN([FR_REPORT_FILE], [config.report])
+
+dnl Where feature list is built up
+AC_DEFUN([FR_REPORT_TMP], [config.report.tmp])
+
+dnl Space prefix for non-first lines of feature list
+AC_DEFUN([FR_REPORT_PREFIX], [ ])
+
+dnl
+dnl Store status about module configure state.
+dnl
+dnl Usage:
+dnl FR_MODULE_STATUS([status])
+dnl FR_MODULE_STATUS([status], [reason])
+dnl
+dnl First argument is the status to report, likely "OK",
+dnl "skipping" or "disabled".
+dnl
+dnl Second optional argument is the reason for skipping this
+dnl module (likely dependencies not met).
+dnl
+AC_DEFUN([FR_MODULE_STATUS],[
+ifelse([$2], [], [
+fr_status="$1"
+], [
+fr_status="$1 ($2)"
+])])
+
+
+dnl
+dnl FR_MODULE_FAIL
+dnl
+dnl Usage:
+dnl FR_MODULE_FAIL([reason])
+dnl
+dnl Add a(nother) reason why the module will not be built.
+dnl
+AC_DEFUN([FR_MODULE_FAIL], [
+fail="$fail $1"
+])
+
+
+dnl
+dnl FR_MODULE_START_TESTS
+dnl
+dnl Usage:
+dnl FR_MODULE_START_TESTS
+dnl
+dnl Set up ready to do module-specific tests. Clears variables and
+dnl adds code to output a header before the tests to make the
+dnl configure output easier to read.
+dnl
+AC_DEFUN([FR_MODULE_START_TESTS],
+[
+fail=
+fr_status=
+fr_features=
+: > "FR_REPORT_FILE"
+: > "FR_REPORT_TMP"
+
+m4_divert_text([SHELL_FN], [
+echo
+echo Running tests for modname
+echo
+])
+
+if test x"$with_[]modname_useropt" != xno; then
+])
+
+AC_DEFUN([FR_LIBRARY_START_TESTS], m4_defn([FR_MODULE_START_TESTS]))
+
+
+dnl
+dnl FR_MODULE_END_TESTS
+dnl
+dnl Usage:
+dnl FR_MODULE_END_TESTS
+dnl FR_MODULE_END_TESTS([nostrict])
+dnl
+dnl If passed "nostrict", checks will be made for the
+dnl enable_strict_dependencies flag.
+dnl
+dnl Called at the end of module-specific tests. This outputs
+dnl information on whether the module is disabled or not, or why
+dnl configuration failed. It also stores the status for a summary
+dnl to be printed at the end of the main configure script.
+dnl
+AC_DEFUN([FR_MODULE_END_TESTS], [
+ targetname=modname
+else
+ targetname=
+ echo \*\*\* module modname is disabled.
+ FR_MODULE_STATUS([disabled])
+fi
+
+if test x"$fail" != x""; then
+ targetname=""
+
+ifelse([$1], [nostrict], [], [
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ AC_MSG_ERROR([set --without-]modname[ to disable it explicitly.])
+ else
+])
+ AC_MSG_WARN([silently not building ]modname[.])
+ AC_MSG_WARN([FAILURE: ]modname[ requires: $fail.]);
+ fail="$(echo $fail)"
+ FR_MODULE_STATUS([skipping], [requires $fail])
+ fr_features=
+ifelse([$1], [nostrict], [], [
+ fi
+])
+else
+ FR_MODULE_STATUS([OK])
+fi
+
+if test x"$fr_features" = x""; then
+ $as_echo "$fr_status" > "FR_REPORT_FILE"
+else
+ $as_echo_n "$fr_status ... " > "FR_REPORT_FILE"
+ cat "FR_REPORT_TMP" >> "FR_REPORT_FILE"
+fi
+
+rm "FR_REPORT_TMP"
+
+AC_SUBST(targetname)
+])
+
+AC_DEFUN([FR_LIBRARY_END_TESTS], m4_defn([FR_MODULE_END_TESTS]))
+
+
+dnl
+dnl FR_MODULE_FEATURE
+dnl
+dnl Usage:
+dnl FR_MODULE_FEATURE([name], [description])
+dnl
+dnl Declare that a module feature is or is not available (but the
+dnl module can still be built).
+dnl
+AC_DEFUN([FR_MODULE_FEATURE], [
+if echo "$fr_features" | grep -q "+$1+"; then :
+dnl feature already declared
+else :
+ fr_report_prefix=""
+ if test x"$fr_features" != x""; then
+ fr_report_prefix="FR_REPORT_PREFIX"
+ fi
+ $as_echo "$fr_report_prefix""$2" >> FR_REPORT_TMP
+ fr_features="$fr_features +$1+"
+fi
+])
+
+dnl
+dnl FR_MODULE_TEST_FAIL_DO
+dnl
+dnl Usage:
+dnl FR_MODULE_TEST_FAIL_DO([commands])
+dnl
+dnl Run commands when the module tests fail and the module is not
+dnl going to be built.
+dnl
+AC_DEFUN([FR_MODULE_TEST_FAIL_DO], [
+if test x"$fail" != x""; then :
+ $1
+fi
+])
+
+AC_DEFUN([FR_LIBRARY_TEST_FAIL_DO], m4_defn([FR_MODULE_TEST_FAIL_DO]))
+
+
+dnl
+dnl FR_MODULE_TEST_PASS_DO
+dnl
+dnl Usage:
+dnl FR_MODULE_TEST_PASS_DO([commands])
+dnl
+dnl Run commands when the module tests succeed and the module is
+dnl going to be built.
+dnl
+AC_DEFUN([FR_MODULE_TEST_PASS_DO], [
+if test x"$fail" = x""; then :
+ $1
+fi
+])
+
+AC_DEFUN([FR_LIBRARY_TEST_PASS_DO], m4_defn([FR_MODULE_TEST_PASS_DO]))
+
+
+
+dnl
+dnl FR_MODULE_REPORT
+dnl
+dnl Usage:
+dnl FR_MODULE_REPORT
+dnl
+dnl Outputs a summary list of all modules and any configure errors.
+dnl
+AC_DEFUN([FR_MODULE_REPORT], [
+module_list=$(find src/modules/ -type d -name 'rlm_*' -print | sort)
+
+echo
+echo Module configure status report
+echo ------------------------------
+
+for module in $module_list; do
+ module_name="$(basename $module)"
+ module_print="$(echo "$module_name ........................" | cut -c 1-25)"
+ module_status="OK"
+
+ if test -r $module/configure.ac; then
+ if test -r $module/FR_REPORT_FILE; then
+ module_status=$(cat $module/FR_REPORT_FILE)
+ fi
+ fi
+
+ $as_echo "$module_print $module_status"
+done
+])
+
+
+dnl
+dnl FR_LIBRARY_REPORT
+dnl
+dnl Usage:
+dnl FR_LIBRARY_REPORT
+dnl
+dnl Outputs a summary list of all libraries and any configure errors.
+dnl
+AC_DEFUN([FR_LIBRARY_REPORT], [
+library_list=$(find src/lib/ -mindepth 1 -maxdepth 1 -type d -print | sort)
+
+echo
+echo Library configure status report
+echo -------------------------------
+
+for library in $library_list; do
+ library_name="$(basename $library)"
+ library_print="$(echo "$library_name ........................" | cut -c 1-25)"
+ library_status="OK"
+
+ if test -r $library/configure.ac; then
+ if test -r $library/FR_REPORT_FILE; then
+ library_status=$(cat $library/FR_REPORT_FILE)
+ fi
+ fi
+
+ echo "$library_print $library_status"
+done
+])
diff --git a/m4/fr_smart_check_include.m4 b/m4/fr_smart_check_include.m4
new file mode 100644
index 0000000..e7d4443
--- /dev/null
+++ b/m4/fr_smart_check_include.m4
@@ -0,0 +1,133 @@
+dnl #
+dnl # Look for a header file in a number of places.
+dnl #
+dnl # FR_SMART_CHECK_INCLUDE(foo.h, [ #include <other.h> ])
+dnl #
+AC_DEFUN([FR_SMART_CHECK_INCLUDE], [
+
+ac_safe=`echo "$1" | sed 'y%./+-%__pm%'`
+old_CPPFLAGS="$CPPFLAGS"
+smart_include=
+dnl # The default directories we search in (in addition to the compilers search path)
+smart_include_dir="/usr/local/include /opt/include"
+
+dnl # Our local versions
+_smart_try_dir=
+_smart_include_dir=
+
+dnl # Add variants with the different prefixes and one with no prefix
+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
+
+dnl #
+dnl # Try any user-specified directory first otherwise we may pick up
+dnl # the wrong version.
+dnl #
+if test "x$_smart_try_dir" != "x"; then
+ for try in $_smart_try_dir; do
+ AC_MSG_CHECKING([for $1 in $try])
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ AC_TRY_COMPILE([$2
+ #include <$1>],
+ [int a = 1;],
+ [
+ smart_include="-isystem $try"
+ AC_MSG_RESULT(yes)
+ break
+ ],
+ [
+ smart_include=
+ AC_MSG_RESULT(no)
+ ])
+ done
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+dnl #
+dnl # Try using the default includes (with prefixes).
+dnl #
+if test "x$smart_include" = "x"; then
+ for _prefix in $smart_prefix; do
+ AC_MSG_CHECKING([for ${_prefix}/$1])
+
+ AC_TRY_COMPILE([$2
+ #include <$1>],
+ [int a = 1;],
+ [
+ smart_include="-isystem ${_prefix}/"
+ AC_MSG_RESULT(yes)
+ break
+ ],
+ [
+ smart_include=
+ AC_MSG_RESULT(no)
+ ])
+ done
+fi
+
+dnl #
+dnl # Try using the default includes (without prefixes).
+dnl #
+if test "x$smart_include" = "x"; then
+ AC_MSG_CHECKING([for $1])
+
+ AC_TRY_COMPILE([$2
+ #include <$1>],
+ [int a = 1;],
+ [
+ smart_include=" "
+ AC_MSG_RESULT(yes)
+ break
+ ],
+ [
+ smart_include=
+ AC_MSG_RESULT(no)
+ ])
+fi
+
+dnl #
+dnl # Try to guess possible locations.
+dnl #
+if test "x$smart_include" = "x"; then
+
+ for try in $_smart_include_dir; do
+ AC_MSG_CHECKING([for $1 in $try])
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ AC_TRY_COMPILE([$2
+ #include <$1>],
+ [int a = 1;],
+ [
+ smart_include="-isystem $try"
+ AC_MSG_RESULT(yes)
+ break
+ ],
+ [
+ smart_include=
+ AC_MSG_RESULT(no)
+ ])
+ done
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+dnl #
+dnl # Found it, set the appropriate variable.
+dnl #
+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
+
+dnl #
+dnl # Consume prefix, it's not likely to be used
+dnl # between multiple calls.
+dnl #
+smart_prefix=
+])
diff --git a/m4/fr_smart_check_lib.m4 b/m4/fr_smart_check_lib.m4
new file mode 100644
index 0000000..16ac5b3
--- /dev/null
+++ b/m4/fr_smart_check_lib.m4
@@ -0,0 +1,97 @@
+dnl #
+dnl # Look for a library in a number of places.
+dnl #
+dnl # FR_SMART_CHECK_LIB(library, function)
+dnl #
+AC_DEFUN([FR_SMART_CHECK_LIB], [
+
+sm_lib_safe=`echo "$1" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "$2" | sed 'y%./+-%__p_%'`
+
+dnl #
+dnl # We pass all arguments for linker testing in CCPFLAGS as these
+dnl # will be passed to the compiler (then linker) first.
+dnl #
+dnl # The linker will search through -L directories in the order they
+dnl # appear on the command line. Unfortunately the same rules appear
+dnl # to apply to directories specified with --sysroot, so we must
+dnl # pass the user specified directory first.
+dnl #
+dnl # Really we should be using LDFLAGS (-L<dir>) for this.
+dnl #
+old_LIBS="$LIBS"
+old_CPPFLAGS="$CPPFLAGS"
+smart_lib=
+smart_ldflags=
+smart_lib_dir=
+
+dnl #
+dnl # Try first any user-specified directory, otherwise we may pick up
+dnl # the wrong version.
+dnl #
+if test "x$smart_try_dir" != "x"; then
+ for try in $smart_try_dir; do
+ AC_MSG_CHECKING([for $2 in -l$1 in $try])
+ LIBS="-l$1 $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ AC_TRY_LINK([extern char $2();],
+ [$2()],
+ [
+ smart_lib="-l$1"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ AC_MSG_RESULT(yes)
+ break
+ ],
+ [AC_MSG_RESULT(no)])
+ done
+ LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+dnl #
+dnl # Try using the default library path
+dnl #
+if test "x$smart_lib" = "x"; then
+ AC_MSG_CHECKING([for $2 in -l$1])
+ LIBS="-l$1 $old_LIBS"
+ AC_TRY_LINK([extern char $2();],
+ [$2()],
+ [
+ smart_lib="-l$1"
+ AC_MSG_RESULT(yes)
+ ],
+ [AC_MSG_RESULT(no)])
+ LIBS="$old_LIBS"
+fi
+
+dnl #
+dnl # Try to guess possible locations.
+dnl #
+if test "x$smart_lib" = "x"; then
+ for try in /usr/local/lib /opt/lib; do
+ AC_MSG_CHECKING([for $2 in -l$1 in $try])
+ LIBS="-l$1 $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ AC_TRY_LINK([extern char $2();],
+ [$2()],
+ [
+ smart_lib="-l$1"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ AC_MSG_RESULT(yes)
+ break
+ ],
+ [AC_MSG_RESULT(no)])
+ done
+ LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+dnl #
+dnl # Found it, set the appropriate variable.
+dnl #
+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
+])
diff --git a/m4/fr_tls.m4 b/m4/fr_tls.m4
new file mode 100644
index 0000000..56ad7f2
--- /dev/null
+++ b/m4/fr_tls.m4
@@ -0,0 +1,67 @@
+dnl #
+dnl # Figure out which storage class specifier for Thread Local Storage is supported by the compiler
+dnl #
+AC_DEFUN([FR_TLS],
+[
+dnl #
+dnl # See if the compilation works with __thread, for thread-local storage
+dnl #
+ AC_MSG_CHECKING(for __thread support in compiler)
+ AC_RUN_IFELSE(
+ [AC_LANG_SOURCE(
+ [[
+ static __thread int val;
+ int main(int argc, char **argv) {
+ val = 0;
+ return val;
+ }
+ ]])
+ ],[have_tls=yes],[have_tls=no],[have_tls=no])
+ AC_MSG_RESULT($have_tls)
+ if test "x$have_tls" = "xyes"; then
+ AC_DEFINE([TLS_STORAGE_CLASS],[__thread],[Define if the compiler supports a thread local storage class])
+ fi
+
+dnl #
+dnl # __declspec(thread) does exactly the same thing as __thread, but is supported by MSVS
+dnl #
+ if test "x$have_tls" = "xno"; then
+ AC_MSG_CHECKING(for __declspec(thread) support in compiler)
+ AC_RUN_IFELSE(
+ [AC_LANG_SOURCE(
+ [[
+ static _Thread_local int val;
+ int main(int argc, char **argv) {
+ val = 0;
+ return val;
+ }
+ ]])
+ ],[have_tls=yes],[have_tls=no],[have_tls=no])
+ AC_MSG_RESULT($have_tls)
+ if test "x$have_tls" = "xyes"; then
+ AC_DEFINE([TLS_STORAGE_CLASS],[__declspec(thread)],[Define if the compiler supports a thread local storage class])
+ fi
+ fi
+dnl #
+dnl # _Thread_local does exactly the same thing as __thread, but it's standards compliant with C11.
+dnl # we, however, state we are only compliant with C99, so the compiler will probably emit warnings
+dnl # if we use it. So save it as a last resort.
+dnl #
+ if test "x$have_tls" = "xno"; then
+ AC_MSG_CHECKING(for _Thread_local support in compiler)
+ AC_RUN_IFELSE(
+ [AC_LANG_SOURCE(
+ [[
+ static _Thread_local int val;
+ int main(int argc, char **argv) {
+ val = 0;
+ return val;
+ }
+ ]])
+ ],[have_tls=yes],[have_tls=no],[have_tls=no])
+ AC_MSG_RESULT($have_tls)
+ if test "x$have_tls" = "xyes"; then
+ AC_DEFINE([TLS_STORAGE_CLASS],[_Thread_local],[Define if the compiler supports a thread local storage class])
+ fi
+ fi
+])
diff --git a/m4/libcurl_check_config.m4 b/m4/libcurl_check_config.m4
new file mode 100644
index 0000000..dabf18b
--- /dev/null
+++ b/m4/libcurl_check_config.m4
@@ -0,0 +1,251 @@
+# LIBCURL_CHECK_CONFIG ([DEFAULT-ACTION], [MINIMUM-VERSION],
+# [ACTION-IF-YES], [ACTION-IF-NO])
+# ----------------------------------------------------------
+# David Shaw <dshaw@jabberwocky.com> May-09-2006
+#
+# Checks for libcurl. DEFAULT-ACTION is the string yes or no to
+# specify whether to default to --with-libcurl or --without-libcurl.
+# If not supplied, DEFAULT-ACTION is yes. MINIMUM-VERSION is the
+# minimum version of libcurl to accept. Pass the version as a regular
+# version number like 7.10.1. If not supplied, any version is
+# accepted. ACTION-IF-YES is a list of shell commands to run if
+# libcurl was successfully found and passed the various tests.
+# ACTION-IF-NO is a list of shell commands that are run otherwise.
+# Note that using --without-libcurl does run ACTION-IF-NO.
+#
+# This macro #defines HAVE_LIBCURL if a working libcurl setup is
+# found, and sets @LIBCURL@ and @LIBCURL_CPPFLAGS@ to the necessary
+# values. Other useful defines are LIBCURL_FEATURE_xxx where xxx are
+# the various features supported by libcurl, and LIBCURL_PROTOCOL_yyy
+# where yyy are the various protocols supported by libcurl. Both xxx
+# and yyy are capitalized. See the list of AH_TEMPLATEs at the top of
+# the macro for the complete list of possible defines. Shell
+# variables $libcurl_feature_xxx and $libcurl_protocol_yyy are also
+# defined to 'yes' for those features and protocols that were found.
+# Note that xxx and yyy keep the same capitalization as in the
+# curl-config list (e.g. it's "HTTP" and not "http").
+#
+# Users may override the detected values by doing something like:
+# LIBCURL="-lcurl" LIBCURL_CPPFLAGS="-I/usr/myinclude" ./configure
+#
+# For the sake of sanity, this macro assumes that any libcurl that is
+# found is after version 7.7.2, the first version that included the
+# curl-config script. Note that it is very important for people
+# packaging binary versions of libcurl to include this script!
+# Without curl-config, we can only guess what protocols are available,
+# or use curl_version_info to figure it out at runtime.
+
+AC_DEFUN([LIBCURL_CHECK_CONFIG],
+[
+ AH_TEMPLATE([LIBCURL_FEATURE_SSL],[Defined if libcurl supports SSL])
+ AH_TEMPLATE([LIBCURL_FEATURE_KRB4],[Defined if libcurl supports KRB4])
+ AH_TEMPLATE([LIBCURL_FEATURE_IPV6],[Defined if libcurl supports IPv6])
+ AH_TEMPLATE([LIBCURL_FEATURE_LIBZ],[Defined if libcurl supports libz])
+ AH_TEMPLATE([LIBCURL_FEATURE_ASYNCHDNS],[Defined if libcurl supports AsynchDNS])
+ AH_TEMPLATE([LIBCURL_FEATURE_IDN],[Defined if libcurl supports IDN])
+ AH_TEMPLATE([LIBCURL_FEATURE_SSPI],[Defined if libcurl supports SSPI])
+ AH_TEMPLATE([LIBCURL_FEATURE_NTLM],[Defined if libcurl supports NTLM])
+
+ AH_TEMPLATE([LIBCURL_PROTOCOL_HTTP],[Defined if libcurl supports HTTP])
+ AH_TEMPLATE([LIBCURL_PROTOCOL_HTTPS],[Defined if libcurl supports HTTPS])
+ AH_TEMPLATE([LIBCURL_PROTOCOL_FTP],[Defined if libcurl supports FTP])
+ AH_TEMPLATE([LIBCURL_PROTOCOL_FTPS],[Defined if libcurl supports FTPS])
+ AH_TEMPLATE([LIBCURL_PROTOCOL_FILE],[Defined if libcurl supports FILE])
+ AH_TEMPLATE([LIBCURL_PROTOCOL_TELNET],[Defined if libcurl supports TELNET])
+ AH_TEMPLATE([LIBCURL_PROTOCOL_LDAP],[Defined if libcurl supports LDAP])
+ AH_TEMPLATE([LIBCURL_PROTOCOL_DICT],[Defined if libcurl supports DICT])
+ AH_TEMPLATE([LIBCURL_PROTOCOL_TFTP],[Defined if libcurl supports TFTP])
+ AH_TEMPLATE([LIBCURL_PROTOCOL_RTSP],[Defined if libcurl supports RTSP])
+ AH_TEMPLATE([LIBCURL_PROTOCOL_POP3],[Defined if libcurl supports POP3])
+ AH_TEMPLATE([LIBCURL_PROTOCOL_IMAP],[Defined if libcurl supports IMAP])
+ AH_TEMPLATE([LIBCURL_PROTOCOL_SMTP],[Defined if libcurl supports SMTP])
+
+ AC_ARG_WITH(libcurl,
+ AC_HELP_STRING([--with-libcurl=PREFIX],[look for the curl library in PREFIX/lib and headers in PREFIX/include]),
+ [_libcurl_with=$withval],[_libcurl_with=ifelse([$1],,[yes],[$1])])
+
+ if test "$_libcurl_with" != "no" ; then
+
+ AC_PROG_AWK
+
+ _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"
+ AC_PATH_PROG([_libcurl_config],[curl-config],[],
+ ["$withval/bin"])
+ else
+ AC_PATH_PROG([_libcurl_config],[curl-config],[],[$PATH])
+ fi
+
+ if test x$_libcurl_config != "x" ; then
+ AC_CACHE_CHECK([for the version of libcurl],
+ [libcurl_cv_lib_curl_version],
+ [libcurl_cv_lib_curl_version=`$_libcurl_config --version | $AWK '{print $[]2}'`])
+
+ _libcurl_version=`echo $libcurl_cv_lib_curl_version | $_libcurl_version_parse`
+ _libcurl_wanted=`echo ifelse([$2],,[0],[$2]) | $_libcurl_version_parse`
+
+ if test $_libcurl_wanted -gt 0 ; then
+ AC_CACHE_CHECK([for libcurl >= version $2],
+ [libcurl_cv_lib_version_ok],
+ [
+ if test $_libcurl_version -ge $_libcurl_wanted ; then
+ libcurl_cv_lib_version_ok=yes
+ else
+ libcurl_cv_lib_version_ok=no
+ fi
+ ])
+ fi
+
+ if test $_libcurl_wanted -eq 0 || test x$libcurl_cv_lib_version_ok = xyes ; then
+ if test x"$LIBCURL_CPPFLAGS" = "x" ; then
+ LIBCURL_CPPFLAGS=`$_libcurl_config --cflags`
+ fi
+ if test x"$LIBCURL" = "x" ; then
+ LIBCURL=`$_libcurl_config --libs`
+
+ # This is so silly, but Apple actually has a bug in their
+ # curl-config script. Fixed in Tiger, but there are still
+ # lots of Panther installs around.
+ case "${host}" in
+ powerpc-apple-darwin7*)
+ LIBCURL=`echo $LIBCURL | sed -e 's|-arch i386||g'`
+ ;;
+ esac
+ fi
+
+ # All curl-config scripts support --feature
+ _libcurl_features=`$_libcurl_config --feature`
+
+ # Is it modern enough to have --protocols? (7.12.4)
+ if test $_libcurl_version -ge 461828 ; then
+ _libcurl_protocols=`$_libcurl_config --protocols`
+ fi
+ else
+ _libcurl_try_link=no
+ fi
+
+ unset _libcurl_wanted
+ 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"}
+
+ AC_CACHE_CHECK([whether libcurl is usable],
+ [libcurl_cv_lib_curl_usable],
+ [
+ _libcurl_save_cppflags=$CPPFLAGS
+ CPPFLAGS="$LIBCURL_CPPFLAGS $CPPFLAGS"
+ _libcurl_save_libs=$LIBS
+ LIBS="$LIBCURL $LIBS"
+
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <curl/curl.h>]],[[
+/* 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) ;
+]])],libcurl_cv_lib_curl_usable=yes,libcurl_cv_lib_curl_usable=no)
+
+ CPPFLAGS=$_libcurl_save_cppflags
+ LIBS=$_libcurl_save_libs
+ unset _libcurl_save_cppflags
+ unset _libcurl_save_libs
+ ])
+
+ if test $libcurl_cv_lib_curl_usable = yes ; then
+
+ # Does curl_free() exist in this version of libcurl?
+ # If not, fake it with free()
+
+ _libcurl_save_cppflags=$CPPFLAGS
+ CPPFLAGS="$CPPFLAGS $LIBCURL_CPPFLAGS"
+ _libcurl_save_libs=$LIBS
+ LIBS="$LIBS $LIBCURL"
+
+ AC_CHECK_FUNC(curl_free,,
+ AC_DEFINE(curl_free,free,
+ [Define curl_free() as free() if our version of curl lacks curl_free.]))
+
+ CPPFLAGS=$_libcurl_save_cppflags
+ LIBS=$_libcurl_save_libs
+ unset _libcurl_save_cppflags
+ unset _libcurl_save_libs
+
+ AC_DEFINE(HAVE_LIBCURL,1,
+ [Define to 1 if you have a functional curl library.])
+ AC_SUBST(LIBCURL_CPPFLAGS)
+ AC_SUBST(LIBCURL)
+
+ for _libcurl_feature in $_libcurl_features ; do
+ AC_DEFINE_UNQUOTED(AS_TR_CPP(libcurl_feature_$_libcurl_feature),[1])
+ eval AS_TR_SH(libcurl_feature_$_libcurl_feature)=yes
+ done
+
+ if test "x$_libcurl_protocols" = "x" ; then
+
+ # We don't have --protocols, so just assume that all
+ # protocols are available
+ _libcurl_protocols="HTTP FTP FILE TELNET LDAP DICT TFTP"
+
+ if test x$libcurl_feature_SSL = xyes ; then
+ _libcurl_protocols="$_libcurl_protocols HTTPS"
+
+ # FTPS wasn't standards-compliant until version
+ # 7.11.0 (0x070b00 == 461568)
+ if test $_libcurl_version -ge 461568; then
+ _libcurl_protocols="$_libcurl_protocols FTPS"
+ fi
+ fi
+
+ # RTSP, IMAP, POP3 and SMTP were added in
+ # 7.20.0 (0x071400 == 463872)
+ if test $_libcurl_version -ge 463872; then
+ _libcurl_protocols="$_libcurl_protocols RTSP IMAP POP3 SMTP"
+ fi
+ fi
+
+ for _libcurl_protocol in $_libcurl_protocols ; do
+ AC_DEFINE_UNQUOTED(AS_TR_CPP(libcurl_protocol_$_libcurl_protocol),[1])
+ eval AS_TR_SH(libcurl_protocol_$_libcurl_protocol)=yes
+ done
+ else
+ unset LIBCURL
+ unset LIBCURL_CPPFLAGS
+ fi
+ 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
+ ifelse([$4],,:,[$4])
+ else
+ # This is the IF-YES path
+ ifelse([$3],,:,[$3])
+ fi
+
+ unset _libcurl_with
+])dnl
diff --git a/m4/python.m4 b/m4/python.m4
new file mode 100644
index 0000000..78ca763
--- /dev/null
+++ b/m4/python.m4
@@ -0,0 +1,363 @@
+## ------------------------ -*- Autoconf -*-
+## Python file handling
+## From Andrew Dalke
+## Updated by James Henstridge and other contributors.
+## ------------------------
+# Copyright (C) 1999-2021 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+
+# AM_PATH_PYTHON([MINIMUM-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+# ---------------------------------------------------------------------------
+# Adds support for distributing Python modules and packages. To
+# install modules, copy them to $(pythondir), using the python_PYTHON
+# automake variable. To install a package with the same name as the
+# automake package, install to $(pkgpythondir), or use the
+# pkgpython_PYTHON automake variable.
+#
+# The variables $(pyexecdir) and $(pkgpyexecdir) are provided as
+# locations to install python extension modules (shared libraries).
+# Another macro is required to find the appropriate flags to compile
+# extension modules.
+#
+# If your package is configured with a different prefix to python,
+# users will have to add the install directory to the PYTHONPATH
+# environment variable, or create a .pth file (see the python
+# documentation for details).
+#
+# If the MINIMUM-VERSION argument is passed, AM_PATH_PYTHON will
+# cause an error if the version of python installed on the system
+# doesn't meet the requirement. MINIMUM-VERSION should consist of
+# numbers and dots only.
+AC_DEFUN([AM_PATH_PYTHON],
+ [
+ dnl Find a Python interpreter. Python versions prior to 2.0 are not
+ dnl supported. (2.0 was released on October 16, 2000).
+ m4_define_default([_AM_PYTHON_INTERPRETER_LIST],
+[python python2 python3 dnl
+ python3.11 python3.10 dnl
+ python3.9 python3.8 python3.7 python3.6 python3.5 python3.4 python3.3 dnl
+ python3.2 python3.1 python3.0 dnl
+ python2.7 python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 dnl
+ python2.0])
+
+ AC_ARG_VAR([PYTHON], [the Python interpreter])
+
+ m4_if([$1],[],[
+ dnl No version check is needed.
+ # Find any Python interpreter.
+ if test -z "$PYTHON"; then
+ AC_PATH_PROGS([PYTHON], _AM_PYTHON_INTERPRETER_LIST, :)
+ fi
+ am_display_PYTHON=python
+ ], [
+ dnl A version check is needed.
+ if test -n "$PYTHON"; then
+ # If the user set $PYTHON, use it and don't search something else.
+ AC_MSG_CHECKING([whether $PYTHON version is >= $1])
+ AM_PYTHON_CHECK_VERSION([$PYTHON], [$1],
+ [AC_MSG_RESULT([yes])],
+ [AC_MSG_RESULT([no])
+ AC_MSG_ERROR([Python interpreter is too old])])
+ am_display_PYTHON=$PYTHON
+ else
+ # Otherwise, try each interpreter until we find one that satisfies
+ # VERSION.
+ AC_CACHE_CHECK([for a Python interpreter with version >= $1],
+ [am_cv_pathless_PYTHON],[
+ for am_cv_pathless_PYTHON in _AM_PYTHON_INTERPRETER_LIST none; do
+ test "$am_cv_pathless_PYTHON" = none && break
+ AM_PYTHON_CHECK_VERSION([$am_cv_pathless_PYTHON], [$1], [break])
+ done])
+ # Set $PYTHON to the absolute path of $am_cv_pathless_PYTHON.
+ if test "$am_cv_pathless_PYTHON" = none; then
+ PYTHON=:
+ else
+ AC_PATH_PROG([PYTHON], [$am_cv_pathless_PYTHON])
+ fi
+ am_display_PYTHON=$am_cv_pathless_PYTHON
+ fi
+ ])
+
+ if test "$PYTHON" = :; then
+ dnl Run any user-specified action, or abort.
+ m4_default([$3], [AC_MSG_ERROR([no suitable Python interpreter found])])
+ else
+
+ dnl Query Python for its version number. Although site.py simply uses
+ dnl sys.version[:3], printing that failed with Python 3.10, since the
+ dnl trailing zero was eliminated. So now we output just the major
+ dnl and minor version numbers, as numbers. Apparently the tertiary
+ dnl version is not of interest.
+ dnl
+ AC_CACHE_CHECK([for $am_display_PYTHON version], [am_cv_python_version],
+ [am_cv_python_version=`$PYTHON -c "import sys; print ('%u.%u' % sys.version_info[[:2]])"`])
+ AC_SUBST([PYTHON_VERSION], [$am_cv_python_version])
+
+ dnl At times, e.g., when building shared libraries, you may want
+ dnl to know which OS platform Python thinks this is.
+ dnl
+ AC_CACHE_CHECK([for $am_display_PYTHON platform], [am_cv_python_platform],
+ [am_cv_python_platform=`$PYTHON -c "import sys; sys.stdout.write(sys.platform)"`])
+ AC_SUBST([PYTHON_PLATFORM], [$am_cv_python_platform])
+
+ dnl emacs-page
+ dnl If --with-python-sys-prefix is given, use the values of sys.prefix
+ dnl and sys.exec_prefix for the corresponding values of PYTHON_PREFIX
+ dnl and PYTHON_EXEC_PREFIX. Otherwise, use the GNU ${prefix} and
+ dnl ${exec_prefix} variables.
+ dnl
+ dnl The two are made distinct variables so they can be overridden if
+ dnl need be, although general consensus is that you shouldn't need
+ dnl this separation.
+ dnl
+ dnl Also allow directly setting the prefixes via configure options,
+ dnl overriding any default.
+ dnl
+ 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.
+ AC_ARG_WITH([python-sys-prefix],
+ [AS_HELP_STRING([--with-python-sys-prefix],
+ [use Python's sys.prefix and sys.exec_prefix values])],
+ [am_use_python_sys=:],
+ [am_use_python_sys=false])
+
+ # Allow user to override whatever the default Python prefix is.
+ AC_ARG_WITH([python_prefix],
+ [AS_HELP_STRING([--with-python_prefix],
+ [override the default PYTHON_PREFIX])],
+ [am_python_prefix_subst=$withval
+ am_cv_python_prefix=$withval
+ AC_MSG_CHECKING([for explicit $am_display_PYTHON prefix])
+ AC_MSG_RESULT([$am_cv_python_prefix])],
+ [
+ if $am_use_python_sys; then
+ # using python sys.prefix value, not GNU
+ AC_CACHE_CHECK([for python default $am_display_PYTHON prefix],
+ [am_cv_python_prefix],
+ [am_cv_python_prefix=`$PYTHON -c "import sys; sys.stdout.write(sys.prefix)"`])
+
+ dnl If sys.prefix is a subdir of $prefix, replace the literal value of
+ dnl $prefix with a variable reference so it can be overridden.
+ 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
+ AC_MSG_CHECKING([for GNU default $am_display_PYTHON prefix])
+ AC_MSG_RESULT([$am_python_prefix])
+ fi])
+ # Substituting python_prefix_subst value.
+ AC_SUBST([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.
+ AC_ARG_WITH([python_exec_prefix],
+ [AS_HELP_STRING([--with-python_exec_prefix],
+ [override the default PYTHON_EXEC_PREFIX])],
+ [am_python_exec_prefix_subst=$withval
+ am_cv_python_exec_prefix=$withval
+ AC_MSG_CHECKING([for explicit $am_display_PYTHON exec_prefix])
+ AC_MSG_RESULT([$am_cv_python_exec_prefix])],
+ [
+ # no explicit --with-python_exec_prefix, but if
+ # --with-python_prefix was given, use its value for python_exec_prefix too.
+ AS_IF([test -n "$with_python_prefix"],
+ [am_python_exec_prefix_subst=$with_python_prefix
+ am_cv_python_exec_prefix=$with_python_prefix
+ AC_MSG_CHECKING([for python_prefix-given $am_display_PYTHON exec_prefix])
+ AC_MSG_RESULT([$am_cv_python_exec_prefix])],
+ [
+ # 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
+ AC_CACHE_CHECK([for python default $am_display_PYTHON exec_prefix],
+ [am_cv_python_exec_prefix],
+ [am_cv_python_exec_prefix=`$PYTHON -c "import sys; sys.stdout.write(sys.exec_prefix)"`])
+ dnl If sys.exec_prefix is a subdir of $exec_prefix, replace the
+ dnl literal value of $exec_prefix with a variable reference so it can
+ dnl be overridden.
+ 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
+ AC_MSG_CHECKING([for GNU default $am_display_PYTHON exec_prefix])
+ AC_MSG_RESULT([$am_python_exec_prefix])
+ fi])])
+ # Substituting python_exec_prefix_subst.
+ AC_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"
+
+ dnl emacs-page Set up 4 directories:
+
+ dnl 1. pythondir: where to install python scripts. This is the
+ dnl site-packages directory, not the python standard library
+ dnl directory like in previous automake betas. This behavior
+ dnl is more consistent with lispdir.m4 for example.
+ dnl Query distutils for this directory.
+ dnl
+ AC_CACHE_CHECK([for $am_display_PYTHON script directory (pythondir)],
+ [am_cv_python_pythondir],
+ [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
+ ])
+ AC_SUBST([pythondir], [$am_cv_python_pythondir])
+
+ dnl 2. pkgpythondir: $PACKAGE directory under pythondir. Was
+ dnl PYTHON_SITE_PACKAGE in previous betas, but this naming is
+ dnl more consistent with the rest of automake.
+ dnl
+ AC_SUBST([pkgpythondir], [\${pythondir}/$PACKAGE])
+
+ dnl 3. pyexecdir: directory for installing python extension modules
+ dnl (shared libraries).
+ dnl Query distutils for this directory.
+ dnl
+ AC_CACHE_CHECK([for $am_display_PYTHON extension module directory (pyexecdir)],
+ [am_cv_python_pyexecdir],
+ [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
+ ])
+ AC_SUBST([pyexecdir], [$am_cv_python_pyexecdir])
+
+ dnl 4. pkgpyexecdir: $(pyexecdir)/$(PACKAGE)
+ dnl
+ AC_SUBST([pkgpyexecdir], [\${pyexecdir}/$PACKAGE])
+
+ dnl Run any user-specified action.
+ $2
+ fi
+])
+
+
+# AM_PYTHON_CHECK_VERSION(PROG, VERSION, [ACTION-IF-TRUE], [ACTION-IF-FALSE])
+# ---------------------------------------------------------------------------
+# Run ACTION-IF-TRUE if the Python interpreter PROG has version >= VERSION.
+# Run ACTION-IF-FALSE otherwise.
+# This test uses sys.hexversion instead of the string equivalent (first
+# word of sys.version), in order to cope with versions such as 2.2c1.
+# This supports Python 2.0 or higher. (2.0 was released on October 16, 2000).
+AC_DEFUN([AM_PYTHON_CHECK_VERSION],
+ [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, '$2'.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)"
+ AS_IF([AM_RUN_LOG([$1 -c "$prog"])], [$3], [$4])])
diff --git a/m4/vl_lib_readline.m4 b/m4/vl_lib_readline.m4
new file mode 100644
index 0000000..f95be7b
--- /dev/null
+++ b/m4/vl_lib_readline.m4
@@ -0,0 +1,45 @@
+AC_DEFUN([VL_LIB_READLINE], [
+ AC_CACHE_CHECK([for a readline compatible library],
+ vl_cv_lib_readline, [
+ ORIG_LIBS="$LIBS"
+ for readline_lib in readline edit editline; do
+ for termcap_lib in "" termcap curses ncurses; do
+ if test -z "$termcap_lib"; then
+ TRY_LIB="-l$readline_lib"
+ else
+ TRY_LIB="-l$readline_lib -l$termcap_lib"
+ fi
+ LIBS="$ORIG_LIBS $TRY_LIB"
+ AC_TRY_LINK_FUNC(readline, vl_cv_lib_readline="$TRY_LIB")
+ if test -n "$vl_cv_lib_readline"; then
+ break
+ fi
+ done
+ if test -n "$vl_cv_lib_readline"; then
+ break
+ fi
+ done
+ if test -z "$vl_cv_lib_readline"; then
+ vl_cv_lib_readline="no"
+ LIBS="$ORIG_LIBS"
+ fi
+ ])
+
+ if test "$vl_cv_lib_readline" != "no"; then
+ LIBREADLINE="$vl_cv_lib_readline"
+ AC_DEFINE(HAVE_LIBREADLINE, 1,
+ [Define if you have a readline compatible library])
+ AC_CHECK_HEADERS(readline.h readline/readline.h)
+ AC_CACHE_CHECK([whether readline supports history],
+ [vl_cv_lib_readline_history], [
+ vl_cv_lib_readline_history="no"
+ AC_TRY_LINK_FUNC([add_history], [vl_cv_lib_readline_history="yes"])
+ ])
+ if test "$vl_cv_lib_readline_history" = "yes"; then
+ AC_DEFINE(HAVE_READLINE_HISTORY, 1,
+ [Define if your readline library has \`add_history'])
+ AC_CHECK_HEADERS(history.h readline/history.h)
+ fi
+ fi
+ AC_SUBST(LIBREADLINE)
+])dnl
diff --git a/main.mk b/main.mk
new file mode 100644
index 0000000..69e0f6b
--- /dev/null
+++ b/main.mk
@@ -0,0 +1 @@
+SUBMAKEFILES := src/all.mk scripts/all.mk doc/all.mk raddb/all.mk
diff --git a/man/man1/dhcpclient.1 b/man/man1/dhcpclient.1
new file mode 100644
index 0000000..d6a538e
--- /dev/null
+++ b/man/man1/dhcpclient.1
@@ -0,0 +1,71 @@
+.TH DHCPCLIENT 1 "19 September 2016" "" "FreeRADIUS Daemon"
+.SH NAME
+dhcpclient - Send a DHCP request with provided RADIUS attributes and get the output response.
+.SH SYNOPSIS
+.B dhcpclient
+.RB [ \-d
+.IR raddb_directory ]
+.RB [ \-D
+.IR dictionary_directory ]
+.RB [ \-f
+.IR file ]
+.RB [ \-h ]
+.RB [ \-i
+.IR interface ]
+.RB [ \-t
+.IR timeout ]
+.RB [ \-v ]
+.RB [ \-x ]
+\fIserver[:port] {discover|request|decline|release|inform|auto}\fP
+.SH DESCRIPTION
+\fBdhcpclient\fP is a DHCP test client program. It can send arbitrary DHCP
+packets to the FreeRADIUS server running as DHCP server, then shows the reply.
+It can be used to test changes you made in the configuration of the radius server,
+or it can be used to monitor if a radius server is up.
+.PP
+\fBdhcpclient\fP reads radius attribute/value pairs from its standard
+input, or from a file specified on the command line. It then encodes
+these attribute/value pairs using the dictionary, and sends them
+to the local/remote server.
+.PP
+
+.SH OPTIONS
+
+.IP \-d\ \fIraddb_directory\fP
+The directory that contains the user dictionary file. Defaults to
+\fI/etc/raddb\fP.
+.IP \-D\ \fIdictionary_directory\fP
+The directory that contains the main dictionary file. Defaults to
+\fI/usr/share/freeradius\fP.
+.IP \-f\ \fIfile[:file]\fP
+File to read the attribute/value pairs from. If this is not specified,
+they are read from stdin. This option can be specified multiple
+times, in which case packets are sent in order by file, and within
+each file, by first packet to last packet. A blank line separates
+logical packets within a file.
+.IP \-h
+Print usage help information.
+.IP \-i\ \fIinterface\fP
+Select which interface to send/receive at packet level on a raw socket.
+.IP \-t\ \fItimeout\fP
+Wait \fItimeout\fP seconds before deciding that the NAS has not
+responded to a request, and re-sending the packet. This may be a floating
+point number, e.g. 2.2.
+.IP \-v
+Print out program version information.
+.IP \-x
+Print out debugging information.
+.IP server[:port]
+The hostname or IP address of the remote server. Optionally a UDP port
+can be specified. If no UDP port is specified, it is looked up in
+\fI/etc/services\fP. The service name looked for is \fBradacct\fP for
+accounting packets, and \fBradius\fP for all other requests. If a
+service is not found in \fI/etc/services\fP, 1813 and 1812 are used
+respectively.
+.IP discover\ |\ request\ |\ decline\ |\ release\ |\ inform\ |\ auto
+DHCP options - use the type relevant for testing
+
+.SH SEE ALSO
+radiusd(8)
+.SH AUTHORS
+Alan DeKok <aland@freeradius.org>
diff --git a/man/man1/rad_counter.1 b/man/man1/rad_counter.1
new file mode 100644
index 0000000..74e7c73
--- /dev/null
+++ b/man/man1/rad_counter.1
@@ -0,0 +1,42 @@
+.TH RAD_COUNTER 1 "19 September 2016" "" "FreeRADIUS Daemon"
+.SH NAME
+rad_counter - Query and maintain FreeRADIUS rlm_counter DB file.
+
+This tool is deprecated
+
+.SH SYNOPSIS
+.B rad_counter
+.RB [ \--file
+.IR counter_filename ]
+.RB [ \--user
+.IR username ]
+.RB [ \--match
+.IR <regex> ]
+.RB [ \--reset
+.IR number]
+.RB [ \--help ]
+.RB [ \-\-hours | \-\-minutes | \-\-seconds ]
+
+.SH DESCRIPTION
+\fBrad_counter\fP is a tool that can query and maintain FreeRADIUS rlm_counter DB files.
+.PP
+
+.SH OPTIONS
+
+.IP \--file=
+Counter DB filename.
+.IP \--user=\ \fIusername\fP
+Information for specific user.
+.IP \--match=\ \fI<regex>\fP
+Information for matching users.
+.IP \--reset=\ \fInumber\fP
+Reset counter to <number>. If divisor is set use it, else <number> means seconds.
+.IP \--help
+Show the help screen.
+.IP \--(hours\ |\ minutes\ |\ seconds)
+Specify information divisor.
+
+.SH SEE ALSO
+radiusd(8)
+.SH AUTHORS
+Alan DeKok <aland@freeradius.org>
diff --git a/man/man1/radclient.1 b/man/man1/radclient.1
new file mode 100644
index 0000000..229dcae
--- /dev/null
+++ b/man/man1/radclient.1
@@ -0,0 +1,195 @@
+.TH RADCLIENT 1 "22 March 2019" "" "FreeRADIUS Daemon"
+.SH NAME
+radclient - send packets to a RADIUS server, show reply
+.SH SYNOPSIS
+.B radclient
+.RB [ \-4 ]
+.RB [ \-6 ]
+.RB [ \-c
+.IR count ]
+.RB [ \-d
+.IR raddb_directory ]
+.RB [ \-D
+.IR dictionary_directory ]
+.RB [ \-f
+.IR file ]
+.RB [ \-F ]
+.RB [ \-h ]
+.RB [ \-i
+.IR id ]
+.RB [ \-n
+.IR num_requests_per_second ]
+.RB [ \-p
+.IR num_requests_in_parallel ]
+.RB [ \-q ]
+.RB [ \-r
+.IR num_retries ]
+.RB [ \-s ]
+.RB [ \-S
+.IR shared_secret_file ]
+.RB [ \-t
+.IR timeout ]
+.RB [ \-v ]
+.RB [ \-x ]
+\fIserver {acct|auth|status|coa|disconnect|auto} secret\fP
+.SH DESCRIPTION
+\fBradclient\fP is a radius client program. It can send arbitrary radius
+packets to a radius server, then shows the reply. It can be used to
+test changes you made in the configuration of the radius server,
+or it can be used to monitor if a radius server is up.
+.PP
+\fBradclient\fP reads radius attribute/value pairs from it standard
+input, or from a file specified on the command line. It then encodes
+these attribute/value pairs using the dictionary, and sends them
+to the remote server.
+.PP
+The \fIUser-Password\fP and \fICHAP-Password\fP attributes are
+automatically encrypted before the packet is sent to the server.
+
+.SH OPTIONS
+
+.IP \-4
+Use IPv4 (default)
+.IP \-6
+Use IPv6
+.IP \-c\ \fIcount\fP
+Send each packet \fIcount\fP times.
+.IP \-d\ \fIraddb_directory\fP
+The directory that contains the user dictionary file. Defaults to
+\fI/etc/raddb\fP.
+.IP \-D\ \fIdictionary_directory\fP
+The directory that contains the main dictionary file. Defaults to
+\fI/usr/share/freeradius\fP.
+.IP \-f\ \fIfile[:file]\fP
+File to read the attribute/value pairs from. If this is not specified,
+they are read from stdin. This option can be specified multiple
+times, in which case packets are sent in order by file, and within
+each file, by first packet to last packet. A blank line separates
+logical packets within a file. If a pair of files separated by a
+colon is specified, the second file will be used to filter the
+responses to requests from the first. The number of requests and
+filters must be the same. A summary of filter results will be displayed
+if \-s is passed.
+.IP \-F
+Print the file name, packet number and reply code.
+.IP \-h
+Print usage help information.
+.IP \-i\ \fIid\fP
+Use \fIid\fP as the RADIUS request Id.
+.IP \-n\ \fInum_requests_per_second\fP
+Try to send \fInum_requests_per_second\fP, evenly spaced. This option
+allows you to slow down the rate at which radclient sends requests.
+When not using \-n, the default is to send packets as quickly as
+possible, with no inter-packet delays.
+
+Due to limitations in radclient, this option does not accurately send
+the requested number of packets per second.
+.IP \-p\ \fInum_requests_in_parallel\fP
+Send \fInum_requests_in_parallel\fP, without waiting for a response
+for each one. By default, radclient sends the first request it has
+read, waits for the response, and once the response is received, sends
+the second request in its list. This option allows you to send many
+requests at simultaneously. Once \fInum_requests_in_parallel\fP are
+sent, radclient waits for all of the responses to arrive (or for the
+requests to time out), before sending any more packets.
+
+This option permits you to discover the maximum load accepted by a
+RADIUS server.
+.IP "\-P\ \fIproto\fP"
+Use \fIproto\fP transport protocol ("tcp" or "udp").
+Only available if FreeRADIUS is compiled with TCP transport support.
+.IP \-q
+Go to quiet mode, and do not print out anything.
+.IP \-r\ \fInum_retries\fP
+Try to send each packet \fInum_retries\fP times, before giving up on
+it. The default is 10.
+.IP \-s
+Print out some summaries of packets sent and received.
+.IP \-S\ \fIshared_secret_file\fP
+Rather than reading the shared secret from the command-line (where it
+can be seen by others on the local system), read it instead from
+\fIshared_secret_file\fP.
+.IP \-t\ \fItimeout\fP
+Wait \fItimeout\fP seconds before deciding that the NAS has not
+responded to a request, and re-sending the packet. The default
+timeout is 3.
+.IP \-v
+Print out version information.
+.IP \-x
+Print out debugging information.
+.IP server[:port]
+The hostname or IP address of the remote server. Optionally a UDP port
+can be specified. If no UDP port is specified, it is looked up in
+\fI/etc/services\fP. The service name looked for is \fBradacct\fP for
+accounting packets, and \fBradius\fP for all other requests. If a
+service is not found in \fI/etc/services\fP, 1813 and 1812 are used
+respectively. For coa and disconnect packets, port 3799 is used.
+
+If a host name is specified, then radclient will do a DNS lookup, and
+use the A record to find the IP address of the RADIUS server. If
+there is no A record, then radclient will look for an AAAA record. If
+there is no AAAA record, an error will be produced.
+
+IPv6 addresses may be specified by surrounding it in square brackets.
+For example, [2002:c000:0201:0:0:0:0:0], or with a port,
+[2002:c000:0201:0:0:0:0:0]:18120.
+
+The RADIUS attributes read by \fIradclient\fP can contain the special
+attribute \fBPacket-Dst-IP-Address\fP. If this attribute exists, then
+that IP address is where the packet is sent, and the \fBserver\fP
+specified on the command-line is ignored.
+
+If the RADIUS attribute list always contains the
+\fBPacket-Dst-IP-Address\fP attribute, then the \fBserver\fP parameter
+can be given as \fB-\fP.
+
+The RADIUS attributes read by \fIradclient\fP can contain the special
+attribute \fBPacket-Dst-Port\fP. If this attribute exists, then that
+UDP port is where the packet is sent, and the \fB:port\fP specified
+on the command-line is ignored.
+
+.IP acct\ |\ auth\ |\ status\ |\ coa\ |\ disconnect\ |\ auto
+Use \fBauth\fP to send an authentication packet (Access-Request),
+\fBacct\fP to send an accounting packet (Accounting-Request),
+\fBstatus\fP to send a status packet (Status-Server), or
+\fBcoa\fP to send a CoA-Request, or
+\fBdisconnect\fP to send a disconnection request. Instead of these
+values, you can also use a decimal code here. For example, code 12 is
+also \fBStatus-Server\fP.
+
+The RADIUS attributes read by \fIradclient\fP can contain the special
+attribute \fBPacket-Type\fP. If this attribute exists, then that type
+of packet is sent, and the \fItype\fP specified on the command-line
+is ignored.
+
+If the RADIUS attribute list always contains the
+\fBPacket-Type\fP attribute, then the \fBtype\fP parameter can be
+given as \fBauto\fP.
+
+.IP secret
+The shared secret for this client. It needs to be defined on the
+radius server side too, for the IP address you are sending the radius
+packets from.
+
+.SH EXAMPLE
+
+A sample session that queries the remote server for
+\fIStatus-Server\fP (not all servers support this, but FreeRADIUS has
+configurable support for it).
+.RS
+.sp
+.nf
+.ne 3
+$ echo "Message-Authenticator = 0x00" | radclient 192.0.2.42 status s3cr3t
+Sending request to server 192.0.2.42, port 1812.
+radrecv: Packet from host 192.0.2.42 code=2, id=140, length=54
+ Reply-Message = "FreeRADIUS up 21 days, 02:05"
+.fi
+.sp
+.RE
+
+.SH SEE ALSO
+radiusd(8),
+.SH AUTHORS
+Miquel van Smoorenburg, miquels@cistron.nl.
+Alan DeKok <aland@freeradius.org>
diff --git a/man/man1/radeapclient.1 b/man/man1/radeapclient.1
new file mode 100644
index 0000000..687ef61
--- /dev/null
+++ b/man/man1/radeapclient.1
@@ -0,0 +1,100 @@
+.TH RADEAPCLIENT 1 "08 September 2003" "" "FreeRADIUS Daemon"
+.SH NAME
+radeapclient - send EAP packets to a RADIUS server, calculate responses
+.SH SYNOPSIS
+.B radeapclient
+.RB [ \-4 ]
+.RB [ \-6 ]
+.RB [ \-c
+.IR count ]
+.RB [ \-d
+.IR raddb_directory ]
+.RB [ \-f
+.IR file ]
+.RB [ \-h ]
+.RB [ \-i
+.IR source_ip ]
+.RB [ \-q ]
+.RB [ \-s ]
+.RB [ \-r
+.IR retries ]
+.RB [ \-S
+.IR file ]
+.RB [ \-t
+.IR timeout ]
+.RB [ \-v ]
+.RB [ \-x ]
+\fIserver {acct|auth} secret\fP
+.SH DESCRIPTION
+\fBradeapclient\fP is a radius client program. It can send arbitrary radius
+packets to a radius server, then shows the reply. Radeapclient differs from
+radclient in that if there is an EAP-MD5 challenge, then it will be responded
+to.
+.PP
+\fBradeapclient\fP is otherwise identical to \fBradclient\fP.
+.PP
+The \fIEAP-Identity\fP attribute, if present is used to construct an
+EAP Identity message.
+.PP
+.PP
+The \fIEAP-MD5-Password\fP attribute, if present is used to respond to an
+MD5 challenge.
+.PP
+No other EAP types are currently supported.
+
+.SH OPTIONS
+.IP \-4
+Use IPv4 (default)
+.IP \-6
+Use IPv6
+.IP \-c\ \fIcount\fP
+Send each packet \fIcount\fP times.
+.IP \-d\ \fIraddb\fP
+Set dictionary directory.
+.IP \-f\ \fIfile\fP
+Read packets from \fIfile\fP, not stdin.
+.IP \-r\ \fIretries\fP
+If timeout, retry sending the packet \fIretries\fP times.
+.IP \-t\ \fItimeout\fP
+Wait \fItimeout\fP seconds before retrying (may be a floating point number).
+.IP \-h
+Print usage help information.
+.IP \-i\ \fIid\fP
+Set request id to '\fIid\fP'. Values may be 0..255
+.IP \-S\ \fIfile\fP
+Read secret from \fIfile\fP, not command line.
+.IP \-q
+Quiet, do not print anything out.
+.IP \-s
+Print out summary information of auth results.
+.IP \-v
+Show program version information.
+.IP \-x
+Enable debugging mode.
+
+.SH EXAMPLE
+
+A sample session that queries the remote server with an EAP-MD5
+challenge.
+.RS
+.sp
+.nf
+.ne 3
+( echo 'User-Name = "bob"';
+ echo 'EAP-MD5-Password = "hello"';
+ echo 'NAS-IP-Address = marajade.sandelman.ottawa.on.c';
+ echo 'EAP-Code = Response';
+ echo 'EAP-Id = 210';
+ echo 'EAP-Type-Identity = "bob";
+ echo 'Message-Authenticator = 0x00';
+ echo 'NAS-Port = 0' ) >req.txt
+
+radeapclient -x localhost auth testing123 <req.txt
+.fi
+.sp
+.RE
+
+.SH SEE ALSO
+radclient(1)
+.SH AUTHOR
+Michael Richardson, <mcr@sandelman.ottawa.on.ca>
diff --git a/man/man1/radlast.1 b/man/man1/radlast.1
new file mode 100644
index 0000000..ff48f22
--- /dev/null
+++ b/man/man1/radlast.1
@@ -0,0 +1,21 @@
+.TH RADLAST 1 "22 February 2001" "" "FreeRADIUS Daemon"
+.SH NAME
+radlast - show "last" info from the radwtmp file
+.SH SYNOPSIS
+.B radlast
+.IR [ options ]
+.SH DESCRIPTION
+The FreeRADIUS server can write an accounting log in the
+\fIwtmp\fP format of the local system. \fBradlast\fP is a frontend
+for the systems \fBlast\fP command - it just calls \fBlast\fP
+with the \fI-f path_to_radwtmp_file\fP argument, and passes all
+options on the command line to the system \fBlast\fP command.
+.SH OPTIONS
+See the manpage of the system \fBlast\fP command.
+.SH SEE ALSO
+radiusd(8),
+radiusd.conf(5),
+wtmp(5),
+last(1).
+.SH AUTHOR
+Miquel van Smoorenburg, miquels@cistron.nl.
diff --git a/man/man1/radtest.1 b/man/man1/radtest.1
new file mode 100644
index 0000000..2bf8997
--- /dev/null
+++ b/man/man1/radtest.1
@@ -0,0 +1,81 @@
+.TH RADTEST 1 "5 April 2010" "" "FreeRADIUS Daemon"
+.SH NAME
+radtest - send packets to a RADIUS server, show reply
+.SH SYNOPSIS
+.B radtest
+.RB [ \-d
+.IR raddb_directory ]
+.RB [ \-P
+.IR tcp/udp ]
+.RB [ \-t
+.IR pap/chap/mschap/eap-md5 ]
+.RB [ \-x
+.IR ]
+.RB [ \-4
+.IR ]
+.RB [ \-6
+.IR ]
+.I user password radius-server nas-port-number secret
+.RB [ ppphint ]
+.RB [ nasname ]
+.SH DESCRIPTION
+\fBradtest\fP is a frontend to \fBradclient\fP(1). It generates a
+list of attribute/value pairs based on the command line arguments,
+and feeds these into \fBradclient\fP. It's a fast and convenient
+way to test a radius server.
+
+.SH OPTIONS
+
+.IP "\-d \fIraddb_directory\fP"
+The directory that contains the RADIUS dictionary files. Defaults to
+\fI/etc/raddb\fP.
+
+.IP "\-P\ \fIproto\fP"
+Use \fIproto\fP transport protocol ("tcp" or "udp").
+Only available if FreeRADIUS is compiled with TCP transport support.
+
+.IP "\-t \fIpap/chap/mschap/eap-md5\fP"
+Choose the authentication method to use. e.g. "-t pap", "-t chap", "-t
+mschap", or "-t eap-md5",. Defaults to "pap". Using EAP-MD5 requires
+that the "radeapclient" program is installed.
+
+.IP "\-x"
+Enables debugging output for the RADIUS client.
+
+.IP "\-4"
+Use NAS-IP-Address for the NAS address (default)
+
+.IP "\-6"
+Use NAS-IPv6-Address for the NAS address (default)
+
+.IP user
+Username to send.
+
+.IP password
+Password of the user.
+
+.IP radius-server
+Hostname or IP address of the radius server. Optionally, you may specify a
+port by appending :port
+
+.IP nas-port-number
+The value of the NAS-Port attribute. Is an integer between 0 and 2^31,
+and it really doesn't matter what you put here. \fI10\fP will do fine.
+
+.IP secret
+The shared secret for this client.
+
+.IP ppphint
+If you put an integer > 0 here, radtest (or actually radclient) will
+add the attribute \fIFramed-Protocol = PPP\fP to the request packet.
+
+.IP nasname
+If present, this will be resolved to an IP address and added to
+the request packet as the \fINAS-IP-Address\fP attribute. If you
+don't specify it, the local hostname of the system will be used.
+
+.SH SEE ALSO
+radiusd(8),
+radclient(1).
+.SH AUTHOR
+Miquel van Smoorenburg, miquels@cistron.nl.
diff --git a/man/man1/radwho.1 b/man/man1/radwho.1
new file mode 100644
index 0000000..c131255
--- /dev/null
+++ b/man/man1/radwho.1
@@ -0,0 +1,99 @@
+.TH RADWHO 1 "17 Feb 2013" "" "FreeRADIUS Daemon"
+.SH NAME
+radwho - show online users
+.SH SYNOPSIS
+.B radwho
+.RB [ \-c ]
+.RB [ \-d
+.IR raddb_directory ]
+.RB [ \-F
+.IR radutmp_file ]
+.RB [ \-i ]
+.RB [ \-n ]
+.RB [ \-N
+.IR nas_ip_address ]
+.RB [ \-p ]
+.RB [ \-P
+.IR nas_port ]
+.RB [ \-r ]
+.RB [ \-R ]
+.RB [ \-s ]
+.RB [ \-S ]
+.RB [ \-u
+.IR user ]
+.RB [ \-U
+.IR user ]
+.RB [ \-Z ]
+.SH DESCRIPTION
+The FreeRADIUS server can be configured to maintain an active session
+database in a file called \fIradutmp\fP. This utility shows the
+content of that session database.
+.SH OPTIONS
+.IP \-c
+Shows caller ID (if available) instead of the full name.
+.IP \-d\ \fIraddb_directory\fP
+The directory that contains the RADIUS configuration files. Defaults to
+\fI/etc/raddb\fP.
+.IP \-F\ \fIradutmp_file\fP
+The file that contains the radutmp file. If this is specified, \-d is
+not necessary.
+.IP \-i
+Shows the session ID instead of the full name.
+.IP \-n
+Normally radwho looks up the username in the systems password file,
+and shows the full username as well. The \fB-n\fP flags prevents this.
+.IP \-N\ \fInas_ip_address\fP
+Show only those entries which match the given NAS IP address.
+.IP \-p
+Adds an extra column for the port type - I for ISDN, A for Analog.
+.IP \-P\ \fInas_port\fP
+Show only those entries which match the given NAS port.
+.IP \-r
+Outputs all data in \fIraw\fP format - no headers, no formatting,
+fields are comma-separated.
+.IP \-R
+Output all data in RADIUS attribute format. All fields are printed.
+.IP \-s
+Show full name.
+.IP \-S
+Hide shell users. Doesn't show the entries for users that do not
+have a SLIP or PPP session.
+.IP \-u\ \fIuser\fP
+Show only those entries which match the given username (case insensitive).
+.IP \-U\ \fIuser\fP
+Show only those entries which match the given username (case sensitive).
+.IP \-Z
+When combined with \fI-R\fP, prints out the contents of an
+Accounting-Request packet which can be passed to \fIradclient\fP, in
+order to "zap" that users session from \fIradutmp\fP.
+.PP
+For example,
+.RS
+.sp
+.nf
+.ne 3
+$ radwho -ZRN 10.0.0.1 | radclient -f - radius.example.net acct testing123
+.fi
+.sp
+.RE
+will result in all an Accounting-Request packet being sent to the
+RADIUS server, which tells the server that the NAS rebooted. i.e. It
+"zaps" all of the users on that NAS.
+
+To "zap" one user, specify NAS, username, and NAS port:
+.RS
+.sp
+.nf
+.ne 3
+$ radwho -ZRN 10.0.0.1 -u user -P 10 | radclient -f - radius.example.net acct testing123
+.fi
+.sp
+.RE
+Other combinations are also possible.
+
+.SH SEE ALSO
+radiusd(8),
+radclient(1),
+radiusd.conf(5).
+.SH AUTHOR
+Miquel van Smoorenburg, miquels@cistron.nl.
diff --git a/man/man1/radzap.1 b/man/man1/radzap.1
new file mode 100644
index 0000000..03b9a43
--- /dev/null
+++ b/man/man1/radzap.1
@@ -0,0 +1,68 @@
+.TH RADZAP 1 "8 April 2005" "" "FreeRADIUS Daemon"
+.SH NAME
+radzap - remove rogue entries from the active sessions database
+.SH SYNOPSIS
+.B radzap
+.RB [ \-d
+.IR raddb_directory ]
+.RB [ \-h ]
+.RB [ \-N
+.IR nas_ip_address ]
+.RB [ \-P
+.IR nas_port ]
+.RB [ \-u
+.IR user ]
+.RB [ \-U
+.IR user ]
+.RB [ \-x ]
+\fIserver[:port] secret\fP
+.SH DESCRIPTION
+The FreeRADIUS server can be configured to maintain an active session
+database in a file called \fIradutmp\fP. Commands like \fBradwho\fP(1)
+use this database. Sometimes that database can get out of sync, and
+then it might contain rogue entries. \fBradzap\fP can clean up this
+database.
+
+As of FreeRADIUS 1.1.0, \fBradzap\fP is a simple shell-script wrapper
+around \fBradwho\fP(1) and \fBradclient\fP(1).
+
+The sessions are "zapped" by sending an Accounting-Request packet
+which contains the information necessary for the server to delete the
+session record. \fBradzap\fP sends a packet to the server, rather
+than writing to \fIradutmp\fP directly, because session records may
+also be maintained in SQL.
+.SH OPTIONS
+.IP \-d\ \fIraddb_directory\fP
+The directory that contains the RADIUS configuration files.
+\fBradzap\fP reads \fIradiusd.conf\fP to determine the location of the
+\fIradutmp\fP file.
+.IP \-h
+Print usage help information.
+.IP \-N\ \fInas_ip_address\fP
+Zap the entries which match the given NAS IP address.
+.IP \-P\ \fInas_port\fP
+Zap the entries which match the given NAS port.
+.IP \-u\ \fIuser\fP
+Zap the entries which match the given username (case insensitive).
+.IP \-U\ \fIuser\fP
+Zap the entries which match the given username (case sensitive).
+.IP \-x
+Enable debugging output.
+.IP server[:port]
+The hostname or IP address of the remote server. Optionally a UDP port
+can be specified. If no UDP port is specified, it is looked up in
+\fI/etc/services\fP. The service name looked for is \fBradacct\fP for
+accounting packets, and \fBradius\fP for all other requests. If a
+service is not found in \fI/etc/services\fP, 1813 and 1812 are used
+respectively.
+.IP secret
+The shared secret for this client. It needs to be defined on the
+radius server side too, for the IP address you are sending the radius
+packets from.
+.SH SEE ALSO
+radwho(1),
+radclient(1),
+radiusd(8),
+radiusd.conf(5).
+.SH AUTHOR
+Alan DeKok <aland@ox.org>
diff --git a/man/man1/smbencrypt.1 b/man/man1/smbencrypt.1
new file mode 100644
index 0000000..19e4d0e
--- /dev/null
+++ b/man/man1/smbencrypt.1
@@ -0,0 +1,22 @@
+.TH SMBENCRYPT 1
+.SH NAME
+smbencrypt - produce LM & NT password hashes from cleartext passwords
+.SH SYNOPSIS
+.B smbencrypt \fIpassword\fP [\fIpassword ...\fP]
+
+.SH DESCRIPTION
+\fBsmbencrypt\fP For each cleartext password passed on the command line
+emit the LM-Password and NT-Password hashes for that password.
+
+.SH EXAMPLE
+.nf
+$ smbencrypt foo bar
+LM Hash NT Hash
+-------------------------------- --------------------------------
+5BFAFBEBFB6A0942AAD3B435B51404EE AC8E657F83DF82BEEA5D43BDAF7800CC
+A6428F2551EDEE1BAAD3B435B51404EE 86C156FC198B358CCCF6278D8BD49B6A
+.fi
+
+.SH SEE ALSO
+radiusd(8)
+.SH AUTHORS
diff --git a/man/man5/checkrad.5 b/man/man5/checkrad.5
new file mode 100644
index 0000000..68a33f4
--- /dev/null
+++ b/man/man5/checkrad.5
@@ -0,0 +1,95 @@
+.TH CHECKRAD 5 "13 January 2006"
+.SH NAME
+checkrad -- See if a user is (still) logged in on a certain port.
+.SH SYNOPSIS
+.B checkrad
+.RB [ -d ]
+.I nas-type nas-ip nas-port login session-id
+.SH DESCRIPTION
+\fBCheckrad\fP is used by the radius server to check if its idea of a user logged in
+on a certain port/NAS is correct if a double login is detected.
+
+Returns: 0 = no duplicate, 1 = duplicate, >1 = error.
+
+.SH OPTIONS
+
+.IP -d
+Enable printing of debugging information.
+
+.IP nas-type
+Type of port/NAS. Can be one of:
+
+.RS
+.IP \(bu
+ascend
+.IP \(bu
+bay
+.IP \(bu
+cisco
+.IP \(bu
+cisco_l2tp
+.IP \(bu
+computone
+.IP \(bu
+cvx
+.IP \(bu
+digitro
+.IP \(bu
+dot1x
+.IP \(bu
+livingston
+.IP \(bu
+max40xx
+.IP \(bu
+mikrotik
+.IP \(bu
+mikrotik_snmp
+.IP \(bu
+multitech
+.IP \(bu
+netserver
+.IP \(bu
+other
+.IP \(bu
+pathras
+.IP \(bu
+patton
+.IP \(bu
+portslave
+.IP \(bu
+pr3000
+.IP \(bu
+pr4000
+.IP \(bu
+redback
+.IP \(bu
+tc
+.IP \(bu
+usrhiper
+.IP \(bu
+versanet
+.P
+The "other" type cause \fBcheckrad\fP to skip any check and always returns 1.
+.RE
+
+
+.IP nas-ip
+IP address of the NAS to check.
+
+.IP nas-port
+The NAS port to check (may be ignored by some nas-type).
+
+.IP login
+The login name to check.
+
+.IP session-id
+Session to check. (actually ignored by all nas-type)
+
+.SH SEE ALSO
+radiusd(8)
+
+.SH AUTHOR
+Written by Miquel van Smoorenburg, miquels@cistron.nl.
+
+This manual page was written by Marco Nenciarini <mnencia@debian.org> for
+the Debian project (but may be used by others).
diff --git a/man/man5/clients.conf.5 b/man/man5/clients.conf.5
new file mode 100644
index 0000000..6c6b3ee
--- /dev/null
+++ b/man/man5/clients.conf.5
@@ -0,0 +1,46 @@
+.TH clients.conf 5 "13 June 2005" "" "FreeRADIUS client configuration"
+.SH NAME
+clients.conf \- FreeRADIUS client configuration
+.SH DESCRIPTION
+The
+.I clients.conf
+file contains definitions of RADIUS clients.
+.PP
+The information in this file overrides any information provided in
+the deprecated
+.BR clients
+and
+.BR naslist
+files.
+.PP
+The file format is the same as that used for
+.I radiusd.conf.
+See
+.BR radiusd.conf (5)
+for more details.
+.PP
+Each RADIUS client entry has the following basic form:
+.IP
+.nf
+client <short-name> {
+ <attribute> = <value>
+ }
+.fi
+.PP
+Clients have many configuration parameters. Most are documented in the file
+itself as comments. This page documents only the format of the file. Please
+read the \fBclients.conf\fP file itself for more information.
+
+The old-style format from 1.x is still accepted by the server, but
+that form is deprecated.
+.SH FILES
+.I /etc/raddb/clients.conf
+
+.I /etc/raddb/radiusd.conf
+.SH "SEE ALSO"
+.BR radiusd (8),
+.BR radiusd.conf (5)
+
+.SH AUTHOR
+FreeRADIUS is authored by the FreeRADIUS team.
+http://freeradius.org/
diff --git a/man/man5/dictionary.5 b/man/man5/dictionary.5
new file mode 100644
index 0000000..ec63309
--- /dev/null
+++ b/man/man5/dictionary.5
@@ -0,0 +1,185 @@
+.\" # DS - begin display
+.de DS
+.RS
+.nf
+.sp
+..
+.\" # DE - end display
+.de DE
+.fi
+.RE
+.sp
+..
+.TH dictionary 5 "12 Jun 2015"
+.SH NAME
+dictionary \- RADIUS dictionary file
+.SH DESCRIPTION
+The master RADIUS dictionary file resides in
+\fI/etc/raddb/dictionary\fP. It references other \fIdictionary\fP
+files located in \fI/usr/local/share/freeradius/\fP. Each dictionary
+file contains a list of RADIUS attributes and values, which the server
+uses to map between descriptive names and on-the-wire data. The names
+have no meaning outside of the RADIUS server itself, and are never
+exchanged between server and clients.
+.PP
+That is, editing the dictionaries will have NO EFFECT on anything
+other than the server that is reading those files. Adding new
+attributes to the dictionaries will have NO EFFECT on RADIUS clients,
+and will not make RADIUS clients magically understand those
+attributes. The dictionaries are solely for local administrator
+convenience, and are specific to each version of FreeRADIUS.
+.PP
+The dictionaries in \fI/usr/local/share\fP SHOULD NOT be edited unless
+you know exactly what you are doing. Changing them will most likely
+break your RADIUS deployment.
+.PP
+If you need to add new attributes, please edit the
+\fI/etc/raddb/dictionary\fP file. It's sole purpose is to contain
+site-local definitions that are added by the local administrator.
+
+.SH FORMAT
+Every line starting with a hash sign
+.RB (' # ')
+is treated as comment and ignored.
+.PP
+Each line of the file can contain one of the following strings:
+.TP 0.5i
+.B ATTRIBUTE name oid type [flags]
+Define a RADIUS attribute name to number mapping.
+
+The \fIname\fP field is a printable field, taken from various
+specifications or vendor definitions. It is most commonly used as a
+series of words, separated by hyphens. e.g. "User-Name".
+Vendor-specific attributes (VSAs) are prefixed by the vendor name,
+e.g. "Cisco-AVPair". The names should be globally unique, as they are
+used as a key to look up the properties of the attribute.
+
+The \fIoid\fP field is taken from the relevant specification for that
+name. In most cases, it is a decimal number, such as "256". For
+certain attributes, a "dotted number" notation is used, e.g. "1.2".
+The "dotted number" notation is used only for certain attributes.
+
+The \fItype\fP field can be one of the standard types:
+
+ string UTF-8 printable text (the RFCs call this "text")
+ octets opaque binary data (the RFCs call this "string")
+ ipaddr IPv4 address
+ date Seconds since January 1, 1970 (32-bits)
+ integer 32-bit unsigned integer
+ ipv6addr IPv6 Address
+ ipv6prefix IPV6 prefix, with mask
+ ifid Interface Id (hex:hex:hex:hex)
+ integer64 64-bit unsigned integer
+
+The \fItype\fP field can be one of the following non-standard types:
+
+ ether Ethernet MAC address
+ abinary Ascend binary filter format
+ byte 8-bit unsigned integer
+ short 16-bit unsigned integer
+ signed 31-bit signed integer (packed into 32-bit field)
+ tlv Type-Length-Value (allows nested attributes)
+ ipv4prefix IPv4 Prefix as given in RFC 6572.
+
+The last (optional) field of an attribute definition are additional
+flags for that attribute, in a comma-separated list. Previous
+versions of the server allowed these flags to include a vendor name.
+This behavior may still work, but it is deprecated, and is not
+recommended.
+
+The options are:
+
+ encrypt=# set encryption type 1, 2, or 3.
+ has_tag The attribute can have an RFC 2868 style tag
+
+The "encrypt" flag marks the attribute as being encrypted with one of
+three possible methods. "1" means that the attribute is encrypted
+with the method as defined in \fIRFC2865\fP for the User-Password
+attribute. "2" means that the password is encrypted with the method
+as defined in \fIRFC2868\fP for the Tunnel-Password attribute. "3"
+means that the attribute is encrypted as per Ascend's definitions for
+the Ascend-Send-Secret attribute.
+
+The "has_tag" flag marks the attribute as being permitted to have a
+tag, as defined in \fIRFC2868\fP. The purpose of the tag is to allow
+grouping of attributes for tunneled users. See \fIRFC2868\fP for
+more details.
+
+When the server receives an encoded attribute in a RADIUS packet, it
+looks up that attribute by number in the dictionary, and uses the
+definition found there for printing diagnostic and log messages. When
+the server sees an attribute name in a configuration file, it looks up
+that attribute by name in the dictionary, and uses the definition
+found there.
+
+.TP 0.5i
+.B VALUE attribute-name value-name number
+Define an attribute value name to number mapping, for an attribute of
+type \fIinteger\fP. The \fIattribute-name\fP field MUST be previously
+defined by an \fIATTRIBUTE\fP entry. The \fIvalue-name\fP field can
+be any non-space text, but is usually taken from \fIRFC2865\fP, or
+other documents.. The \fInumber\fP field is also taken from the
+relevant documents, for that name.
+
+When the server receives an encoded value in a RADIUS packet, it looks
+up the value of that attribute by number in the dictionary, and uses
+the name found there for printing diagnostic and log messages.
+.TP 0.5i
+.B VENDOR vendor-name number [format=...]
+Define a Vendor Specific Attribute encapsulation for \fIvendor-name\fP
+to \fInumber\fP. For a list of vendor names and numbers, see
+http://www.iana.org/enterprise-numbers.txt.
+
+The "format=t,l" statement tells the server how many octets to use to
+encode/decode the vendor "type" and "length" fields in the attributes.
+The default is "format=1,1", which does not have to be specified. For
+USR VSA's, the format is "format=4,0", for Lucent VSA's it's
+"format=2,1", and for Starent VSA's it's "format=2,2".
+
+The supported values for the number of type octets (i.e. the first
+digit) are 1, 2, and 4. The support values for the number of length
+octets (i.e. the second digit) are 0, 1, and 2. Any combination of
+those values will work.
+
+.TP 0.5i
+.B BEGIN-VENDOR vendor-name
+Define the start of a block of Vendor-Specific attributes. All of the
+following \fIATTRIBUTE\fP definitions are interpreted as being for the
+named vendor, until the block is closed by an "END-VENDOR" statement.
+
+This practice is preferred to placing the vendor name at the end of an
+\fIATTRIBUTE\fP definition.
+
+For VSAs in the RFC 6929 "Extended vendor-specific" space, a format
+can be specified following the "vendor-name". The format should be
+"format=Extended-Vendor-Specific-1", through
+"format=Extended-Vendor-Specific-6". The matching "END-VENDOR" should
+just have the "vendor-name", without the format string.
+.TP 0.5i
+.B END-VENDOR vendor-name
+End a previously defined BEGIN-VENDOR block. The "vendor-name" must match.
+.TP 0.5i
+.B $INCLUDE filename
+Include dictionary entries from the file \fIfilename\fP. The
+\fIfilename\fP is taken as relative to the location of the file which
+is asking for the inclusion.
+.TP 0.5i
+.B BEGIN-TLV name
+This feature is supported for backwards compatibility with older
+dictionaries. It should not be used. The new "oid" form for defining
+the attribute number should be used instead.
+.TP 0.5i
+.B END-TLV name
+This feature is supported for backwards compatibility with older
+dictionaries. It should not be used. The new "oid" form for defining
+the attribute number should be used instead.
+.PP
+.SH FILES
+.I /etc/raddb/dictionary,
+.I /usr/share/freeradius/dictionary.*
+.SH "SEE ALSO"
+.BR radiusd (8),
+.BR RFC2865,
+.BR RFC2866,
+.BR RFC2868
+.BR RFC6929
diff --git a/man/man5/radiusd.conf.5 b/man/man5/radiusd.conf.5
new file mode 100644
index 0000000..3f7caa6
--- /dev/null
+++ b/man/man5/radiusd.conf.5
@@ -0,0 +1,202 @@
+.\" # DS - begin display
+.de DS
+.RS
+.nf
+.sp
+..
+.\" # DE - end display
+.de DE
+.fi
+.RE
+.sp
+..
+.TH radiusd.conf 5 "28 Jun 2013" "" "FreeRADIUS configuration file"
+.SH NAME
+radiusd.conf \- configuration file for the FreeRADIUS server
+.SH DESCRIPTION
+The \fBradiusd.conf\fP file resides in the radius database directory,
+by default \fB/etc/raddb\fP. It defines the global configuration for
+the FreeRADIUS RADIUS server.
+.SH "CONTENTS"
+There are a large number of configuration parameters for the server.
+Most are documented in the file itself as comments. This page
+documents only the format of the file. Please read the
+\fBradiusd.conf\fP file itself for more information.
+
+The configuration file parser is independent of the server
+configuration. This means that you can put almost anything into the
+configuration file. So long as it is properly formatted, the server
+will start.
+
+When the server parses the configuration file, it looks only for those
+configurations it understands. Extra configuration items are ignored.
+This "feature" can be (ab)used in certain interesting ways.
+.SH "FILE FORMAT"
+The file format is line-based, like many other Unix configuration
+files. Each entry in the file must be placed on a line by itself,
+although continuations are supported.
+
+The file consists of configuration items (variable = value pairs),
+sections, and comments.
+.IP Variables
+Variables can be set via:
+
+.DS
+.br
+ name = value
+.DE
+
+Single and double-quoted strings are permitted:
+
+.DS
+.br
+ string1 = "hello world"
+.br
+ string2 = 'hello mom'
+.DE
+.IP Sections
+A section begins with a section name, followed on the same line by an
+open bracket '\fB{\fP'. Section may contain other sections, comments, or
+variables. Sections may be nested to any depth, limited
+only by available memory. A section ends with a close bracket
+\'\fB}\fP', on a line by itself.
+
+.DS
+.br
+ section {
+.br
+ ...
+.br
+ }
+.DE
+
+Sections can sometimes have a second name following the first one.
+The situations where this is legal depend on the context. See the
+examples and comments in the \fBradiusd.conf\fP file for more
+information.
+
+.DS
+.br
+ section foo {
+.br
+ ...
+.br
+ }
+.DE
+.IP Comments
+Any line beginning with a (\fB#\fP) is deemed to be a comment, and is
+ignored. Comments can appear after a variable or section definitions.
+
+.DS
+.br
+ # comment
+.br
+ foo = bar # set variable 'foo' to value 'bar'
+.br
+ section { # start of section
+.br
+ ...
+.br
+ } # end of section
+.DE
+.IP Continuations
+Long lines can be broken up via continuations, using '\\' as the last
+character of the line. For example, the following entry:
+
+.DS
+.br
+ foo = "blah \\
+.br
+ blah \\
+.br
+ blah"
+.DE
+
+will set the value of the variable "foo" to "blah blah blah". Any CR
+or LF is not turned into a space, but all other whitespace is
+preserved in the final value.
+.SH "REFERENCES"
+The value of a variable can reference another variable. These
+references are evaluated when the configuration file is loaded, which
+means that there is no run-time cost associated with them. This
+feature is most useful for turning long, repeated pieces of text into
+short ones.
+
+Variables are referenced by ${variable_name}, as in the following examples.
+
+.DS
+ foo = bar # set variable 'foo' to value 'bar'
+.br
+ who = ${foo} # sets variable 'who' to value of variable 'foo'
+.br
+ my = "${foo} a" # sets variable 'my' to "bar a"
+.DE
+
+If the variable exists in a section or subsection, it can be
+referenced as ${section.subsection.variable}. Forward references are
+not allowed. Relative references are allowed, by pre-pending the name
+with one or more period.
+
+.DS
+ blogs = ${.foo}
+
+.DE
+Will set variable \fBblogs\fP to the value of variable \fBfoo\fP,
+from the current section.
+
+.DS
+ blogs = ${..foo}
+
+.DE
+Will set variable \fBblogs\fP to the value of variable \fBfoo\fP, from the
+section which contains the current section.
+
+.DS
+ blogs = ${modules.detail.filename}
+
+.DE
+Will set variable \fBblogs\fP to the value of variable \fBfilename\fP,
+of the \fBdetail\fP module, which is in the \fBmodules\fP section of
+the configuration file.
+
+Properties of anonymous parent sections may also be referenced, currently
+\fBname\fP and \fBinstance\fP are supported.
+
+.DS
+ modules {
+ example foo {
+ file = ${.:name}
+ }
+ }
+
+.DE
+Will set variable \fBfile\fP to the name of the containing section (example).
+
+.DS
+ modules {
+ example foo {
+ file = ${.:instance}
+ }
+ }
+
+.DE
+Will set variable \fBfile\fP to the instance name of the containing
+section (foo).
+
+.DS
+ modules {
+ example foo {
+ file = ${..:name}
+ }
+ }
+
+.DE
+Will set variable \fBfile\fP to the name of the parent of the containing
+section (modules).
+.SH FILES
+/etc/raddb/radiusd.conf
+.SH "SEE ALSO"
+.BR radiusd (8)
+.BR unlang (5)
+.SH AUTHOR
+Alan DeKok <aland@freeradius.org>
diff --git a/man/man5/radrelay.conf.5 b/man/man5/radrelay.conf.5
new file mode 100644
index 0000000..db74d83
--- /dev/null
+++ b/man/man5/radrelay.conf.5
@@ -0,0 +1,146 @@
+.\" # DS - begin display
+.de DS
+.RS
+.nf
+.sp
+..
+.\" # DE - end display
+.de DE
+.fi
+.RE
+.sp
+..
+.TH radrelay.conf 5 "27 May 2005" "" "FreeRADIUS configuration file"
+.SH NAME
+radrelay.conf - configuration file for the FreeRADIUS server "radrelay" personality
+.SH DESCRIPTION
+The \fBradrelay.conf\fP file resides in the radius database directory,
+by default \fB/etc/raddb\fP. It defines the global configuration for
+the FreeRADIUS server, when the server is operating as "radrelay".
+.SH "FILE FORMAT"
+For a detailed description of the file format, see "man radiusd.conf".
+The configuration entries are much the same for radrelay.conf, with a
+few differences as noted here.
+.SH "REPLICATION FOR BACKUPS"
+Many sites run multiple radius servers; at least one primary and one
+backup server. When the primary goes down, most NASes detect that and
+switch to the backup server.
+
+That will cause your accounting packets to go to the backup server -
+and some NASes don't even switch back to the primary server when it
+comes back up.
+
+The result is that accounting records are missed, and/or the
+administrator must jump through hoops in order to combine the
+different detail files from multiple servers. It also means that the
+session database ("radutmp", used for radwho and simultaneous use
+detection) gets out of sync.
+
+radrelay solves this issue by "relaying" packets from one server to
+another, so they both have the same set of accounting data.
+.SH "BUFFERING FOR HIGH-LOAD SERVERS"
+If the RADIUS server suddenly receives a many accounting packets,
+there may be insufficient CPU power to process them all in a timely
+manner. This problem is especially noticeable when the accounting
+packets are going to a back-end database.
+
+Similarly, you may have one database that tracks "live" sessions, and
+another that tracks historical accounting data. In that case,
+accessing the first database is fast, as it is small. Accessing the
+second database many be slower, as it may contain multiple gigabytes
+of data. In addition, writing to the first database in a timely
+manner is important, while data may be written to the second database
+with a few minutes delay, without any harm being done.
+.SH "RELAYING OF ACCOUNTING PACKETS"
+The \fBradrelay.conf\fP file controls the "radrelay" personality of
+the server, which can perform both of the functions above at the same
+time.
+.SH USAGE
+First, you should configure the main radius server to log to an extra,
+single detail file. This may be done by adding an extra instance of
+the detail module to \fBradiusd.conf\fP:
+
+For example:
+
+.DS
+ detail radrelay-detail {
+.br
+ filename = ${radacctdir}/radrelay/detail
+.br
+ permissions = 0600
+.br
+ dir_permissions = 0755
+.br
+ locking = yes
+.br
+ }
+.br
+ ...
+.br
+ accounting {
+.br
+ ...
+.br
+ radrelay-detail
+.br
+ ...
+.br
+ }
+.br
+.DE
+This configuration will cause accounting packets to be logged to the
+\fI${radacctdir}/radrelay/detail\fP file. This file should not be
+rotated by standard log rotation scripts, as the \fBradrelay\fP
+program will read and rotate it.
+.SH RADRELAY.CONF EXAMPLE
+See the \fBradrelay.conf\fP file for detailed instructions on
+configuration entries, what they mean, and how to use them.
+
+To have the "radrelay" portion of the server read the above detail
+file, configure \fBradrelay.conf\fP with the following section:
+
+.DS
+.br
+ listen {
+.br
+ type = detail
+.br
+ filename = ${radacctdir}/radrelay/detail
+.br
+ max_outstanding = 100
+.br
+ identity = radrelay
+.br
+ }
+.br
+.DE
+
+The server will read the accounting packets from the detail file, and
+process them just as if it had received them from the NAS. Therefore,
+you should configure the "accounting" section of \fBradrelay.conf\fP
+to write the accounting records to an "sql" module, or to proxy them
+to another RADIUS server.
+
+Then, start the server via the following command:
+
+$ radiusd \-n radrelay
+
+The server should start up, read the detail file, and process
+accounting packets from it.
+.SH NOTES
+The \fBradiusd.conf\fP file is not read at all when the server is
+running as radrelay. Please edit \fBradrelay.conf\fP.
+.SH CREDITS
+The original "radrelay" program was written by Miquel van Smoorenburg
+for the Cistron radius project, and ported to FreeRADIUS by Simon
+Ekstrand. The "radsqlrelay" was written by Kostas Kalavras. It was
+never released as part of an official FreeRADIUS release, but served as
+a basis for the design of this implementation.
+.PP
+.SH FILES
+/etc/raddb/radrelay.conf
+.SH "SEE ALSO"
+.BR radiusd (8),
+.BR radiusd.conf (5)
+.SH AUTHOR
+Alan DeKok <aland@ox.org>
diff --git a/man/man5/rlm_always.5 b/man/man5/rlm_always.5
new file mode 100644
index 0000000..383b271
--- /dev/null
+++ b/man/man5/rlm_always.5
@@ -0,0 +1,119 @@
+.\" # DS - begin display
+.de DS
+.RS
+.nf
+.sp
+..
+.\" # DE - end display
+.de DE
+.fi
+.RE
+.sp
+..
+.TH rlm_always 5 "10 January 2015" "" "FreeRADIUS Module"
+.SH NAME
+rlm_always \- FreeRADIUS Module
+.SH DESCRIPTION
+The \fIrlm_always\fP module provides a simple way to "always" return a
+value during the processing of a configuration section.
+.PP
+The main configuration item is \fIrcode\fP, which sets the return code that
+this instantiation of the module will return. The default, if none
+specified, is 'fail'.
+.PP
+The valid options for rcode are as follows:
+.RS
+.TP
+reject
+reject the user;
+.IP fail
+a failure has occurred;
+.IP ok
+success;
+.IP handled
+the request has been handled: processing should be stopped and the response
+sent;
+.IP invalid
+request is invalid;
+.IP userlock
+the user account has been locked out;
+.IP notfound
+the user account cannot be found;
+.IP noop
+no-op: nothing has happened;
+.IP updated
+the request has been updated.
+.RE
+.SH CONFIGURATION
+.PP
+.IP "rcode = <code>"
+This module will always return with the code specified, as listed in the
+table above. If unspecified, the default is 'fail'.
+.IP "simulcount = <n>"
+If this module is used in the session{} section, the simulcount option
+simulates the user having 'n' current sessions. The default is to not
+override the number of sessions.
+.IP "mpp = <yes|no>"
+If set to yes, and this module is used in the session{} section, this
+simulates the user having multilink sessions. The default is 'no'.
+.PP
+.SH EXAMPLE
+.PP
+.DS
+modules {
+ ...
+.br
+ # instantiate the "always" module with the name "ok"
+.br
+ always ok {
+.br
+ # return code for this instantiation is "ok":
+.br
+ rcode = ok
+.br
+ }
+.br
+ ...
+.br
+}
+.br
+
+.br
+authorize {
+ ...
+.br
+ redundant {
+ sql1 # try to find the user in sql1
+.br
+ sql2 # try to find the user in sql2
+.br
+ # the default here would be to fail, but...
+.br
+ ok # if still not found, it's OK.
+.br
+ }
+ ...
+.br
+}
+.DE
+.SH SECTIONS
+.BR authorization,
+.BR authentication,
+.BR postauthentication,
+.BR preaccounting,
+.BR accounting,
+.BR preproxy,
+.BR postproxy
+.PP
+.SH FILES
+.I /etc/raddb/mods-available/always
+.PP
+.SH "SEE ALSO"
+.BR radiusd (8),
+.BR radiusd.conf (5),
+.BR unlang (5)
+.PP
+Further details of how module return codes operate can be found at <http://wiki.freeradius.org/config/Fail-over>.
+.SH AUTHOR
+Chris Parker <cparker@segv.org>, Matthew Newton
+<matthew@newtoncomputing.co.uk>.
diff --git a/man/man5/rlm_attr_filter.5 b/man/man5/rlm_attr_filter.5
new file mode 100644
index 0000000..adb6130
--- /dev/null
+++ b/man/man5/rlm_attr_filter.5
@@ -0,0 +1,145 @@
+.\" # DS - begin display
+.de DS
+.RS
+.nf
+.sp
+..
+.\" # DE - end display
+.de DE
+.fi
+.RE
+.sp
+..
+.TH rlm_attr_filter 5 "27 June 2013" "" "FreeRADIUS Module"
+.SH NAME
+rlm_attr_filter \- FreeRADIUS Module
+.SH DESCRIPTION
+The \fIrlm_attr_filter\fP module exists for filtering certain
+attributes and values in received ( or transmitted ) radius packets.
+It gives the server a flexible framework to filter the attributes we
+send to or receive from home servers or NASes. This makes sense, for
+example, in an out-sourced dialup situation to various policy
+decisions, such as restricting a client to certain ranges of
+Idle-Timeout or Session-Timeout.
+.PP
+Filter rules are normally defined and applied on a per-realm basis,
+where the realm is anything that is defined and matched based on the
+configuration of the \fIrlm_realm\fP module. Filter rules can
+optionally be applied using another attribute, by editing the
+\fIkey\fP configuration for this module.
+.PP
+In 2.0.1 and earlier versions, the "accounting" section filtered the
+Accounting-Request, even though it was documented as filtering the
+response. This issue has been fixed in version 2.0.2 and later
+versions. The "preacct" section may now be used to filter
+Accounting-Request packets. The "accounting" section now filters
+Accounting-Response packets. Administrators using "attr_filter" in
+the "accounting" section SHOULD move the reference to "attr_filter"
+from "accounting" to "preacct".
+.PP
+The file that defines the attribute filtering rules follows a similar
+syntax to the \fIusers\fP file. There are a few differences however:
+.PP
+.DS
+ There are no check-items allowed other than the name of the key.
+.PP
+ There can only be a single DEFAULT entry.
+.PP
+The rules for each entry are parsed to top to bottom, and an
+attribute must pass *all* the rules which affect it in order to
+make it past the filter. Order of the rules is important.
+The operators and their purpose in defining the rules are as
+follows:
+.TP
+.B =
+THIS OPERATOR IS NOT ALLOWED. If used, and warning message is
+printed and it is treated as ==
+.TP
+.B :=
+Set, this attribute and value will always be placed in the
+output A/V Pairs. If the attribute exists, it is overwritten.
+.TP
+.B ==
+Equal, value must match exactly.
+.TP
+.B =*
+Always Equal, allow all values for the specified attribute.
+.TP
+.B !*
+Never Equal, disallow all values for the specified attribute.
+( This is redundant, as any A/V Pair not explicitly permitted
+will be dropped ).
+.TP
+.B !=
+Not Equal, value must not match.
+.TP
+.B >=
+Greater Than or Equal
+.TP
+.B <=
+Less Than or Equal
+.TP
+.B >
+Greater Than
+.TP
+.B <
+Less Than
+.PP
+If regular expressions are enabled the following operators are
+also possible. ( Regular Expressions are included by default
+unless your system doesn't support them, which should be rare ).
+The value field uses standard regular expression syntax.
+.PP
+.TP
+.B =~
+Regular Expression Equal
+.TP
+.B !~
+Regular Expression Not Equal
+.PP
+See the default \fI/etc/raddb/mods-config/attr_filter/\fP for working examples of
+sample rule ordering and how to use the different operators.
+.DE
+.PP
+The configuration items are:
+.IP file
+This specifies the location of the file used to load the filter rules.
+This file is used to filter the accounting response, packet before it
+is proxied, proxy response from the home server, or our response to
+the NAS.
+.IP key
+Usually %{Realm} (the default). Can also be %{User-Name}, or other
+attribute that exists in the request. Note that the module always
+keys off of attributes in the request, and NOT in any other packet.
+.IP relaxed
+If set to 'yes', then attributes which do not match any filter rules
+explicitly, will also be allowed. This behaviour may be overridden
+for an individual filter block using the Relax-Filter check item.
+The default for this configuration item is 'no'.
+.PP
+.SH SECTIONS
+.IP preacct
+Filters Accounting-Request packets.
+.IP accounting
+Filters Accounting-Response packets.
+.IP pre-proxy
+Filters Accounting-Request or Access-Request packets prior to proxying
+them.
+.IP post-proxy
+Filters Accounting-Response, Access-Accept, Access-Reject, or
+Access-Challenge responses from a home server.
+.IP authorize
+Filters Access-Request packets.
+.IP post-auth
+Filters Access-Accept or Access-Reject packets.
+.PP
+.SH FILES
+.I /etc/raddb/radiusd.conf
+.I /etc/raddb/mods-config/attr_filter/*
+.PP
+.SH "SEE ALSO"
+.BR radiusd (8),
+.BR radiusd.conf (5)
+.SH AUTHOR
+Chris Parker, cparker@segv.org
+
diff --git a/man/man5/rlm_chap.5 b/man/man5/rlm_chap.5
new file mode 100644
index 0000000..de0b8c0
--- /dev/null
+++ b/man/man5/rlm_chap.5
@@ -0,0 +1,30 @@
+.TH rlm_chap 5 "3 February 2004" "" "FreeRADIUS Module"
+.SH NAME
+rlm_chap \- FreeRADIUS Module
+.SH DESCRIPTION
+The \fIrlm_chap\fP module provides CHAP functionality.
+.PP
+This module validates a user with CHAP authentication.
+If called in Authorize, it will look for CHAP-Password
+attribute in the Access-Request and adds an Auth-Type
+attribute set to CHAP if the Config-Items list unless
+Auth-Type has already set.
+.PP
+CHAP authentication requires access to the clear-text
+password for the user. Standard Unix system authentication
+or passwords encrypted via crypt() are not compatible
+with CHAP.
+.PP
+.SH SECTIONS
+.BR authorization,
+.BR authentication
+.PP
+.SH FILES
+.I /etc/raddb/radiusd.conf
+.PP
+.SH "SEE ALSO"
+.BR radiusd (8),
+.BR radiusd.conf (5)
+.SH AUTHOR
+Chris Parker, cparker@segv.org
+
diff --git a/man/man5/rlm_counter.5 b/man/man5/rlm_counter.5
new file mode 100644
index 0000000..a8eae18
--- /dev/null
+++ b/man/man5/rlm_counter.5
@@ -0,0 +1,89 @@
+.\" # DS - begin display
+.de DS
+.RS
+.nf
+.sp
+..
+.\" # DE - end display
+.de DE
+.fi
+.RE
+.sp
+..
+.TH rlm_counter 5 "13 March 2004" "" "FreeRADIUS Module"
+.SH NAME
+rlm_counter \- FreeRADIUS Module
+.SH DESCRIPTION
+The \fIrlm_counter\fP module provides a general framework to
+allow access based on accumulated usage of a resource, such as
+total time online in a given period, total data transferred in
+a given period, etc. This is very useful in a 'Prepaid Service'
+situation, where a user has paid for a finite amount of usage
+and should not be allowed to use more than that service. Collection,
+monitoring, and replenishment of prepaid services are beyond the
+scope of this module.
+.PP
+The main configuration items to be aware of are:
+.IP filename
+The filename where the usage data is stored.
+.IP key
+An attribute which will be present in the Access-Request to be used as
+the 'index' value for the counter. A counter entry is tracked for
+each unique key. The most likely key you will want to use is User-Name.
+.IP count_attribute
+An attribute which will be used to increment the counter value. If this
+attribute is Acct-Session-Time or an integer value the counter data is
+incremented by the Attribute value. For all other attribute types the
+counter is incremented by one.
+.IP reset
+How frequently the counter data should be set back to 0. Valid values for
+this variable are:
+.BR hourly,
+.BR daily,
+.BR weekly,
+.BR monthly,
+.BR or never
+Alternatively, it can be user defined, in the form: num[hdwm]. num is
+a numeric value, followed by one or none of the following letters. h: hours,
+d: days, w: weeks, m: months.
+.IP check_name
+This defines an attribute name 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. If Daily-Session-Time is set, you can use the following
+syntax in the Users file to set a cap of 3600 seconds ( 8 hours ):
+.PP
+.DS
+DEFAULT Max-Daily-Session := 3600
+.DE
+.PP
+.IP reply_name
+This is the name of the attribute which will contain the remaining value for
+the counter in the reply packet when the user is successfully authorized. The
+default attribute name is "Session-Timeout".
+.IP allowed_service_type
+This can be used to only apply the limitations to specific service types of
+sessions. For example, setting this to Framed-User will only apply the counter
+module to Framed sessions, excluding other types such as Telnet or Rlogin.
+.IP cache_size
+The maximum size of the cache to be used by the module. The default is 1000.
+.SH NOTES
+This module registers an attribute, so it should be added to the
+instantiate section, to be called on server startup. When used
+in the authorize section, it must come after any modules which
+set the 'check_name' attribute.
+.PP
+.SH SECTIONS
+.BR instantiate,
+.BR authorize,
+.BR accounting
+.PP
+.SH FILES
+.I /etc/raddb/radiusd.conf
+.PP
+.SH "SEE ALSO"
+.BR radiusd (8),
+.BR radiusd.conf (5)
+.BR rlm_sqlcounter (5)
+.SH AUTHOR
+Chris Parker, cparker@segv.org
+
diff --git a/man/man5/rlm_detail.5 b/man/man5/rlm_detail.5
new file mode 100644
index 0000000..6609e16
--- /dev/null
+++ b/man/man5/rlm_detail.5
@@ -0,0 +1,89 @@
+.\" # DS - begin display
+.de DS
+.RS
+.nf
+.sp
+..
+.\" # DE - end display
+.de DE
+.fi
+.RE
+.sp
+..
+.TH rlm_detail 5 "27 June 2013" "" "FreeRADIUS Module"
+.SH NAME
+rlm_detail \- FreeRADIUS Module
+.SH DESCRIPTION
+The \fIrlm_detail\fP module writes radius packets to 'detail' files.
+It is primarily used for storing accounting information, but can be
+used in other sections to write packet details as well.
+.PP
+The file format is similar to that of the old Livingston servers, and
+many 'detail' file parsers should work with FreeRADIUS.
+.PP
+The main configuration items to be aware of are:
+.IP file
+The file name in which to store the radius packet records. NOTE: this
+variable is run through dynamic string expansion, and can include
+FreeRADIUS variables to create a dynamic filename.
+.PP
+ %{radacctdir}/%{Client-IP-Address}/detail-%Y%m
+.PP
+ This will create one file per month, for each client.
+ This accomplishes 'file rotation' automatically from
+ within the server.
+.PP
+.IP permissions
+The file permissions of the file.
+If omitted, the default is 0600.
+.IP locking
+This option is set to 'yes' or 'no'. By default it is 'no'. Set this
+to yes to enable file locking, which is used with the 'radrelay'
+program.
+.SH CONFIGURATION
+.PP
+.DS
+modules {
+ ...
+.br
+ detail {
+.br
+ filename = ${radacctdir}/%{Client-IP-Address}/detail-%Y%m
+.br
+ permissions = 0600
+.br
+ dir_permissions = 0755
+.br
+ locking = no
+.br
+ }
+.br
+ ...
+.br
+}
+ ...
+.br
+accounting {
+ ...
+.br
+ detail
+ ...
+.br
+}
+.DE
+.PP
+.SH SECTIONS
+.BR authorization,
+.BR accounting,
+.BR pre_proxy,
+.BR post_proxy,
+.BR post_authentication
+.PP
+.SH FILES
+.I /etc/raddb/radiusd.conf
+.PP
+.SH "SEE ALSO"
+.BR radiusd (8),
+.BR radiusd.conf (5)
+.SH AUTHORS
+Chris Parker, cparker@segv.org
diff --git a/man/man5/rlm_digest.5 b/man/man5/rlm_digest.5
new file mode 100644
index 0000000..fb99e0f
--- /dev/null
+++ b/man/man5/rlm_digest.5
@@ -0,0 +1,79 @@
+.\" # DS - begin display
+.de DS
+.RS
+.nf
+.sp
+..
+.\" # DE - end display
+.de DE
+.fi
+.RE
+.sp
+..
+.TH rlm_digest 5 "31 March 2005" "" "FreeRADIUS Module"
+.SH NAME
+rlm_digest \- FreeRADIUS Module
+.SH DESCRIPTION
+The \fIrlm_digest\fP module authenticates RADIUS Access-Request
+packets that contain Cisco SIP digest authentication attributes. The
+module should be listed in the \fIauthorize\fP and \fIauthenticate\fP
+sections of \fIradiusd.conf\fP.
+.SH CONFIGURATION
+The digest module requires no additional configuration items. When it
+is being used to authenticate requests, however, it does require
+access to the clear-text password for the user. Hashed passwords are
+not acceptable, and will not work.
+.SH EXAMPLES
+Add the following lines to the top of your 'raddb/users' file:
+.PP
+.DS
+#---
+.br
+test Auth-Type := Digest, User-Password = "test"
+.br
+ Reply-Message = "Hello, test with digest"
+.br
+#---
+.DE
+
+Once the server has been started (debugging mode is recommended),
+use '\fIradclient\fP to send the following packet to the server:
+.PP
+.DS
+$ radclient \-f digest localhost auth testing123
+.DE
+
+Where 'digest' is a file containing:
+.PP
+.DS
+ User-Name = "test",
+.br
+ Digest-Response = "631d6d73147add2f9e437f59bbc3aeb7",
+.br
+ Digest-Realm = "testrealm",
+.br
+ Digest-Nonce = "1234abcd",
+.br
+ Digest-Method = "INVITE",
+.br
+ Digest-URI = "sip:5555551212@example.com",
+.br
+ Digest-Algorithm = "MD5",
+.br
+ Digest-User-Name = "test",
+.br
+ Message-Authenticator = ""
+.DE
+
+You should see the authentication succeed.
+
+.SH SECTIONS
+.BR authorize,
+.BR authenticate
+.PP
+.SH FILES
+.I /etc/raddb/radiusd.conf,
+.I draft-sterman-aaa-sip-00.txt
+.PP
+.SH AUTHOR
+Alan DeKok <aland@ox.org>
diff --git a/man/man5/rlm_expr.5 b/man/man5/rlm_expr.5
new file mode 100644
index 0000000..313a16e
--- /dev/null
+++ b/man/man5/rlm_expr.5
@@ -0,0 +1,113 @@
+.\" # DS - begin display
+.de DS
+.RS
+.nf
+.sp
+..
+.\" # DE - end display
+.de DE
+.fi
+.RE
+.sp
+..
+.TH rlm_expr 5 "5 February 2004" "" "FreeRADIUS Module"
+.SH NAME
+rlm_expr \- FreeRADIUS Module
+.SH DESCRIPTION
+The \fIrlm_expr\fP module allows the server to perform
+limited mathematical calculations. This module is not called
+directly in any section, it is invoked through the dynamic expansion
+of strings.
+.PP
+For example, some NAS boxes send a NAS-Port attribute
+which is a 32-bit number composed of port, card, and interface, all in
+different bytes. To see these attributes split into pieces, you can
+have an entry in the 'users' file like:
+
+.DS
+DEFAULT
+.br
+ Vendor-Interface = `%{expr: %{NAS-Port} / (256 * 256)}`,
+.br
+ Vendor-Card = `%{expr: (%{NAS-Port} / 256) %% 256}`,
+.br
+ Vendor-Port = `%{expr: %{NAS-Port} %% 256}`
+.br
+
+.DE
+where the attributes Vendor-Interface, Vendor-Card, and Vendor-Port
+are attributes created by either you or a vendor-supplied
+dictionary.
+
+The mathematical operators supported by the expression module are:
+.TP
+.B +
+addition
+.TP
+.B -
+subtraction
+.TP
+.B /
+division
+.TP
+.B %%
+modulo remainder
+.TP
+.B *
+multiplication
+.TP
+.B &
+boolean AND
+.TP
+.B |
+boolean OR
+.TP
+.B ()
+grouping of sub-expressions
+.PP
+NOTE: The modulo remainder operator is '%%', and not '%'. This
+is due to the '%' character being used as a special character for
+dynamic translation.
+.PP
+NOTE: These operators do NOT have precedence. The parsing
+of the input string, and the calculation of the answer, is done
+strictly left to right. If you wish to order the expressions, you
+MUST group them into sub-expression, as shown in the previous
+example.
+.PP
+All of the calculations are performed as unsigned 32-bit integers.
+.DE
+.SH CONFIGURATION
+.DS
+modules {
+ ...
+.br
+ expr {
+.br
+ }
+.br
+ ...
+.br
+}
+.br
+ ...
+.br
+instantiate {
+ ...
+.br
+ expr
+ ...
+.br
+}
+.SH SECTIONS
+.BR instantiate
+.PP
+.SH FILES
+.I /etc/raddb/radiusd.conf
+.PP
+.SH "SEE ALSO"
+.BR radiusd (8),
+.BR radiusd.conf (5)
+.SH AUTHOR
+Chris Parker, cparker@segv.org
+
diff --git a/man/man5/rlm_files.5 b/man/man5/rlm_files.5
new file mode 100644
index 0000000..52f4734
--- /dev/null
+++ b/man/man5/rlm_files.5
@@ -0,0 +1,95 @@
+.\" # DS - begin display
+.de DS
+.RS
+.nf
+.sp
+..
+.\" # DE - end display
+.de DE
+.fi
+.RE
+.sp
+..
+.TH rlm_files 5 "5 February 2004" "" "FreeRADIUS Module"
+.SH NAME
+rlm_files \- FreeRADIUS Module
+.SH DESCRIPTION
+The \fIrlm_files\fP module uses the 'users' file for accessing
+authorization information for users. Additionally, it supports
+a 'users' file syntax to be applied to the accounting and pre-proxy
+sections.
+.PP
+The main configuration items to be aware of are:
+.IP usersfile
+The filename of the 'users' file, which is parsed during the
+authorization stage of this module.
+.IP acctusersfile
+The filename of the 'users' file, which is parsed during the
+accounting stage of this module.
+.IP preproxy_usersfile
+The filename of the 'users' file, which is parsed during the
+pre_proxy stage of this module.
+.IP compat
+This option allows FreeRADIUS to parse an old style Cistron syntax.
+The default is 'no'. If you need to parse an old style Cistron
+file, set this option to 'cistron'.
+.IP key
+This option lets you set the attribute to use as a key to find
+entries. The default is "%{%{Stripped-User-Name}:-%{User-Name}}". Note
+that the key MUST supply real data. Dynamic attributes like "Group"
+will not work, because the "Group" attribute can only be used as a
+comparison, to see if a user is in a Unix group. It will not return
+the name of the Unix group that a user is in.
+.PP
+If you want to use groups as a key, see the \fIrlm_passwd\fP, which
+will create a real attribute that contains the group name.
+.PP
+This configuration entry enables you to have configurations that
+perform per-group checks, and return per-group attributes, where the
+group membership is dynamically defined by a previous module. It also
+lets you do things like key off of attributes in the reply, and
+express policies like "when I send replies containing attribute
+FOO with value BAR, do more checks, and maybe send additional
+attributes".
+.SH CONFIGURATION
+.PP
+.DS
+modules {
+ ... stuff here ...
+.br
+ files {
+.br
+ usersfile = %{confdir}/users
+.br
+ acctusersfile = %{confdir}/acct_users
+.br
+ preproxy_usersfile = %{confdir}/preproxy_users
+.br
+ compat = no
+.br
+ key = %{%{Stripped-User-Name}:-%{User-Name}}
+.br
+ }
+.br
+ ... stuff here ...
+.br
+}
+.DE
+.PP
+.SH SECTIONS
+.BR authorization,
+.BR accounting,
+.BR pre_proxy
+.PP
+.SH FILES
+.I /etc/raddb/radiusd.conf,
+.I /etc/raddb/users,
+.I /etc/raddb/acct_users,
+.I /etc/raddb/preproxy_users
+.PP
+.SH "SEE ALSO"
+.BR radiusd (8),
+.BR radiusd.conf (5),
+.BR users (5)
+.SH AUTHORS
+Chris Parker, cparker@segv.org
diff --git a/man/man5/rlm_idn.5 b/man/man5/rlm_idn.5
new file mode 100644
index 0000000..391b7d9
--- /dev/null
+++ b/man/man5/rlm_idn.5
@@ -0,0 +1,45 @@
+.\" # DS - begin display
+.de DS
+.RS
+.nf
+.sp
+..
+.\" # DE - end display
+.de DE
+.fi
+.RE
+.sp
+..
+.TH rlm_idn 5 "8 May 2013" "" "FreeRADIUS Module"
+.SH NAME
+rlm_idn \- FreeRADIUS Module
+.SH DESCRIPTION
+When instantiated, the \fIrlm_idn\fP module provides an xlat
+for performing IDNA encoding of internationalized domain names.
+Decoding and other similar encodings like plain punycode are not
+currently supported.
+.PP
+For example, the following unlang expression would evaluate to TRUE:
+
+"%{idn:fūbar.site}" == "xn--fbar-v7a.site"
+
+.PP
+Each instance of rlm_idn may take the following parameters:
+.IP use_std3_ascii_rules
+This boolean is set by default and prohibits e.g. underscores in domain names.
+.IP allow_unassigned
+This boolean is unset by default, which prohibits use of unassigned Unicode points.
+.PP
+.SH FILES
+.I /etc/raddb/radiusd.conf
+.PP
+.SH REFERENCES
+RFC 3490
+.PP
+.SH "SEE ALSO"
+.BR radiusd (8),
+.BR radiusd.conf (5)
+.BR idna_to_ascii_8z (3)
+.SH AUTHOR
+Brian S. Julin, bjulin@clarku.edu
+
diff --git a/man/man5/rlm_mschap.5 b/man/man5/rlm_mschap.5
new file mode 100644
index 0000000..cc3a72a
--- /dev/null
+++ b/man/man5/rlm_mschap.5
@@ -0,0 +1,110 @@
+.\" # DS - begin display
+.de DS
+.RS
+.nf
+.sp
+..
+.\" # DE - end display
+.de DE
+.fi
+.RE
+.sp
+..
+.TH rlm_mschap 5 "13 March 2004" "" "FreeRADIUS Module"
+.SH NAME
+rlm_mschap \- FreeRADIUS Module
+.SH DESCRIPTION
+The \fIrlm_mschap\fP module provides MS-CHAP and MS-CHAPv2
+authentication support.
+.PP
+This module validates a user with MS-CHAP or MS-CHAPv2
+authentication.
+If called in Authorize, it will look for MS-CHAP Challenge/Response
+attributes in the Acess-Request and adds an Auth-Type
+attribute set to MS-CHAP in the Config-Items list unless
+Auth-Type has already set.
+.PP
+The module can authenticate the MS-CHAP session via plain-text
+passwords (User-Password attribute), or NT passwords (NT-Password
+attribute). The module cannot perform authentication against an NT
+domain.
+.PP
+The module also enforces the SMB-Account-Ctrl attribute. See the
+Samba documentation for the meaning of SMB account control. The
+module does not read Samba password files. Instead, the fIrlm_passwd\fP
+module can be used to read a Samba password file, and supply an
+NT-Password attribute which this module can use.
+.PP
+The main configuration items to be aware of are:
+.IP authtype
+This is the string used to set the authtype. Normally it should be
+left to the default value of MS-CHAP.
+.IP use_mppe
+Unless this is set to 'no', FreeRADIUS will add MS-CHAP-MPPE-Keys for
+MS-CHAPv1 and MS-MPPE-Recv-Key/MS-MPPE-Send-Key for MS-CHAPv2. The
+default is 'yes'.
+.IP require_encryption
+If MPPE is enabled, setting this attribute to 'yes' will cause the
+MS-MPPE-Encryption-Policy attribute to be set to require encryption.
+The default is 'no'.
+.IP require_strong
+If MPPE is enabled, setting this attribute to 'yes' will cause the
+MS-MPPE-Encryption-Types attribute to be set to require a 128 bit key.
+The default is 'no'.
+.IP with_ntdomain_hack
+Windows clients send User-Name in the form of "DOMAIN\\User", but send the
+challenge/response based only on the User portion. Setting this value
+to yes, enables a work-around for this error. The default is 'no'.
+.PP
+.SH CONFIGURATION
+.DS
+modules {
+ ...
+.br
+ mschap {
+.br
+ authtype = MS-CHAP
+.br
+ use_mppe = yes
+.br
+ }
+.br
+ ...
+.br
+}
+.br
+ ...
+.br
+authorize {
+ ...
+.br
+ mschap
+.br
+ ...
+.br
+}
+ ...
+.br
+authenticate {
+ ...
+.br
+ mschap
+.br
+ ...
+.br
+}
+.DE
+.PP
+.SH SECTIONS
+.BR authorization,
+.BR authentication
+.PP
+.SH FILES
+.I /etc/raddb/radiusd.conf
+.PP
+.SH "SEE ALSO"
+.BR radiusd (8),
+.BR radiusd.conf (5)
+.SH AUTHOR
+Chris Parker, cparker@segv.org
+
diff --git a/man/man5/rlm_pap.5 b/man/man5/rlm_pap.5
new file mode 100644
index 0000000..e2ad426
--- /dev/null
+++ b/man/man5/rlm_pap.5
@@ -0,0 +1,137 @@
+.\" # DS - begin display
+.de DS
+.RS
+.nf
+.sp
+..
+.\" # DE - end display
+.de DE
+.fi
+.RE
+.sp
+..
+.TH rlm_pap 5 "10 January 2015" "" "FreeRADIUS Module"
+.SH NAME
+rlm_pap \- FreeRADIUS Module
+.SH DESCRIPTION
+The \fIrlm_pap\fP module authenticates RADIUS Access-Request packets
+that contain a User-Password attribute. The module should also be
+listed last in the \fIauthorize\fP section, so that it can set the
+Auth-Type attribute as appropriate.
+.PP
+When a RADIUS packet contains a clear-text password in the form of a
+User-Password attribute, the \fIrlm_pap\fP module may be used for
+authentication. The module requires a "known good" password, which it
+uses to validate the password given in the RADIUS packet. That "known
+good" password must be supplied by another module
+(e.g. \fIrlm_files\fP, \fIrlm_ldap\fP, etc.), and is usually taken
+from a database.
+.SH CONFIGURATION
+.PP
+The only configuration item is:
+.IP normalise
+The default is "yes". This means that the module will try to
+automatically detect passwords that are hex- or base64-encoded and
+decode them back to their binary representation. However, some clear
+text passwords may be erroneously converted. Setting this to "no"
+prevents that conversion.
+.SH USAGE
+.PP
+The module looks for the Password-With-Header control attribute to find
+the "known good" password. The attribute value comprises the header
+followed immediately by the password data. The header is given by the
+following table.
+.PP
+.DS
+.br
+Header Attribute Description
+.br
+------ --------- -----------
+.br
+{clear} Cleartext-Password Clear-text passwords
+.br
+{cleartext} Cleartext-Password Clear-text passwords
+.br
+{crypt} Crypt-Password Unix-style "crypt"ed passwords
+.br
+{md5} MD5-Password MD5 hashed passwords
+.br
+{base64_md5} MD5-Password MD5 hashed passwords
+.br
+{smd5} SMD5-Password MD5 hashed passwords, with a salt
+.br
+{sha} SHA-Password SHA1 hashed passwords
+.br
+ SHA1-Password SHA1 hashed passwords
+.br
+{ssha} SSHA-Password SHA1 hashed passwords, with a salt
+.br
+{sha2} SHA2-Password SHA2 hashed passwords
+.br
+{sha224} SHA2-Password SHA2 hashed passwords
+.br
+{sha256} SHA2-Password SHA2 hashed passwords
+.br
+{sha384} SHA2-Password SHA2 hashed passwords
+.br
+{sha512} SHA2-Password SHA2 hashed passwords
+.br
+{ssha224} SSHA2-224-Password SHA2 hashed passwords, with a salt
+.br
+{ssha256} SSHA2-256-Password SHA2 hashed passwords, with a salt
+.br
+{ssha384} SSHA2-384-Password SHA2 hashed passwords, with a salt
+.br
+{ssha512} SSHA2-512-Password SHA2 hashed passwords, with a salt
+.br
+{nt} NT-Password Windows NT hashed passwords
+.br
+{nthash} NT-Password Windows NT hashed passwords
+.br
+{md4} NT-Password Windows NT hashed passwords
+.br
+{x-nthash} NT-Password Windows NT hashed passwords
+.br
+{ns-mta-md5} NS-MTA-MD5-Password Netscape MTA MD5 hashed passwords
+.br
+{x- orcllmv} LM-Password Windows LANMAN hashed passwords
+.br
+{X- orclntv} NT-Password Windows NT hashed passwords
+.DE
+
+The module tries to be flexible when handling the various password
+formats. It will automatically handle Base-64 encoded data, hex
+strings, and binary data, and convert them to a format that the server
+can use.
+.PP
+If there is no Password-With-Header attribute, the module looks for one
+of the Cleartext-Password, NT-Password, Crypt-Password, etc. attributes
+as listed in the above table. These attributes should contain the
+relevant format password directly, without the header prefix.
+.PP
+Only one control attribute should be set, otherwise behaviour is
+undefined as to which one is used for authentication.
+.SH NOTES
+.PP
+It is important to understand the difference between the User-Password
+and Cleartext-Password attributes. The Cleartext-Password attribute
+is the "known good" password for the user. Simply supplying the
+Cleartext-Password to the server will result in most authentication
+methods working. The User-Password attribute is the password as typed
+in by the user on their private machine. The two are not the same,
+and should be treated very differently. That is, you should generally
+not use the User-Password attribute anywhere in the RADIUS
+configuration.
+.SH SECTIONS
+.BR authorize
+.BR authenticate
+.PP
+.SH FILES
+.I /etc/raddb/mods-available/pap
+.PP
+.SH "SEE ALSO"
+.BR radiusd (8),
+.BR radiusd.conf (5)
+.SH AUTHOR
+Alan DeKok <aland@freeradius.org>
+
diff --git a/man/man5/rlm_passwd.5 b/man/man5/rlm_passwd.5
new file mode 100644
index 0000000..5a9ac7b
--- /dev/null
+++ b/man/man5/rlm_passwd.5
@@ -0,0 +1,136 @@
+.\" # DS - begin display
+.de DS
+.RS
+.nf
+.sp
+..
+.\" # DE - end display
+.de DE
+.fi
+.RE
+.sp
+..
+.TH rlm_passwd 5 "20 January 2015" "" "FreeRADIUS Module"
+.SH NAME
+rlm_passwd \- FreeRADIUS Module
+.SH DESCRIPTION
+The \fIrlm_passwd\fP module provides authorization via files similar
+in format to /etc/passwd.
+.PP
+This module allows you to retrieve any account information from any
+files with passwd-like format (/etc/passwd, /etc/group,
+smbpasswd, .htpasswd, etc). Every field of the file may be mapped to
+a RADIUS attribute, with one of the fields used as a key.
+.PP
+The module reads the file when it initializes, and caches the data in
+memory. This makes it very fast, even for files with thousands of
+lines. To re-read the file the module will need to be reloaded with
+\fIradmin(8)\fP, or the server will need to be sent a SIGHUP, as
+dynamic updates are not supported.
+.PP
+.SH CONFIGURATION
+The configuration item(s):
+.IP allow_multiple_keys
+If set to 'yes', and more than one record in file matches the request,
+then the attributes from all records will be used. If set to 'no' (the
+default) the module will warn about duplicated records.
+.IP delimiter\ =\ ":"
+The character to use as a delimiter between fields. The default is
+":"
+.IP filename
+The path to the file.
+.IP format
+The format of the fields in the file, given as an example line from
+the file, with the content of the fields as the RADIUS attributes
+which the fields map to. The fields are separated by the ':' character
+in the configuration (no matter what is configured for the 'delimiter'
+option).
+.IP hash_size
+The size of the hash table. A larger value means less probability of a
+collision so records will be found faster, at the expense of greater
+memory usage. Having a hash_size in the range of 30-100% of the number
+of passwd file records is reasonable.
+.IP ignore_empty
+When set to "yes", the default, empty fields in the input will be
+skipped and the RADIUS attribute will not be added. By setting this
+value to "no", all attributes in the format list will always be added,
+even if they have no value.
+.IP ignore_nislike
+If set to 'yes', then all records from the file beginning with the '+'
+sign will be ignored. The default is 'no'.
+.PP
+.SH FORMAT
+The \fIformat\fP option controls how lines are read from the file, and
+which fields are mapped to which RADIUS attributes.
+.PP
+The key field is the field being searched for within the file. It is
+normally signified by being preceded with a '*' character, which
+indicates that the field has only one key, like the /etc/passwd file.
+The key field may instead be preceded with '*,', which indicates that
+the field has multiple possible comma-separated keys, such as when
+searching the /etc/group file.
+.PP
+The other fields signify RADIUS attributes. By default they will be
+added as a control attribute list.
+.PP
+To add an attribute to the RADIUS request (as though it had been sent
+by the NAS), prefix the attribute name in the "format" string with the
+\(aq~' character.
+.PP
+To add an attribute to the RADIUS reply (to be sent back to the NAS),
+prefix the attribute name in the "format" string with the '='
+character.
+.PP
+.SH EXAMPLES
+.DS
+format = "*User-Name:Crypt-Password:"
+.DE
+.IP
+For a file the looks similar to /etc/passwd. The first field,
+User-Name, is the key to look up in the file. When the record is
+found, a control attribute, 'Crypt-Password', will be added with the
+contents of the second field. (Note this will not work with shadow
+passwords.)
+.PP
+.DS
+format = "My-Group:::*,User-Name"
+.DE
+.IP
+Parse a file similar to the /etc/group file. An entry matches a
+request when the name in a User-Name attribute exists in the
+comma-separated list of a line in the file. When an entry matches,
+a "My-Group" attribute will be created and added to the control
+items for the request. The value of that attribute will be taken from
+the first field of the matching line in the file.
+.IP
+The ":::" in the format string means that there are extra two fields
+in the line, in between the group name and list of user names. Those
+fields do not map to any RADIUS attribute, and are therefore ignored.
+.IP
+For this example to work in practice, you will have to add the
+My-Group attribute to the dictionary file. See \fIdictionary(5)\fP
+for details on how this may be done.
+.PP
+.DS
+format = "~My-Group:::*,User-Name"
+.DE
+.IP
+Similar to the previous entry, except the My-Group attribute is added
+to the request, as though it was sent by the NAS.
+.PP
+.SH SECTIONS
+.BR authorize
+.PP
+.SH FILES
+.I /etc/raddb/mods-available/passwd
+.PP
+.SH "SEE ALSO"
+.BR radiusd (8),
+.BR radiusd.conf (5),
+.BR radmin (8),
+.BR dictionary (5),
+.BR rlm_unix (5)
+.SH AUTHOR
+Alan DeKok <aland@freeradius.org>, Matthew Newton
+<matthew@newtoncomputing.co.uk>.
+
diff --git a/man/man5/rlm_realm.5 b/man/man5/rlm_realm.5
new file mode 100644
index 0000000..8b8237a
--- /dev/null
+++ b/man/man5/rlm_realm.5
@@ -0,0 +1,94 @@
+.\" # DS - begin display
+.de DS
+.RS
+.nf
+.sp
+..
+.\" # DE - end display
+.de DE
+.fi
+.RE
+.sp
+..
+.TH rlm_realm 5 "14 March 2004" "" "FreeRADIUS Module"
+.SH NAME
+rlm_realm \- FreeRADIUS Module
+.SH DESCRIPTION
+The \fIrlm_realm\fP module parses the User-Name attribute into a
+User section and a Realm section. This is used primarily in a
+proxy situation, however, Realms can also be used locally to provide
+different service profiles based on the Realm being used.
+.PP
+The main configuration items to be aware of are:
+.IP format
+This can be either 'prefix' or 'suffix'. It specifies whether the
+Realm is before or after the User portion in the User-Name string.
+.IP delimiter
+A single character in quotes, which is used as the delimiting
+character that separates the Realm and User sections of the string.
+.IP ignore_default
+This is set to either 'yes' or 'no'. If set to 'yes', this will
+prevent the module instance from matching a realm against the DEFAULT
+entry. This may be useful if you have multiple realm module instances.
+The default is 'no'.
+.IP ignore_null
+This is set to either 'yes' or 'no'. If set to 'yes', this will
+prevent the module instance from matching a realm against the NULL
+entry. This may be useful if you have multiple realm module instances.
+The default is 'no'.
+.PP
+This module parses the realm from the User-Name attribute according
+to the instance configuration, and then performs a lookup to find a
+matching realm in the '/etc/raddb/proxy.conf' file. Depending on the
+configuration of the Realm as matched in the file, the username may
+be rewritten in a 'stripped' format, or with the Realm portion
+removed. In either case, a Realm attribute is created and added to
+the packet on a match, which can be used by other modules.
+.SH CONFIGURATION
+.PP
+.DS
+modules {
+ ... stuff here ...
+.br
+.br
+ # useranme@realm syntax
+.br
+ realm suffix {
+.br
+ format = suffix
+.br
+ delimiter = "@"
+.br
+ }
+.br
+.br
+ # realm/username syntax
+.br
+ realm prefix {
+.br
+ format = prefix
+.br
+ delimiter = "/"
+.br
+ }
+.br
+.br
+ ... stuff here ...
+.br
+}
+.DE
+.PP
+.SH SECTIONS
+.BR authorization,
+.BR pre-accounting
+.PP
+.SH FILES
+.I /etc/raddb/radiusd.conf,
+.I /etc/raddb/proxy.conf
+.PP
+.SH "SEE ALSO"
+.BR radiusd (8),
+.BR radiusd.conf (5),
+.BR proxy.conf (5)
+.SH AUTHORS
+Chris Parker, cparker@segv.org
diff --git a/man/man5/rlm_sql.5 b/man/man5/rlm_sql.5
new file mode 100644
index 0000000..f0c42b5
--- /dev/null
+++ b/man/man5/rlm_sql.5
@@ -0,0 +1,152 @@
+.\" # DS - begin display
+.de DS
+.RS
+.nf
+.sp
+..
+.\" # DE - end display
+.de DE
+.fi
+.RE
+.sp
+..
+.TH rlm_sql 5 "5 February 2004" "" "FreeRADIUS Module"
+.SH NAME
+rlm_sql \- FreeRADIUS Module
+.SH DESCRIPTION
+The \fIrlm_sql\fP module provides an SQL interface to retrieve
+authorization information and store accounting information. It can be
+used in conjunction with, or in lieu of the files and detail modules.
+The SQL module has drivers to support the following SQL databases:
+.PP
+.DS
+.br
+ db2
+.br
+ iodbc
+.br
+ mysql
+.br
+ oracle
+.br
+ postgresql
+.br
+ sybase
+.br
+ unixodbc
+.br
+.DE
+.PP
+Due to the size of the configuration variables, the sql module is
+usually configured in a separate file, which is included in the main
+radiusd.conf via an include directive.
+.PP
+The main configuration items to be aware of are:
+.IP driver
+This variable specifies the driver to be loaded.
+.IP server
+.IP login
+.IP password
+These specify the servername, username, and password the module will
+use to connect to the database.
+.IP radius_db
+The name of the database where the radius tables are stored.
+.IP acct_table1
+.IP acct_table2
+These specify the tables names for accounting records. acct_table1
+specifies the table where Start records are stored. acct_table2
+specifies the table where Stop records are stored. In most cases,
+this should be the same table.
+.IP postauth_table
+The name of the table to store post-authentication data.
+.IP authcheck_table
+.IP authreply_table
+The tables where individual Check-Items and Reply-Items are stored.
+.IP groupcheck_table
+.IP groupreply_table
+The tables where group Check-Items and Reply-Items are stored.
+.IP usergroup_table
+The table where username to group relationships are stored.
+.IP deletestalesessions
+This option is set to 'yes' or 'no'. If you are doing
+Simultaneous-Use checking, and this is set to yes, stale sessions (
+defined as sessions for which a Stop record was not received ) will be
+cleared.
+.IP logfile
+This option is useful for debugging sql problems. If logfile is set
+then all sql queries for the containing section are written to the
+file specified. This is useful for debugging and bulk inserts.
+.IP num_sql_socks
+The number of sql connections to make to the database.
+.IP connect_failure_retry_delay
+The number of seconds to wait before attempting to reconnect to a
+failed database connection.
+.IP sql_user_name
+This is the definition of the SQL-User-Name attribute. This is set
+once, so that you can use %{SQL-User-Name} in the SQL queries, rather
+than the nested username substitution. This ensures that Username is
+parsed consistently for all SQL queries executed.
+.IP default_user_profile
+This is the default profile name that will be applied to all users if
+set. This is not set by default.
+.IP query_on_not_found
+This option is set to 'yes' or 'no'. If set to yes, then the default
+user profile is returned if no specific match was found for the user.
+.IP authorize_check_query
+.IP authorize_reply_query
+These queries are run during the authorization stage to extract the
+user authorization information from the ${authcheck_table} and
+${authreply_table}.
+.IP authorize_group_check_query
+.IP authorize_group_reply_query
+These queries are run during the authorization stage to extract the
+group authorization information from the ${groupcheck_table} and
+${groupreply_table}.
+.IP accounting_onoff_query
+The query to be run when receiving an Accounting On or Accounting Off
+packet.
+.IP accounting_update_query
+.IP accounting_update_query_alt
+The query to be run when receiving an Accounting Update packet. If the
+primary query fails, the alt query is run.
+.IP accounting_start_query
+.IP accounting_start_query_alt
+The query to be run when receiving an Accounting Start packet. If the
+primary query fails, the alt query is run.
+.IP accounting_stop_query
+.IP accounting_stop_query_alt
+The query to be run when receiving an Accounting Stop packet. If the
+primary query fails, the alt query is run.
+.IP simul_count_query
+The query to be run to return the number simultaneous sessions for the
+purposes of limiting Simultaneous Use.
+.IP simul_verify_query
+The query to return the detail information needed to confirm that all
+suspected connected sessions are valid, and are not stale sessions.
+.IP group_membership_query
+The query to run to check user group membership.
+.IP postauth_query
+The query to run during the post-authentication stage.
+.SH CONFIGURATION
+.PP
+Due to the size of the configuration for this module, it is not
+included in this manual page. Please review the supplied
+configuration files for example queries and configuration details.
+.SH SECTIONS
+.BR authorization,
+.BR accounting,
+.BR checksimul,
+.BR post-authentication
+.PP
+.SH FILES
+.I /etc/raddb/radiusd.conf,
+.I /etc/raddb/sql.conf,
+.I /etc/raddb/sql/<DB>/dialup.conf,
+.I /etc/raddb/sql/<DB>/schema.sql,
+.BR
+.PP
+.SH "SEE ALSO"
+.BR radiusd (8),
+.BR radiusd.conf (5),
+.SH AUTHORS
+Chris Parker, cparker@segv.org
diff --git a/man/man5/rlm_unbound.5 b/man/man5/rlm_unbound.5
new file mode 100644
index 0000000..34cff92
--- /dev/null
+++ b/man/man5/rlm_unbound.5
@@ -0,0 +1,82 @@
+.\" # DS - begin display
+.de DS
+.RS
+.nf
+.sp
+..
+.\" # DE - end display
+.de DE
+.fi
+.RE
+.sp
+..
+.TH rlm_unbound 5 "8 July 2013" "" "FreeRADIUS Module"
+.SH NAME
+rlm_unbound \- FreeRADIUS Module
+.SH DESCRIPTION
+Each instance of \fIrlm_unbound\fP provides an embedded DNS client
+for performing DNS lookups. Each instance may be configured separately
+to query different DNS horizons, change DNSSEC options, etc.
+.PP
+The module is primarily intended for use by other modules through
+internal APIs, and so, instances should be initialized earlier than
+those modules which use them. Each instance does also provide some
+xlat functionalities for general use and for troubleshooting.
+.PP
+Each instance of rlm_unbound may take the following parameters:
+.IP filename
+This file must exist and must point to a valid libunbound configuration file.
+The default is ${raddbdir}/mods-config/unbound/default.conf.
+.IP timeout
+While libunbound provides an asyncronous API for internal use, using any xlat
+is done syncronously from the perspective of unlang. This value limits the
+amount of time a request will wait for DNS to respond, after which the xlat
+will fail. The default is 3000 milliseconds. This setting is independent of
+any libunbound configuration values.
+.IP resolvconf
+Full path of a resolv.conf file to load resolver details from. If this is
+not set then libunbound will query root DNS servers.
+.IP hosts
+Full path of a hosts file to load. This provides a mechanism for local
+overrides to names which would otherwise not resolve or need different
+results to those which a DNS resolution would provide.
+.PP
+An instance named, for example, "dns" will provide the following xlat
+functionalities:
+.IP %{dns-a:<owner>}
+Performs an A lookup for the owner name, returning a stringified IPv4
+address. Only the first A record in the RRSET will be returned.
+.IP %{dns-aaaa:<owner>}
+Performs an AAAA lookup for the owner name, returning a stringified IPv6
+address. Only the first AAAA record in the RRSET will be returned.
+.IP %{dns-ptr:<owner>}
+Performs a PTR lookup for the owner.
+.PP
+.SH CAVEATS
+Logging from rlm_unbound can be problematic, especialy if more than one
+instantiation of the module is used. This is due to the need for additional
+features in the underlying libunbound which hopefully will be enhanced over
+time.
+.PP
+There is a potential for a FreeRADIUS server using rlm_unbound to either
+fail to terminate cleanly (leaving zombie processes, failing to clean up
+other modules, and hanging after a SIGTERM until a SIGKILL is sent) or
+to fail valgrind checks during termination when run with -m. Likewise this
+problem will rely on upstream enhancements before it can be fixed, and the
+exact behavior may change in interim releases until then.
+.PP
+The logging behavior of rlm_unbound may vary depending on whether
+FreeRADIUS is compiled with support for threads.
+.PP
+.SH FILES
+.I /etc/raddb/modules-available/rlm_unbound
+.I /etc/raddb/modules-config/unbound/
+.PP
+.SH "SEE ALSO"
+.BR radiusd (8),
+.BR radiusd.conf (5)
+.BR libunbound (3)
+.BR unbound.conf (5)
+.SH AUTHOR
+Brian S. Julin, bjulin@clarku.edu
+
diff --git a/man/man5/rlm_unix.5 b/man/man5/rlm_unix.5
new file mode 100644
index 0000000..38668e0
--- /dev/null
+++ b/man/man5/rlm_unix.5
@@ -0,0 +1,66 @@
+.\" # DS - begin display
+.de DS
+.RS
+.nf
+.sp
+..
+.\" # DE - end display
+.de DE
+.fi
+.RE
+.sp
+..
+.TH rlm_unix 5 "17 February 2005" "" "FreeRADIUS Module"
+.SH NAME
+rlm_unix \- FreeRADIUS Module
+.SH DESCRIPTION
+The \fIrlm_unix\fP module reads crypt(3) passwords from the system
+password file, and allows the server to use them for authentication.
+The module also provides FreeRADIUS an interface into a radwtmp file
+(used by "radlast") when added to the accounting section.
+.PP
+The \fIrlm_unix\fP module should be listed in the
+"authenticate" section. Please see the default \fIradiusd.conf\fP
+shipped with the server for an example of the correct usage of this
+module.
+.PP
+As of FreeRADIUS 1.1.0, the module no longer reads, or caches
+/etc/passwd, /etc/shadow, or /etc/group. If you wish to cache those
+files, see \fIrlm_passwd\fP. Most, if not all, configurations should
+not need those files to be cached.
+.PP
+The main configuration items to be aware of are:
+.IP radwtmp
+The path to the system wtmp file to be used for keeping the database
+of online users as read by the 'radlast' program.
+.SH CONFIGURATION
+.PP
+.DS
+modules {
+ ...
+.br
+ unix {
+.br
+ radwtmp = ${logdir}/radwtmp
+.br
+ }
+.br
+ ...
+.br
+}
+.DE
+.PP
+.SH SECTIONS
+.BR authentication,
+.BR accounting
+.PP
+.SH FILES
+.I /etc/raddb/radiusd.conf,
+.PP
+.SH "SEE ALSO"
+.BR radiusd (8),
+.BR radiusd.conf (5),
+.BR rlm_passwd (5),
+.BR radlast (1)
+.SH AUTHORS
+Chris Parker, cparker@segv.org
diff --git a/man/man5/unlang.5 b/man/man5/unlang.5
new file mode 100644
index 0000000..63f5570
--- /dev/null
+++ b/man/man5/unlang.5
@@ -0,0 +1,900 @@
+.\" # DS - begin display
+.de DS
+.RS
+.nf
+.sp
+..
+.\" # DE - end display
+.de DE
+.fi
+.RE
+.sp
+..
+.TH unlang 5 "16 February 2021" "" "FreeRADIUS Processing un-language"
+.SH NAME
+unlang \- FreeRADIUS Processing un\-language
+.SH DESCRIPTION
+FreeRADIUS supports a simple processing language in its configuration
+files. We call it an "un-language" because the intention is NOT to
+create yet another programming language. If you need something more
+complicated than what is described here, we suggest using the Perl or
+Python modules rlm_perl, or rlm_python.
+
+The goal of the language is to allow simple policies to be written
+with minimal effort. Those policies are then applied when a request
+is being processed. Requests are processed through virtual servers
+(including the default one), in the sections titled "authorize",
+"authenticate", "post-auth", "preacct", "accounting", "pre-proxy",
+"post-proxy", and "session".
+
+These policies cannot be used in any other part of the configuration
+files, such as module or client configuration.
+.SH KEYWORDS
+The keywords for the language are a combination of pre-defined
+keywords, and references to loadable module names. We document only
+the pre-defined keywords here.
+
+Subject to a few limitations described below, any keyword can appear
+in any context. The language consists of a series of entries, each
+one line. Each entry begins with a keyword. Entries are
+organized into lists. Processing of the language is line by line,
+from the start of the list to the end. Actions are executed
+per-keyword.
+.IP module-name[.section-name]
+A reference to the named module. When processing reaches this point,
+the pre-compiled module is called. The module may succeed or fail,
+and will return a status to "unlang" if so. This status can be tested
+in a condition. See the "Simple Conditions" text in the CONDITIONS
+section, and MODULE RETURN CODES, below.
+If a section-name is provided, it will cause the module to execute
+as if it were listed in the named section.
+
+.DS
+ chap # call the CHAP module
+.br
+ sql # call the SQL module
+.br
+ ...
+.DE
+.IP if
+.br
+Checks for a particular condition. If true, the block after the
+condition is processed. Otherwise, the block is ignored. See
+CONDITIONS, below, for documentation on the format of the conditions.
+
+.DS
+ if (condition) {
+.br
+ ...
+.br
+ }
+.DE
+.IP else
+.br
+Define a block to be executed only if the previous "if" condition
+returned false.
+
+.DS
+ else {
+.br
+ ...
+.br
+ }
+.DE
+.IP elsif
+.br
+Define a block to be executed only if the previous "if" condition
+returned false, and if the specified condition evaluates to true.
+
+.DS
+ elsif (condition) {
+.br
+ ...
+.br
+ }
+.DE
+.IP foreach
+.br
+Loops over values of an attribute, running the block for each value.
+The return value of the block is the return value of the last
+statement executed. The loop can be exited early by using the "break"
+keyword. Unlike other languages, "break" here means "exit the loop at
+the next iteration", not "exit the loop now". The result is that any
+statements after the "break" keyword will still be executed. We
+recommend using "break" only when it is the last statement in a
+"foreach" block.
+
+Inside of the "foreach" block, the attribute which is being looped
+over can be referenced as "Foreach-Variable-#". Where "#" is the
+depth of the loop, starting at "0". e.g. "Foreach-Variable-0". The
+loops can be nested up to eight (8) deep, though this is not
+recommended.
+
+.DS
+ foreach &Attribute-Reference {
+.br
+ ...
+.br
+ }
+.DE
+.IP switch
+.br
+A "switch" statement takes one argument, and contains a series of
+"case" statements. When a "switch" statement is encountered, the
+argument from the "switch" is evaluated in turn against the argument
+from each "case" statement. The first "case" statement which matches
+is executed. All other "case" statements are ignored. A default
+"case" statement can be defined, by omitting its argument.
+
+If the argument is a double quoted string (e.g. "%{exec:1 + 2}", it is
+expanded as described in the DATA TYPES section, below. The match is
+then performed on the string returned from the expansion. If the
+argument is an attribute reference (e.g. &User-Name), then the match
+is performed on the value of that attribute. Otherwise, the argument
+is taken to be a literal string, and matching is done via simple
+comparison.
+
+No statement other than "case" can appear in a "switch" block.
+
+.DS
+ switch <argument> {
+.br
+ ...
+.br
+ }
+.DE
+.IP case
+.br
+Provides a place-holder which matches the argument of a parent
+"switch" statement.
+
+A "case" statement cannot appear outside of a "switch" block.
+
+If the argument is a double quoted string (e.g. "%{exec:1 + 2}", it is
+expanded as described in the DATA TYPES section, below. The match is
+then performed on the string returned from the expansion. If the
+argument is an attribute reference (e.g. &User-Name), then the match
+is performed on the value of that attribute. Otherwise, the argument
+is taken to be a literal string, and matching is done via simple
+comparison.
+
+.DS
+ case <argument> {
+.br
+ ...
+.br
+ }
+.DE
+A default entry can be defined by omitting the argument, as given
+below. This entry will be used if no other "case" entry matches.
+Only one default entry can exist in a "switch" section.
+
+.DS
+ case {
+.br
+ ...
+.br
+ }
+.DE
+.IP update
+.br
+Update a particular attribute list, based on the attributes given in
+the current block.
+
+.DS
+ update <list> {
+.br
+ &Attribute-Reference = value
+.br
+ ...
+.br
+ }
+.DE
+The <list> can be one of "request", "reply", "proxy-request",
+"proxy-reply", "coa", "disconnect", "session-state", or "control". As
+of Version 3, the <list> can be omitted, in which case "request" is
+assumed.
+
+The "control" list is the list of attributes maintained internally by
+the server that controls how the server processes the request. Any
+attribute that does not go in a packet on the network will generally
+be placed in the "control" list.
+
+For EAP methods with tunneled authentication sessions (i.e. PEAP and
+EAP-TTLS), the inner tunnel session can also reference
+"outer.request", "outer.reply", and "outer.control". Those references
+allow you to address the relevant list in the outer tunnel session.
+
+The "coa" and "disconnect" sections can only be used when the server
+receives an Access-Request or Accounting-Request. Use "request" and
+"reply" instead of "coa" when the server receives a CoA-Request or
+Disconnect-Request packet.
+
+Adding one or more attributes to either of the "coa" or "disconnect"
+list causes server to originate a CoA-Request or Disconnect-Request
+packet. That packet is sent when the current Access-Request or
+Accounting-Request has been finished, and a reply sent to the NAS.
+See raddb/sites-available/originate-coa for additional information.
+
+The "session-state" list is primarily used for EAP. Attributes put
+into the "session-state" list are saved for the next packet in the
+session. They are automatically retrieved when the next packet is
+received.
+
+The only contents permitted in an "update" section are attributes and
+values. The contents of the "update" section are described in the
+ATTRIBUTE REFERENCE and ATTRIBUTE ASSIGNMENT sections below.
+.IP redundant
+This section contains a simple list of modules. The first module is
+called when the section is being processed. If the first module
+succeeds in its operation, then the server stops processing the
+section, and returns to the parent section.
+
+If, however, the module fails, then the next module in the list is
+tried, as described above. The processing continues until one module
+succeeds, or until the list has been exhausted.
+
+Redundant sections can contain only a list of modules, and cannot
+contain keywords that perform conditional operations (if, else, etc)
+or update an attribute list.
+
+.DS
+ redundant {
+.br
+ sql1 # try this
+.br
+ sql2 # try this only if sql1 fails.
+.br
+ ...
+.br
+ }
+.DE
+.IP load-balance
+This section contains a simple list of modules. When the section is
+entered, one module is chosen at random to process the request. All
+of the modules in the list should be the same type (e.g. ldap or sql).
+All of the modules in the list should behave identically, otherwise
+the load-balance section will return different results for the same
+request.
+
+Load-balance sections can contain only a list of modules, and cannot
+contain keywords that perform conditional operations (if, else, etc)
+or update an attribute list.
+
+.DS
+ load-balance {
+.br
+ ldap1 # 50% of requests go here
+.br
+ ldap2 # 50% of requests go here
+.br
+ }
+.DE
+In general, we recommend using "redundant-load-balance" instead of
+"load-balance".
+.IP redundant-load-balance
+This section contains a simple list of modules. When the section is
+entered, one module is chosen at random to process the request. If
+that module succeeds, then the server stops processing the section.
+If, however, the module fails, then one of the remaining modules is
+chosen at random to process the request. This process repeats until
+one module succeeds, or until the list has been exhausted.
+
+All of the modules in the list should be the same type (e.g. ldap or
+sql). All of the modules in the list should behave identically,
+otherwise the load-balance section will return different results for
+the same request.
+
+Load-balance sections can contain only a list of modules, and cannot
+contain keywords that perform conditional operations (if, else, etc)
+or update an attribute list. Please see raddb/radiusd.conf
+"instantiate" section for more configuration examples.
+
+.DS
+ redundant-load-balance {
+.br
+ ldap1 # 50%, unless ldap2 is down, then 100%
+.br
+ ldap2 # 50%, unless ldap1 is down, then 100%
+.br
+ }
+.DE
+.IP return
+.br
+Returns from the current top-level section, e.g. "authorize" or
+"authenticate". This keyword is mainly used to avoid layers of nested
+"if" and "else" statements.
+
+.DS
+ authorize {
+.br
+ if (...) {
+.br
+ ...
+.br
+ return
+.br
+ }
+.br
+ ... # this is never reached when the "if"
+.br
+ ... # statement is executed
+.br
+ }
+.DE
+.SH ATTRIBUTE REFERENCES
+
+Attributes may be referenced via the following syntax:
+.DS
+ &Attribute-Name
+ &Attribute-Name:TAG
+ &Attribute-Name[NUM]
+ &<list>:Attribute-Name
+ &<list>:Attribute-Name:TAG[NUM]
+.DE
+Where <list> is one of "request", "reply", "control", "proxy-request",
+"proxy-reply", or "outer.request", "outer.reply", "outer.control",
+"outer.proxy-request", or "outer.proxy-reply". just as with the
+"update" section, above. The "<list>:" prefix is optional, and if
+omitted, is assumed to refer to the "request" list.
+
+The TAG portion is a decimal integer between 1 and 31. Please see RFC
+2868 for more information about tags. Tags can only be used for
+attributes which are marked in the dictionary as "has_tag".
+
+The NUM portion is used when there are multiple attributes of the same
+name in a list. The "Attribute-Name" reference will return the first
+attribute. Using an array offset allows the policy to refer to the
+second and subsequent attributes.
+
+If '*' is used in the NUM portion, it evaluates to all instances of
+the attribute in the request.
+
+If 'n' is used in the NUM portion, it evaluates to the last instance
+of the attribute in the request.
+
+When an attribute name is encountered, the given list is examined for
+an attribute of the given name. Some examples are:
+.DS
+ User-Name
+.br
+ request:User-Name # same as above
+.br
+ reply:User-Name
+.br
+ Tunnel-Password:1
+.br
+ Cisco-AVPAir[2]
+.br
+ outer.request:User-Name # from inside of a TTLS/PEAP tunnel
+.DE
+Note that unlike C, there is no way to define new attributes at
+run-time. They MUST be declared in a dictionary file, and loaded when
+the server starts.
+
+All attributes are defined in the dictionaries that accompany the
+server. These definitions define only the name and type, and do not
+define the value of the attribute. When the server receives a packet,
+it uses the packet contents to look up entries in the dictionary, and
+instantiates attributes with a name taken from the dictionaries, and a
+value taken from the packet contents. This process means that if an
+attribute does not exist, it is usually because it was not contained
+in a packet that the server received.
+
+Once the attribute is instantiated, it is added to a list. It can
+then be referenced, updated, replaced, etc.
+
+.SH CONDITIONS
+The conditions are similar to C conditions in syntax, though
+quoted strings are supported, as with the Unix shell.
+.IP Simple
+conditions
+.br
+.DS
+ (foo)
+.DE
+Evaluates to true if 'foo' is a non-empty string (single quotes, double
+quotes, or back-quoted). Also evaluates to true if 'foo' is a
+non-zero number. Note that the language is poorly typed, so the
+string "0000" can be interpreted as a numerical zero. This issue can
+be avoided by comparing strings to an empty string, rather than by
+evaluating the string by itself.
+
+If the word 'foo' is not a quoted string, then it can be taken as a
+reference to a named attribute. See "Referencing attribute lists",
+below, for examples of attribute references. The condition evaluates
+to true if the named attribute exists.
+
+Otherwise, if the word 'foo' is not a quoted string, and is not an
+attribute reference, then it is interpreted as a reference to a module
+return code. The condition evaluates to true if the most recent
+module return code matches the name given here. Valid module return
+codes are given in MODULE RETURN CODES, below.
+.IP Negation
+.DS
+ (!foo)
+.DE
+Evaluates to true if 'foo' evaluates to false, and vice-versa.
+.PP
+Short-circuit operators
+.RS
+.br
+.DS
+ (foo || bar)
+.br
+ (foo && bar)
+.DE
+"&&" and "||" are short-circuit operators. "&&" evaluates the first
+condition, and evaluates the second condition if and only if the
+result of the first condition is true. "||" is similar, but executes
+the second command if and only if the result of the first condition is
+false.
+.RE
+.IP Comparisons
+.DS
+ (foo == bar)
+.DE
+Compares 'foo' to 'bar', and evaluates to true if the comparison holds
+true. Valid comparison operators are "==", "!=", "<", "<=", ">",
+">=", "=~", and "!~", all with their usual meanings. The operators
+":=", "^=" and "=" are assignment operators, and are not allowed for
+comparisons.
+
+The operators "<", "<=", ">", and ">=" are also allowed for checking
+that an IP address is contained within a network. For example:
+.DS
+ if (<ipaddr>192.0.2.1 < 192.0.2.0/24) {
+.DE
+This comparison succeeds, because the address 192.0.2.1 is contained
+within the network 192.0.2.0/24.
+.RE
+.IP "Attribute Comparisons"
+When doing attribute comparisons, the data type of the attribute is
+used to determine the data type of the right-hand side argument.
+.DS
+ (&User-Name == "foo")
+.DE
+Compares the value of the User-Name attribute to the string 'foo', and
+evaluates to true if the comparison holds true.
+
+Similarly,
+.DS
+ (&Framed-IP-Address == 192.0.2.1)
+.DE
+Compares the value of the Framed-IP-Address attribute to the IP
+address 192.0.2.1. This IP address does not need to be quoted.
+.RE
+.IP "Inter-Attribute Comparisons"
+.DS
+ (&User-Name == &Filter-Id)
+.DE
+Compares the value of the User-Name attribute to the contents of the
+Filter-Id attribute, and evaluates to true if the comparison holds
+true. Unlike the previous example, this comparison is done in a
+type-safe way. For example, comparing the IP addresses 1.2.3.4 and
+127.0.0.1 as strings will return different results than comparing them
+as IP addresses.
+
+The "&" character in the condition means that the comparison "refers"
+to the Filter-Id attribute. If left off, it means that the User-Name
+attribute is compared to the literal string "Filter-Id".
+
+Where the left-hand side is an attribute, the "&" can be omitted.
+However, it is allowed for backwards compatibility. e.g. The comparison
+"(&User-Name == &Filter-Id)" is equivalent to the example above.
+
+We recommend using attribute references instead of printing
+attributes to a string, e.g. (User-Name == "%{Filter-Id}").
+Attribute references will be faster and more efficient.
+
+The conditions will check only the first occurrence of an attribute.
+If there is more than one instance of an attribute, the following
+syntax should be used:
+
+.DS
+ (&Attribute-Name[*] == "foo")
+.DE
+Using the "[*]" syntax means that it checks all of the instances of
+the named attribute. If one attribute matches, the condition
+succeeds. If none match, the condition fails.
+
+.RE
+.IP Casts
+.DS
+ (<type>foo == bar)
+.DE
+The left-hand-side of a condition can be "cast" to a specific data
+type. The data type must be one which is valid for the dictionaries.
+e.g. "integer", "ipaddr", etc.
+
+The comparison is performed in a type-safe way, as with
+"Inter-Attribute Comparisons", above. Both sides of the condition are
+parsed into temporary attributes, and the attributes compared via
+type-specific methods. The temporary attributes have no other effect,
+and are not saved anywhere.
+
+Casting allows conditions to perform type-specific comparisons. In
+previous versions of the server, the data would have to be manually
+placed into an intermediate attribute (or attributes), and then the
+attribute (or attributes) compared. The use of a cast allows for
+simpler policies.
+
+Casts are allowed only on the left-hand side argument of a condition.
+.PP
+Conditions may be nested to any depth, subject only to line length
+limitations (8192 bytes).
+.SH DATA TYPES
+There are only a few data types supported in the language. Reference
+to attributes, numbers, and strings. Any data type can appear in
+stand-alone condition, in which case they are evaluated as described
+in "Simple conditions", above. They can also appear (with some
+exceptions noted below) on the left-hand or on the right-hand side of
+a comparison.
+.IP numbers
+Numbers are composed of decimal digits. Floating point, hex, and
+octal numbers are not supported. The maximum value for a number is
+machine-dependent, but is usually 32-bits, including one bit for a
+sign value.
+.PP
+word
+.RS
+Text that is not enclosed in quotes is interpreted differently
+depending on where it occurs in a condition. On the left hand side of
+a condition, it is interpreted as a reference to an attribute. On the
+right hand side, it is interpreted as a simple string, in the same
+manner as a single-quoted string.
+
+Using attribute references permits limited type-specific comparisons,
+as seen in the examples below.
+
+.DS
+ if (&User-Name == "bob") {
+.br
+ ...
+.br
+ if (&Framed-IP-Address > 127.0.0.1) {
+.br
+ ...
+.br
+ if (&Service-Type == Login-User) {
+.DE
+.RE
+.IP """strings"""
+.RS
+Double-quoted strings are expanded by inserting the value of any
+attributes (see ATTRIBUTE REFERENCES, below) before being evaluated. If
+the result is a number it is evaluated in a numerical context.
+
+String length is limited by line-length, usually about 8000
+characters. A double quote character can be used in a string via
+the normal back-slash escaping method. ("like \\"this\\" !")
+.RE
+.IP 'strings'
+Single-quoted strings are evaluated as-is. Their values are not
+expanded as with double-quoted strings above, and they are not
+interpreted as attribute references.
+.IP `strings`
+Back-quoted strings are evaluated by expanding the contents of the
+string, as described above for double-quoted strings. The resulting
+command given inside of the string in a sub-shell, and taking the
+output as a string. This behavior is much the same as that of Unix
+shells.
+
+Note that for security reasons, the input string is split into command
+and arguments before string expansion is done.
+
+For performance reasons, we suggest that the use of back-quoted
+strings be kept to a minimum. Executing external programs is
+relatively expensive, and executing a large number of programs for
+every request can quickly use all of the CPU time in a server. If you
+believe that you need to execute many programs, we suggest finding
+alternative ways to achieve the same result. In some cases, using a
+real language may be sufficient.
+
+.IP /regex/im
+These strings are valid only on the right-hand side of a comparison,
+and then only when the comparison operator is "=~" or "!~". They are
+regular expressions, as implemented by the local regular expression
+library on the system. This is usually Posix regular expressions.
+
+The trailing 'i' is optional, and indicates that the regular
+expression match should be done in a case-insensitive fashion.
+
+The trailing 'm' is also optional, and indicates that carrot '^'
+and dollar '$' anchors should match on new lines as well as at the
+start and end of the subject string.
+
+If the comparison operator is "=~", then parentheses in the regular
+expression will define variables containing the matching text, as
+described below in the ATTRIBUTE REFERENCES section.
+.SH EXPANSIONS
+Attributes are expanded using the ATTRIBUTE REFERENCE syntax
+described above, and surrounding the reference with "%{...}"
+
+.DS
+ %{Attribute-Reference}
+.DE
+
+The result will be a string which contains the value of the attribute
+which was referenced, as a printable string. If the attribute does
+not exist, the result will be an empty string.
+.PP
+Results of regular expression matches
+.RS
+If a regular expression match has previously been performed, then the
+special variable %{0} will contain a copy of the matched portion of
+the input string. The variables %{1} through %{32} will contain the
+substring matches, starting from the left-most capture group, onwards.
+If there are more than 32 capture groups, the additional results will
+not be accessible.
+If the server is built with libpcre, the results of named capture groups
+are available using the "%{regex:capture group}" expansion. They will
+also be accessible using the variables described above.
+Every time a regular expression is evaluated, whether it matches or not,
+the capture group values will be cleared.
+.RE
+.PP
+Obtaining results from databases
+.RS
+It is useful to query a database for some information, and to use the
+result in a condition. The following syntax will call a module, pass
+it the given string, and replace the string expansion with the
+resulting string returned from the module.
+
+.DS
+ %{module: string ...}
+.DE
+
+The syntax of the string is module-specific. Please read the module
+documentation for additional details.
+.RE
+.PP
+Conditional Syntax
+.RS
+Conditional syntax similar to that used in Unix shells may also be
+used.
+.IP %{%{Foo}:-bar}
+If %{Foo} has a value, returns that value.
+.br
+Otherwise, returns literal string "bar".
+.IP %{%{Foo}:-%{Bar}}
+If %{Foo} has a value, returns that value.
+.br
+Otherwise, returns the expansion of %{Bar}.
+
+These conditional expansions can be nested to almost any depth, such
+as with %{%{One}:-%{%{Two}:-%{Three}}}
+.RE
+.PP
+String lengths and arrays
+.RS
+Similar to a Unix shell, there are ways to reference string lengths,
+and the second or more instance of an attribute in a list. If you
+need more than this functionality, we suggest using a real language.
+.IP %{strlen:string}
+The number of characters in "string". If "string" does not exist,
+then the length also does not exist, instead of being zero.
+
+The "string" is expanded before the length is taken.
+
+.IP %{integer:Attribute-Name}
+The integer value of the Attribute-Name, instead of the enumerated
+name.
+
+e.g. If a request contains "Service-Type = Login-User", the expansion
+of %{integer:Service-Type} will yield "1".
+
+.IP %{hex:Attribute-Name}
+The hex value of the Attribute-Name, as a series of hex digits.
+
+e.g. If a request contains "Framed-IP-Address = 127.0.0.1", the expansion
+of %{hex:Framed-IP-Address} will yield "0x7f000001".
+
+.IP %{Attribute-Name[#]}
+The number of instances of Attribute-Name.
+
+e.g. If a request contains "User-Name = bob", the expansion
+of %{User-Name[#]} will yield "1".
+
+.IP %{Attribute-Name[*]}
+All values of Attribute-Name, concatenated together with ',' as the
+separator.
+
+.IP %{List-Name:[#]}
+The number of attributes in the named list.
+
+.IP %{List-Name:[*]}
+All values of attributes in the named-list, concatenated together with ','
+as the separator. Use the %{pairs:} xlat to get a list of attributes and
+values.
+
+e.g. If a response contains "Reply-Message = 'Hello', Reply-Message = 'bob'
+the expansion of "%{reply:Reply-Message[*]} will yield "Hello\\nbob"
+
+.SH ATTRIBUTE ASSIGNMENTS
+The attribute lists described above may be edited by listing one or
+more attributes in an "update" section. Once the attributes have been
+defined, they may be referenced as described above in the ATTRIBUTE
+REFERENCES section.
+
+The following syntax defines attributes in an "update" section. Each
+attribute and value has to be all on one line in the configuration
+file. There is no need for commas or semi-colons after the value.
+
+.DS
+ Attribute-Reference = value
+.DE
+.PP
+Attribute Reference
+.RS
+The Attribute-Reference must be a reference (see above), using a name
+previously defined in a dictionary. If an undefined name is used, the
+server will return an error, and will not start.
+
+.RE
+.IP Operators
+The operator used to assign the value of the attribute may be one of
+the following, with the given meaning.
+.RS
+.IP =
+Add the attribute to the list, if and only if an attribute of the same
+name is not already present in that list.
+.IP :=
+Add the attribute to the list. If any attribute of the same name is
+already present in that list, its value is replaced with the value of
+the current attribute.
+.IP +=
+Add the attribute to the tail of the list, even if attributes of the
+same name are already present in the list. When the right hand side
+of the expression resolves to multiple values, it means add all values
+to the tail of the list.
+.IP ^=
+Add the attribute to the head of the list, even if attributes of the
+same name are already present in the list. When the right hand side
+of the expression resolves to multiple values, it means prepend all
+values to the head of the list.
+.RE
+.PP
+Enforcement and Filtering Operators
+.RS
+The following operators may also be used in addition to the ones
+listed above. Their function is to perform enforcement or filtering
+on attributes in a list.
+.IP -=
+Remove all matching attributes from the list. Both the attribute name
+and value have to match in order for the attribute to be removed from
+the list.
+.IP ==
+Keep all matching attributes. Both the attribute name and value have
+to match in order for the attribute to remain in the list.
+
+Note that this operator is very different than the '=' operator listed
+above!
+.IP !=
+Keep all attributes with matching name, and value not equal to the
+given one.
+.IP <
+Keep all attributes having values less than the value
+given here. Any larger value is replaced by the value given here. If
+no attribute exists, it is added with the value given here, as with
+"+=".
+.IP <=
+Keep all attributes having values less than, or equal to, the value
+given here. Any larger value is replaced by the value given here. If
+no attribute exists, it is added with the value given here, as with
+"+=".
+.IP >
+Keep all attributes having values greater than the value
+given here. Any smaller value is replaced by the value given here. If
+no attribute exists, it is added with the value given here, as with
+"+=".
+.IP >=
+Keep all attributes having values greater than, or equal to, the value
+given here. Any smaller value is replaced by the value given here. If
+no attribute exists, it is added with the value given here, as with
+"+=".
+.IP !*
+Delete all occurrences of the named attribute, no matter what the
+value.
+.IP =~
+Keep all attributes having values which match the given regular
+expression. If no attribute matches, nothing else is done.
+.IP !~
+Keep all attributes having values which fail to match the given
+regular expression. If no attribute matches, nothing else is done.
+.RE
+.IP Values
+.br
+The value can be an attribute reference, or an attribute-specific
+string.
+
+When the value is an attribute reference, it must take the form of
+"&Attribute-Name". The leading "&" signifies that the value is a
+reference. The "Attribute-Name" is an attribute name, such as
+"User-Name" or "request:User-Name". When an attribute reference is
+used, both attributes must have the same data type. For example,
+"User-Name := &NAS-Port" is invalid, because "User-Name" is a string,
+and "NAS-Port" is an integer.
+
+We recommend using the form "Attribute-1 = &Attribute-2" for updates,
+instead of "Attribute-1 = "%{Attribute-2}". The first version will
+copy the attribute data, no matter what its form. The second
+version will print the Attribute-2 to a string, and then parse it to
+create the value for Attribute-1. This second version is slower
+and more fragile than the first one.
+
+When the value is an attribute-specific string, it can be a string,
+integer, IP address, etc. The value may be expanded as described
+above in the DATA TYPES section, above. For example, specifying
+"Framed-IP-Address = 127.0.0.1" will cause the "Framed-IP-Address"
+attribute to be set to the IP address "127.0.0.1". However, using
+"Framed-IP-Address := \"%{echo: 127.0.0.1}\"" will cause the "echo"
+module to be run with a string "127.0.0.1". The output of the "echo"
+module will then be parsed as an IP address, and placed into the
+Framed-IP-Address attribute.
+
+This flexibility means that you can assign an IP address by specifying
+it directly, or by having the address returned from a database query,
+or by having the address returned as the output of a program that is
+executed.
+
+When string values are finally assigned to an attribute, they can have a
+maximum length of 253 characters. This limit is due in part to both
+protocol and internal server requirements. That is, the strings in
+the language can be nearly 8k in length, say for a long SQL query.
+However, the output of that SQL query should be no more than 253
+characters in length.
+.SH OTHER KEYWORDS
+Other keywords in the language are taken from the names of modules
+loaded by the server. These keywords are dependent on both the
+modules, and the local configuration.
+
+Some use keywords that are defined in the default configuration file
+are:
+.IP fail
+Cause the request to be treated as if a database failure had occurred.
+.IP noop
+Do nothing. This also serves as an instruction to the configurable
+failover tracking that nothing was done in the current section.
+.IP ok
+Instructs the server that the request was processed properly. This
+keyword can be used to over-ride earlier failures, if the local
+administrator determines that the failures are not catastrophic.
+.IP reject
+Causes the request to be immediately rejected
+.SH MODULE RETURN CODES
+When a module is called, it returns one of the following codes to
+"unlang", with the following meaning.
+
+.DS
+ notfound information was not found
+.br
+ noop the module did nothing
+.br
+ ok the module succeeded
+.br
+ updated the module updated the request
+.br
+ fail the module failed
+.br
+ reject the module rejected the request
+.br
+ userlock the user was locked out
+.br
+ invalid the configuration was invalid
+.br
+ handled the module has handled the request itself
+.DE
+
+These return codes can be tested for in a condition, as described
+above in the CONDITIONS section.
+
+See also the file doc/configurable_failover for additional methods of
+trapping and modifying module return codes.
+.SH FILES
+/etc/raddb/radiusd.conf
+.SH "SEE ALSO"
+.BR radiusd.conf (5),
+.BR dictionary (5)
+.SH AUTHOR
+Alan DeKok <aland@deployingradius.com>
diff --git a/man/man5/users.5 b/man/man5/users.5
new file mode 100644
index 0000000..4586b96
--- /dev/null
+++ b/man/man5/users.5
@@ -0,0 +1,228 @@
+.\" # DS - begin display
+.de DS
+.RS
+.nf
+.sp
+..
+.\" # DE - end display
+.de DE
+.fi
+.RE
+.sp
+..
+.TH USERS 5 "04 Jan 2004" "" "FreeRADIUS user authorization file"
+.SH NAME
+users \- user authorization file for the FreeRADIUS server
+.SH DESCRIPTION
+The \fBusers\fP files reside in the files module configuration directory,
+by default \fB/etc/raddb/mods-config/files/\fP. It contains a series
+of configuration directives which are used by the \fIfiles\fP
+module to decide how to authorize and authenticate each user request.
+
+Every line starting with a hash sign
+.RB (' # ')
+is treated as comment and ignored.
+.PP
+Each entry of the file begins with a username, followed by a (possibly
+empty) list of check items, all on one line. The next line begins
+with a tab, and a (possibly empty) list of reply items. Each item in
+the check or reply item list is an attribute of the form \fBname =
+value\fP. Multiple items may be placed on one line, in which case
+they must be separated by commas. The reply items may be specified
+over multiple lines, in which case each line must end with a comma,
+and the last line of the reply items must not end with a comma.
+
+The check items are a list of attributes used to match the incoming
+request. If the username matches, AND all of the check items match
+the incoming request, then the reply items are added to the list of
+attributes which will be used in the reply to that request. This
+process is repeated for all of the entries in the users file.
+
+If the incoming request matches NO entry, then the request is
+rejected.
+
+.SH CAVEATS
+The special keyword \fBDEFAULT\fP matches any usernames.
+
+The entries are processed in order, from the top of the \fBusers\fP file,
+on down. If an entry contains the special item \fBFall-Through =
+No\fP as a reply attribute, then the processing of the file stops, and
+no more entries are matched. Any reply item list without any
+\fBFall-Through\fP attribute is treated as though it included a
+\fBFall-Through = No\fP attribute.
+
+If an entry contains the special item \fBFall-Through = Yes\fP as a
+reply attribute, then the processing proceeds to the next entry in
+order.
+
+Care should be taken when using \fBFall-Through\fP. The server should
+be tested in debugging mode with a number of test requests, in order
+to verify that the configured entries behave as expected.
+
+The special attribute \fBAuth-Type\fP is used to identify the
+authentication type to be used for that user. See the
+\fBdictionary\fP file for a list of permitted values for the
+\fBAuth-Type\fP attribute.
+
+Once the \fBusers\fP file has been processed, the request is authenticated,
+using the method given by \fBAuth-Type\fP.
+
+.SH OPERATORS
+Additional operators other than \fB=\fP may be used for the attributes in
+either the check item, or reply item list. The following is a list of
+operators, and their meaning.
+
+.TP 0.5i
+.B "Attribute = Value"
+Not allowed as a check item for RADIUS protocol attributes. It is
+allowed for server configuration attributes (Auth-Type, etc), and sets
+the value of on attribute, only if there is no other item of the
+same attribute.
+.br
+As a reply item, it means "add the item
+to the reply list, but only if there is no other item of the same
+attribute."
+
+.TP 0.5i
+.B "Attribute := Value"
+Always matches as a check item, and replaces in the configuration
+items any attribute of the same name. If no attribute of that name
+appears in the request, then this attribute is added.
+.br
+As a reply item, it has an identical meaning, but for the reply items,
+instead of the request items.
+
+.TP 0.5i
+.B "Attribute == Value"
+As a check item, it matches if the named attribute is present in the
+request, AND has the given value.
+.br
+Not allowed as a reply item.
+
+.TP 0.5i
+.B "Attribute += Value"
+Always matches as a check item, and adds the current attribute with
+value to the tail of the list of configuration items.
+.br
+As a reply item, it has an identical meaning, but the attribute is
+added to the tail of the reply items list.
+
+.TP 0.5i
+.B "Attribute ^= Value"
+Always matches as a check item, and adds the current attribute with
+value to the head of the list of configuration items.
+.br
+As a reply item, it has an identical meaning, but the attribute is
+added to the head of the reply items list.
+
+.TP 0.5i
+.B "Attribute != Value"
+As a check item, matches if the given attribute is in the request, AND
+does not have the given value.
+.br
+Not allowed as a reply item.
+
+.TP 0.5i
+.B "Attribute > Value"
+As a check item, it matches if the request contains an attribute with
+a value greater than the one given.
+.br
+Not allowed as a reply item.
+
+.TP 0.5i
+.B "Attribute >= Value"
+As a check item, it matches if the request contains an attribute with
+a value greater than, or equal to the one given.
+.br
+Not allowed as a reply item.
+
+.TP 0.5i
+.B "Attribute < Value"
+As a check item, it matches if the request contains an attribute with
+a value less than the one given.
+.br
+Not allowed as a reply item.
+
+.TP 0.5i
+.B "Attribute <= Value"
+As a check item, it matches if the request contains an attribute with
+a value less than, or equal to the one given.
+.br
+Not allowed as a reply item.
+
+.TP 0.5i
+.B "Attribute =* Value"
+As a check item, it matches if the request contains the named
+attribute, no matter what the value is.
+.br
+Not allowed as a reply item.
+
+.TP 0.5i
+.B "Attribute !* Value"
+As a check item, it matches if the request does not contain the named
+attribute, no matter what the value is.
+.br
+Not allowed as a reply item.
+
+.SH EXAMPLES
+
+.DS
+bob Cleartext-Password := "hello"
+
+.DE
+.RS
+Requests containing the User-Name attribute, with value "bob", will be
+authenticated using the "known good" password "hello". There are no
+reply items, so the reply will be empty.
+.RE
+
+.DS
+DEFAULT Service-Type == Framed-User, Framed-Protocol == PPP
+.br
+ Service-Type = Framed-User,
+.br
+ Framed-Protocol = PPP,
+.br
+ Fall-Through = Yes
+
+.DE
+.RS
+If the request packet contains the attributes Service-Type and
+Framed-Protocol, with the given values, then include those attributes
+in the reply.
+
+That is, give the user what they ask for. This entry also shows how
+to specify multiple reply items.
+.RE
+
+See the \fBusers\fP file supplied with the server for more examples
+and comments.
+
+.SH HINTS
+Run the server in debugging mode (\fB-X\fP), and use the
+\fBradclient\fP program to send it test packets which you think will
+match specific entries. The server will print out which entries were
+matched for that request, so you can verify your expectations. This
+should be the FIRST thing you do if you suspect problems with the
+file.
+
+Care should be taken when writing entries for the \fBusers\fP file. It is
+easy to misconfigure the server so that requests are accepted when you
+wish to reject them. The entries should be ordered, and the
+Fall-Through item should be used ONLY where it is required.
+
+Entries rejecting certain requests should go at the top of the file,
+and should not have a Fall-Through item in their reply items. Entries
+for specific users, who do not have a Fall-Through item, should come
+next. Any DEFAULT entries should usually come last, except as fall-through
+entries that set reply attributes.
+
+.SH FILES
+/etc/raddb/mods-config/files/
+.SH "SEE ALSO"
+.BR radclient (1),
+.BR radiusd (8),
+.BR dictionary (5),
+
+.SH AUTHOR
+The FreeRADIUS team.
diff --git a/man/man8/radcrypt.8 b/man/man8/radcrypt.8
new file mode 100644
index 0000000..08336c6
--- /dev/null
+++ b/man/man8/radcrypt.8
@@ -0,0 +1,45 @@
+.TH RADCRYPT 8
+.SH NAME
+radcrypt - generate password hash for use with radius, or validates a password hash
+.SH SYNOPSIS
+.B radcrypt
+.RB [ \-d | --des ]
+.RB [ \-m | --md5 ]
+.RB [ \-c | --check ]
+\fIplaintext_password\fP [\fIhashed_password\fP]
+.SH DESCRIPTION
+\fBradcrypt\fP generates a hashed digest of a plaintext password, or can
+validate if a password hash matches a plaintext password. DES and MD5
+hashes are currently supported. When generating a password hash a random
+salt is generated and applied.
+.PP
+A hashed password can be validated by specifying \fI-c\fP or \fI--check\fP and
+passing \fIhashed_password\fP after \fIplaintext_password\fP on the command line.
+In this case \fIhashed_password\fP will be checked to see if it matches
+\fIplaintext_password\fP. If so "Password OK" will be printed and the exit
+status will be 1, otherwise "Password BAD" will be printed and exit status
+will be 0 (Note this is the opposite of a normal successful shell status).
+
+.SH OPTIONS
+
+.IP "\-d --des"
+Use a DES (Data Encryption Standard) hash (default).
+Ignored if performing a password check.
+.IP "\-m --md5"
+Use a MD5 (Message Digest 5) hash.
+Ignored if performing a password check.
+.IP "\-c --check"
+Perform a validation check on a password hash to verify if it matches
+the plantext password.
+
+.SH EXAMPLES
+.nf
+$ radcrypt foobar
+HaX0xn7Qy650Q
+$ radcrypt \-c foobar HaX0xn7Qy650Q
+Password OK
+.fi
+.SH SEE ALSO
+radiusd(8), crypt(3)
+.SH AUTHORS
+Miquel van Smoorenburg <miquels@cistron-office.nl>
diff --git a/man/man8/raddebug.8 b/man/man8/raddebug.8
new file mode 100644
index 0000000..6e27e24
--- /dev/null
+++ b/man/man8/raddebug.8
@@ -0,0 +1,104 @@
+.TH RADDEBUG 8 "1 September 2010" "" "FreeRADIUS Daemon"
+.SH NAME
+raddebug - Display debugging output from a running server.
+.SH SYNOPSIS
+.B raddebug
+.RB [ \-c
+.IR condition ]
+.RB [ \-d
+.IR config_directory ]
+.RB [ \-D
+.IR dictionary_directory ]
+.RB [ \-n
+.IR name ]
+.RB [ \-i
+.IR ipv4-address ]
+.RB [ \-I
+.IR ipv6-address ]
+.RB [ \-f
+.IR socket_file ]
+.RB [ \-t
+.IR timeout ]
+.RB [ \-u
+.IR user-name ]
+.SH DESCRIPTION
+\fBraddebug\fP is a shell script wrapper around \fBradmin\fP that
+automates the process of obtaining debugging output from a running
+server. It does this without impacting service availability, unlike
+using \fBradiusd -X\fP. There are a number of prerequisites that are
+required for its proper operation:
+.PP
+.in +0.3i
+* \fBradmin\fP must be available in the PATH.
+.br
+* The user running \fBraddebug\fP must have permission to connect to
+ the server control socket.
+.br
+* The control socket must be configured. For instructions, see
+ raddb/sites-available/control-socket
+.br
+* The control socket must be marked as "mode = rw".
+.br
+* The user running \fBraddebug\fP must have permission to read and
+ write files in the "logdir" directory. This is usually
+ /var/log/radiusd.
+.in -0.3i
+.PP
+For a number of reasons, the debugging output is placed in an
+intermediate file, rather than being sent directly to standard output.
+In order to prevent this file from growing too large, the
+\fBraddebug\fP program is automatically terminated after 10 seconds.
+This timeout can be changed via the "-t" parameter.
+.PP
+When the script exits, debug mode in the server is disabled, and the
+intermediate file is deleted.
+.PP
+Debug output from a live server can be redirected to only one
+location. If a second instance of \fIraddebug\fP is started while the
+first one is still running, the later one will over-ride the first
+one, and the first will stop producing output.
+.SH OPTIONS
+
+.IP \-c\ \fIcondition\fP
+Set a specific debug condition. The format of the condition is as
+specified in the CONDITIONS section of the \fIunlang\fP manual page.
+.IP \-f\ \fIsocket_file\fP
+The path to the control socket. See the \fIradmin\fP manual page for
+more description of this option.
+.IP \-i\ \fIipv4-address\fP
+Show debug output for the client having the given IPv4 address. This
+option is equivalent to using:
+.br
+.in +0.3i
+-c '(Packet-Src-IP-Address == ipv4-address)'
+.in -0.3i
+.IP "\-d \fIconfig directory\fP"
+The radius configuration directory, usually /etc/raddb. See the
+\fIradmin\fP manual page for more description of this option.
+.IP "\-D \fIdictionary directory\fP"
+Set main dictionary directory. Defaults to \fI/usr/share/freeradius\fP.
+.IP "\-n \fImname\fP"
+Read \fIraddb/name.conf\fP instead of \fIraddb/radiusd.conf\fP.
+.IP \-I\ \fIipv6-address\fP
+Show debug output for the client having the given IPv6 address. This
+option is equivalent to using:
+.br
+.in +0.3i
+-c '(Packet-Src-IPv6-Address == ipv6-address)'
+.in -0.3i
+.IP \-t\ \fItimeout\fP
+Stop printing debug output after "timeout" seconds. The default
+timeout is sixty (60) seconds. Use "-t 0" to print debugging output forever,
+or until the script exits.
+.IP \-u\ \fIname\fP
+Show debug output for users having the given name. This
+option is equivalent to using:
+.br
+.in +0.3i
+-c '(User-Name == name)'
+.in -0.3i
+
+.SH SEE ALSO
+radmin(8), raddb/sites-available/control-socket, unlang(5), radiusd.conf(5)
+.SH AUTHORS
+Alan DeKok <aland@freeradius.org>
diff --git a/man/man8/radiusd.8 b/man/man8/radiusd.8
new file mode 100644
index 0000000..74da13b
--- /dev/null
+++ b/man/man8/radiusd.8
@@ -0,0 +1,235 @@
+.TH RADIUSD 8 "26 Apr 2012" "" "FreeRADIUS Daemon"
+.SH NAME
+radiusd - Authentication, Authorization and Accounting server
+.SH SYNOPSIS
+.B radiusd
+.RB [ \-C ]
+.RB [ \-d
+.IR config_directory ]
+.RB [ \-D
+.IR dictionary_directory ]
+.RB [ \-f ]
+.RB [ \-h ]
+.RB [ \-i
+.IR ip-address ]
+.RB [ \-l
+.IR log_file ]
+.RB [ \-m ]
+.RB [ \-n
+.IR name ]
+.RB [ \-p
+.IR port ]
+.RB [ \-P ]
+.RB [ \-s ]
+.RB [ \-t ]
+.RB [ \-v ]
+.RB [ \-x ]
+.RB [ \-X ]
+.SH DESCRIPTION
+FreeRADIUS is a high-performance and highly configurable RADIUS
+server. It supports many database back-ends such as flat-text files,
+SQL, LDAP, Perl, Python, etc. It also supports many authentication
+protocols such as PAP, CHAP, MS-CHAP(v2), HTTP Digest, and EAP
+(EAP-MD5, EAP-TLS, PEAP, EAP-TTLS, EAP-SIM, etc.).
+
+It also has full support for Cisco's VLAN Query Protocol (VMPS) and
+DHCP.
+
+Please read the DEBUGGING section below. It contains instructions
+for quickly configuring the server for your local system.
+.SH OPTIONS
+The following command-line options are accepted by the server:
+.IP \-C
+Check the configuration and exit immediately. If there is a problem
+reading the configuration, then the server will exit with a non-zero
+status code. If the configuration appears to be acceptable, then the
+server will exit with a zero status code.
+
+Note that there are limitations to this check. Due to the
+complexities involved in \fIalmost\fP starting a RADIUS server, these
+checks are necessarily incomplete. The server can return a zero
+status code when run with \-C, but may still exit with an error when
+run normally.
+
+See the output of
+.B "radiusd \-XC"
+for an informative list of which modules are checked for correct
+configuration, and which modules are skipped, and therefore not checked.
+.IP "\-d \fIconfig directory\fP"
+Defaults to \fI/etc/raddb\fP. \fBRadiusd\fP looks here for its configuration
+files such as the \fIdictionary\fP and the \fIusers\fP files.
+.IP "\-D \fIdictionary directory\fP"
+Set main dictionary directory. Defaults to \fI/usr/share/freeradius\fP.
+.IP \-f
+Do not fork, stay running as a foreground process.
+.IP \-h
+Print usage help information.
+.IP "\-i \fIip-address\fP"
+Defines which IP address that the server uses for sending and
+receiving packets.
+
+If this command-line option is given, then the "bind_address" and all
+"listen{}" entries in \fIradiusd.conf\fP are ignored.
+
+This option MUST be used in conjunction with "-p".
+.IP "\-l \fIlog_file\fP"
+Defaults to \fI${logdir}/radius.log\fP. \fBRadiusd\fP writes it's logging
+information to this file. If log_file is the string "stdout" logging will
+be written to stdout.
+.IP \-m
+On SIGINT or SIGQUIT exit cleanly instead of immediately.
+This is most useful for when running the server with "valgrind".
+.IP "\-n \fIname\fP"
+Read \fIraddb/name.conf\fP instead of \fIraddb/radiusd.conf\fP.
+.IP "\-p \fIport\fP"
+Defines which port is used for receiving authentication packets.
+Accounting packets are received on "port + 1".
+
+When this command-line option is given, all "listen" sections in
+\fIradiusd.conf\fP are ignored.
+
+This option MUST be used in conjunction with "-i".
+.IP "\-P
+Always write out PID, even with -f.
+.IP \-s
+Run in "single server" mode. The server normally runs with multiple
+threads and/or processes, which can lower its response time to
+requests. Some systems have issues with threading, however, so
+running in "single server" mode may help to address those issues. In
+single server mode, the server will also not "daemonize"
+(auto-background) itself.
+.IP \-t
+Do not spawn threads.
+.IP \-v
+Print server version information and exit.
+.IP \-X
+Debugging mode. Equivalent to "\-sfxx \-l stdout". When trying to
+understand how the server works, ALWAYS run it with "radiusd \-X".
+For production servers, use "raddebug"
+.IP \-x
+Finer-grained debug mode. In this mode the server will print details
+of every request on it's \fBstdout\fP output. You can specify this
+option multiple times (\-x \-x or \-xx) to get more detailed output.
+.SH DEBUGGING
+The default configuration is set to work in the widest possible
+circumstances. It requires minimal changes for your system.
+
+However, your needs may be complex, and may require significant
+changes to the server configuration. Making random changes is a
+guaranteed method of failure. Instead, we STRONGLY RECOMMEND
+proceeding via the following steps:
+.PP
+1) Always run the server in debugging mode (
+.B radiusd \-X
+) after making a configuration change. We cannot emphasize this
+enough. If you are not running the server in debugging mode, you
+\fIwill not\fP be able to see what is doing, and you \fIwill not\fP be
+able to correct any problems.
+
+If you ask questions on the mailing list, the first response will be
+to tell you "run the server in debugging mode". Please, follow these
+instructions.
+.PP
+2) Change as little as possible in the default configuration files.
+The server contains a decade of experience with protocols, databases,
+and different systems. Its default configuration is designed to work
+almost everywhere, and to do almost everything you need.
+.PP
+3) When you make a small change, testing it before changing anything
+else. If the change works, save a copy of the configuration, and make
+another change. If the change doesn't work, debug it, and try to
+understand why it doesn't work.
+.PP
+If you begin by making large changes to the server configuration, it
+will never work, and you will never be able to debug the problem.
+.PP
+4) If you need to add a connection to a database FOO (e.g. LDAP or
+SQL), then:
+.PP
+.in +0.3i
+a) Edit raddb/modules/foo
+.br
+This file contains the default configuration for the module. It
+contains comments describing what can be configured, and what those
+configuration entries mean.
+.br
+.br
+b) Edit raddb/sites-available/default
+.br
+This file contains the default policy for the server. e.g. "enable
+CHAP, MS-CHAP, and EAP authentication". Look in this file for all
+references to your module "foo". Read the comments, and remove the
+leading hash '#' from the lines referencing the module. This enables
+the module.
+.br
+.br
+c) Edit raddb/sites-available/inner-tunnel
+.br
+This file contains the default policy for the "tunneled" portion of
+certain EAP methods. Perform the same kind of edits as above, for the
+"default" file.. If you are not using EAP (802.1X), then this step
+can be skipped.
+.br
+.br
+d) Start the server in debugging mode (
+.B radiusd \-X
+), and start testing.
+.in -0.3i
+.PP
+5) Ask questions on the mailing list
+(freeradius-users@lists.freeradius.org). When asking questions,
+include the output from debugging mode (
+.B radiusd \-X
+). This information will allow people to help you. If you do not
+include it, the first response to your message will be "post the
+output of debug mode".
+.PP
+Ask questions earlier, rather than later. If you cannot solve a
+problem in a day, ask a question on the mailing list. Most questions
+have been seen before, and can be answered quickly.
+.SH BACKGROUND
+\fBRADIUS\fP is a protocol spoken between an access server, typically
+a device connected to several modems or ISDN lines, and a \fBradius\fP
+server. When a user connects to the access server, (s)he is asked for
+a loginname and a password. This information is then sent to the \fBradius\fP
+server. The server replies with "access denied", or "access OK". In the
+latter case login information is sent along, such as the IP address in
+the case of a PPP connection.
+.PP
+The access server also sends login and logout records to the \fBradius\fP
+server so accounting can be done. These records are kept for each terminal
+server separately in a file called \fBdetail\fP, and in the \fIwtmp\fP
+compatible logfile \fB/var/log/radwtmp\fP.
+.SH CONFIGURATION
+\fBRadiusd\fP uses a number of configuration files. Each file has it's
+own manpage describing the format of the file. These files are:
+.IP radiusd.conf
+The main configuration file, which sets the administrator-controlled
+items.
+.IP dictionary
+This file is usually static. It defines all the possible RADIUS attributes
+used in the other configuration files. You don't have to modify it.
+It includes other dictionary files in the same directory.
+.IP hints
+Defines certain hints to the radius server based on the users's loginname
+or other attributes sent by the access server. It also provides for
+mapping user names (such as Pusername -> username). This provides the
+functionality that the \fILivingston 2.0\fP server has as "Prefix" and
+"Suffix" support in the \fIusers\fP file, but is more general. Of course
+the Livingston way of doing things is also supported, and you can even use
+both at the same time (within certain limits).
+.IP huntgroups
+Defines the huntgroups that you have, and makes it possible to restrict
+access to certain huntgroups to certain (groups of) users.
+.IP users
+Here the users are defined. On a typical setup, this file mainly contains
+DEFAULT entries to process the different types of logins, based on hints
+from the hints file. Authentication is then based on the contents of
+the UNIX \fI/etc/passwd\fP file. However it is also possible to define all
+users, and their passwords, in this file.
+.SH SEE ALSO
+radiusd.conf(5), users(5), huntgroups(5), hints(5),
+dictionary(5), raddebug(8)
+.SH AUTHOR
+The FreeRADIUS Server Project (http://www.freeradius.org)
+
diff --git a/man/man8/radmin.8 b/man/man8/radmin.8
new file mode 100644
index 0000000..b58a2e3
--- /dev/null
+++ b/man/man8/radmin.8
@@ -0,0 +1,188 @@
+.TH RADMIN 8 "11 Mar 2019" "" "FreeRADIUS Server Administration Tool"
+.SH NAME
+radmin - FreeRADIUS Administration tool
+.SH SYNOPSIS
+.B radmin
+.RB [ \-d
+.IR config_directory ]
+.RB [ \-D
+.IR dictionary_directory ]
+.RB [ \-e
+.IR command ]
+.RB [ \-E ]
+.RB [ \-f
+.IR socket_file ]
+.RB [ \-h ]
+.RB [ \-i
+.IR input_file ]
+.RB [ \-n
+.IR name ]
+.RB [ \-q ]
+.SH DESCRIPTION
+FreeRADIUS Server administration tool that connects to the control
+socket of a running server, and gives a command-line interface to it.
+
+At this time, only a few commands are supported. Please type "help"
+at the command prompt for detailed information about the supported
+commands.
+.SH WARNING
+The security protections offered by this command are limited to the
+permissions on the Unix domain socket, and the server
+configuration. If someone can connect to the Unix domain socket, they
+have a substantial amount of control over the server.
+.SH OPTIONS
+The following command-line options are accepted by the program.
+.IP "\-d \fIconfig directory\fP"
+Defaults to \fI/etc/raddb\fP. \fBradmin\fP looks here for the server
+configuration files to find the "listen" section that defines the
+control socket filename.
+.IP "\-D \fIdictionary directory\fP"
+Set main dictionary directory. Defaults to \fI/usr/share/freeradius\fP.
+.IP "\-e \fIcommand\fP"
+Run \fIcommand\fP and exit.
+.IP \-E
+Echo commands as they are being executed.
+.IP "\-f \fIsocket_file\fP"
+Specify the socket filename directly. The radiusd.conf file is not read.
+.IP \-h
+Print usage help information.
+.IP "\-i \fIinput_file\fP"
+Reads input from the specified file. If not specified, stdin is used.
+This also sets "-q".
+.IP "\-n \fImname\fP"
+Read \fIraddb/name.conf\fP instead of \fIraddb/radiusd.conf\fP.
+.IP \-q
+Quiet mode.
+.SH COMMANDS
+The commands implemented by the command-line interface are almost
+completely controlled by the server. There are a few commands
+interpreted locally by radmin:
+.IP reconnect
+Reconnect to the server.
+.IP quit
+Exit from radmin.
+.IP exit
+Exit from radmin.
+.PP
+The other commands are implemented by the server. Type "help" at the
+prompt for more information.
+.SH EXAMPLES
+.IP debug\ file\ /var/log/radius/bob.log
+Set debug logs to /var/log/radius/bob.log. There is very little
+checking of this filename. Rogue administrators may be able use this
+command to over-write almost any file on the system. If those
+administrators have write access to "radius.conf", they can do the
+same thing without radmin, too.
+.IP debug\ condition\ '(User-Name\ ==\ "bob")'
+Enable debugging output for all requests that match the condition.
+Any "unlang" condition is valid here. The condition is parsed as a
+string, so it must be enclosed in single or double quotes. Strings
+enclosed in double-quotes must have back-slashes and the quotation
+marks escaped inside of the string.
+
+Only one debug condition can be active at a time.
+.IP "debug condition '((User-Name == ""bob"") || (Packet-Src-IP-Address == 192.0.2.22))'"
+A more complex condition that enables debugging output for requests
+containing User-Name "bob", or requests that originate from source IP
+address 192.0.2.22.
+.IP debug\ condition
+Disable debug conditionals.
+.SH FULL LIST OF COMMANDS
+.IP add\ <command>
+do sub-command of add
+.IP add\ client\ <command>
+Add client configuration commands
+.IP add\ client\ file\ <filename>
+Add new client definition from <filename>
+.IP debug\ <command>
+debugging commands
+.IP debug\ condition\ [condition]
+Enable debugging for requests matching [condition]
+.IP debug\ level\ <number>
+Set debug level to <number>. Higher is more debugging.
+.IP debug\ file\ [filename]
+Send all debugging output to [filename]
+.IP del\ <command>
+do sub-command of del
+.IP del\ client\ <command>
+Delete client configuration commands
+.IP del\ client\ ipaddr\ <ipaddr>
+Delete a dynamically created client
+.IP hup\ [module]
+sends a HUP signal to the server, or optionally to one module
+.IP inject\ <command>
+commands to inject packets into a running server
+.IP inject\ to\ <ipaddr>\ <port>
+Inject packets to the destination IP and port.
+.IP inject\ from\ <ipaddr>
+Inject packets as if they came from <ipaddr>
+.IP inject\ file\ <input-file>\ <output-file>
+Inject packet from input-file>, with results sent to <output-file>
+.IP reconnect
+reconnect to a running server
+.IP terminate
+terminates the server, and cause it to exit
+.IP set\ <command>
+do sub-command of set
+.IP set\ module\ <command>
+set module commands
+.IP set\ module\ config\ <module>\ variable\ value
+set configuration for <module>
+.IP set\ module\ status\ [alive|dead]
+set the module to be alive or dead (always return "fail")
+.IP set\ home_server\ <command>
+set home server commands
+.IP set\ home_server\ state\ <ipaddr>\ <port>\ [alive|dead]
+set state for given home server
+.IP show\ <command>
+do sub-command of show
+.IP show\ client\ <command>
+do sub-command of client
+.IP show\ client\ config\ <ipaddr>\ [udp|tcp]
+shows configuration for a given client.
+.IP show\ client\ list
+shows list of global clients
+.IP show\ debug\ <command>
+show debug properties
+.IP show\ debug\ condition
+Shows current debugging condition.
+.IP show\ debug\ level
+Shows current debugging level.
+.IP show\ debug\ file
+Shows current debugging file.
+.IP show\ home_server\ <command>
+do sub-command of home_server
+.IP show\ home_server\ config\ <ipaddr>\ <port>
+show configuration for given home server
+.IP show\ home_server\ list
+shows list of home servers
+.IP show\ home_server\ state\ <ipaddr>\ <port>
+shows state of given home server
+.IP show\ module\ <command>
+do sub-command of module
+.IP show\ module\ config\ <module>
+show configuration for given module
+.IP show\ module\ flags\ <module>
+show other module properties
+.IP show\ module\ list
+shows list of loaded modules
+.IP show\ module\ methods\ <module>
+show sections where <module> may be used
+.IP show\ uptime
+shows time at which server started
+.IP show\ version
+Prints version of the running server
+.IP show\ xml\ <reference>
+Prints out configuration as XML
+.IP stats\ <command>
+do sub-command of stats
+.IP stats\ client\ [auth/acct]\ <ipaddr>
+show statistics for given client, or for all clients (auth or acct)
+.IP stats\ home_server\ [<ipaddr>|auth|acct]\ <port>
+show statistics for given home server (ipaddr and port), or for all home servers (auth or acct)
+.IP stats\ detail\ <filename>
+show statistics for the given detail file
+.SH SEE ALSO
+unlang(5), radiusd.conf(5), raddb/sites-available/control-socket
+.SH AUTHOR
+Alan DeKok <aland@freeradius.org>
diff --git a/man/man8/radrelay.8 b/man/man8/radrelay.8
new file mode 100644
index 0000000..99e6573
--- /dev/null
+++ b/man/man8/radrelay.8
@@ -0,0 +1,49 @@
+.TH RADRELAY 8 "23 October 2007" "" "FreeRADIUS Daemon"
+.SH NAME
+radrelay -- Deprecated command.
+.SH DESCRIPTION
+The functions of \fIradrelay\fP have been added to \fIradiusd\fP. One
+benefit is that one instance of \fIradiusd\fP can read multiple detail
+files, among others.
+.PP
+The \fIrlm_sql_log\fP module does something similar, but for SQL
+queries. See it's man page for details.
+.SH "REPLICATION FOR BACKUPS"
+Many sites run multiple radius servers; at least one primary and one
+backup server. When the primary goes down, most NASes detect that and
+switch to the backup server.
+
+That will cause your accounting packets to go to the backup server -
+and some NASes don't even switch back to the primary server when it
+comes back up.
+
+The result is that accounting records are missed, and/or the
+administrator must jump through hoops in order to combine the
+different detail files from multiple servers. It also means that the
+session database ("radutmp", used for radwho and simultaneous use
+detection) gets out of sync.
+
+We solve this issue by "relaying" packets from one server to
+another, so they both have the same set of accounting data.
+
+See raddb/sites-available/buffered-sql for more information.
+.SH "BUFFERING FOR HIGH-LOAD SERVERS"
+If the RADIUS server suddenly receives a many accounting packets,
+there may be insufficient CPU power to process them all in a timely
+manner. This problem is especially noticeable when the accounting
+packets are going to a back-end database.
+
+Similarly, you may have one database that tracks "live" sessions, and
+another that tracks historical accounting data. In that case,
+accessing the first database is fast, as it is small. Accessing the
+second database many be slower, as it may contain multiple gigabytes
+of data. In addition, writing to the first database in a timely
+manner is important, while data may be written to the second database
+with a few minutes delay, without any harm being done.
+
+See raddb/sites-available/copy-to-home-server for more information.
+.SH SEE ALSO
+.BR radiusd(8),
+.BR rlm_sql_log(5)
+.SH AUTHOR
+The FreeRADIUS Server Project
diff --git a/man/man8/radsniff.8 b/man/man8/radsniff.8
new file mode 100644
index 0000000..24c0ee3
--- /dev/null
+++ b/man/man8/radsniff.8
@@ -0,0 +1,75 @@
+.TH RADSNIFF 8
+.SH NAME
+radsniff - dump radius protocol
+.SH SYNOPSIS
+.B radsniff
+.RB [ \-c
+.IR count ]
+.RB [ \-d
+.IR directory ]
+.RB [ \-F ]
+.RB [ \-f
+.IR filter ]
+.RB [ \-h ]
+.RB [ \-i
+.IR interface ]
+.RB [ \-I
+.IR filename ]
+.RB [ \-m ]
+.RB [ \-p
+.IR port ]
+.RB [ \-r
+.IR request filter]
+.RB [ \-R
+.IR response filter ]
+.RB [ \-s
+.IR secret ]
+.RB [ \-S ]
+.RB [ \-w
+.IR file ]
+.RB [ \-x ]
+
+.SH DESCRIPTION
+\fBradsniff\fP is a simple wrapper around libpcap. It can also print
+out the contents of RADIUS packets using the FreeRADIUS dictionaries.
+
+.SH OPTIONS
+
+.IP \-c\ \fIcount\fP
+Number of packets to capture.
+.IP \-d\ \fIdirectory\fP
+Directory where the dictionaries are found.
+.IP \-F
+Filter PCAP file from stdin to stdout.
+Output file will contain RADIUS packets.
+.IP \-f\ \fIfilter\fP
+PCAP filter. (default is udp port 1812 or 1813)
+.IP \-h
+Print usage help information.
+.IP \-i\ \fIinterface\fP
+Interface to capture.
+.IP \-I\ \fIfilename\fP
+Read packets from filename.
+.IP \-m
+Print packet headers only, not contents.
+.IP \-p\ \fIport\fP
+\tListen for packets on port.
+.IP \-r\ \fIattribute-filter\fP
+RADIUS attribute request filter.
+.IP \-R\ \fIattribute-filter\fP
+RADIUS attribute response filter.
+.IP \-s\ \fIsecret\fP
+RADIUS secret.
+.IP \-S
+Sort attributes in the packet.
+Used to compare server results.
+.IP \-w\ \fIfile\fP
+Write output packets to file.
+.IP \-x
+Print out debugging information.
+
+
+.SH SEE ALSO
+radiusd(8),pcap(3)
+.SH AUTHORS
+Nicolas Baradakis <nicolas.baradakis@cegetel.net>
diff --git a/man/man8/radsqlrelay.8 b/man/man8/radsqlrelay.8
new file mode 100644
index 0000000..f161cc3
--- /dev/null
+++ b/man/man8/radsqlrelay.8
@@ -0,0 +1,90 @@
+.\" # DS - begin display
+.de DS
+.RS
+.nf
+.sp
+..
+.\" # DE - end display
+.de DE
+.fi
+.RE
+.sp
+..
+.TH RADSQLRELAY 8 "19 June 2005" "" "FreeRADIUS helper program"
+
+.SH NAME
+radsqlrelay - relay SQL queries to a central database server
+
+.SH SYNOPSIS
+.B radsqlrelay
+.RB [ \-? ]
+.RB [ \-d
+.IR sql_driver ]
+.RB [ \-b
+.IR database ]
+.RB [ \-f
+.IR file ]
+.RB [ \-h
+.IR host ]
+.RB [ \-u
+.IR user ]
+.RB [ \-P
+.IR port ]
+.RB [ \-p
+.IR password ]
+.RB [ \-1 ]
+.RB [ \-x ]
+\fIfile_path\fP
+
+.SH DESCRIPTION
+\fBradsqlrelay\fP tails a SQL \fIlogfile\fP and forwards the queries
+to a database server. Used to replicate accounting records to one
+(central) database, even if the database has extended downtime.
+.PP
+The SQL logfile is created by the \fBrlm_sql\fP module with the
+rlm_sql_null driver logging to disk.. The module must be configured in
+the \fBradiusd\fP server before you can use \fBradsqlrelay\fP.
+
+.SH OPTIONS
+.IP "\-?"
+Print usage help information.
+.IP "\-d \fIsql_driver\fP"
+Driver to use: mysql, pg, oracle.
+.IP "\-b \fIdatabase\fP"
+Name of the database to use.
+.IP "\-f \fIfile\fP"
+Read password from file, instead of command line.
+.IP "\-h \fIhost\fP"
+Connect to host.
+.IP "\-u \fIuser\fP"
+User for login.
+.IP "\-P \fIport\fP"
+Port number to use for connection.
+.IP "\-p \fIpassword\fP"
+Password to use when connecting to server.
+.IP "\-1"
+One-shot mode: push the file to database and exit.
+.IP "\-x"
+Turn on debugging.
+.IP "file_path"
+The pathname of the SQL logfile to use.
+
+.SH NOTES
+.SS Oracle driver
+The command "radsqlrelay \-d oracle \-b db.domain.tld sql-relay" reads the
+database description stored in $TNS_ADMIN/tnsnames.ora:
+.PP
+.DS
+db.domain.tld =
+ (DESCRIPTION =
+ (ADDRESS_LIST =
+ (ADDRESS = (PROTOCOL = TCP)(HOST = db.domain.tld)(PORT = 1521))
+ )
+ (CONNECT_DATA =
+ (SERVICE_NAME = <DB SID>)
+ )
+ )
+.DE
+
+.SH AUTHOR
+Nicolas Baradakis <nicolas.baradakis@cegetel.net>
diff --git a/man/man8/rlm_sqlippool_tool.8 b/man/man8/rlm_sqlippool_tool.8
new file mode 100644
index 0000000..a7dfbb7
--- /dev/null
+++ b/man/man8/rlm_sqlippool_tool.8
@@ -0,0 +1,157 @@
+.TH RLM_SQLIPPOOL_TOOL 8
+.SH NAME
+rlm_sqlippool_tool - manage SQL IP pools
+.SH SYNOPSIS
+.B rlm_sqlippool_tool
+.RB \-p
+.IR pool_name
+.RB \-s
+.IR range_start
+.RB \-e
+.IR range_end
+.RB \-t
+.IR table_name
+.RB \-d
+.OR dialect
+.RB \-f
+.IR raddb_dir
+.RB \-i
+.IR instance
+.RB [ \-c
+.IR capacity ]
+.RB [ \-x
+.IR existing_ips_file ]
+
+.B rlm_sqlippool_tool
+.RB \-y
+.IR pool_defs_yaml_file
+.RB \-t
+.IR table_name
+.RB \-d
+.OR dialect
+.RB \-f
+.IR raddb_dir
+.RB \-i
+.IR instance
+.RB [ \-x
+.IR existing_ips_file ]
+
+.SH DESCRIPTION
+\fBrlm_sqlippool_tool\fP is a tool to manage IP address in SQL IP
+pools as used by FreeRADIUS. It will either output SQL that can
+be used to manipulate the database or will interact directly with
+a database to populate an IP pool table.
+
+The format of the SQL output or the commands operated on the database
+are based on the default FreeRADIUS ippool schemas. The fields
+populated are \fIpool_name\fP and \fIframedipaddress\fP. All other
+fields are left to be populated with their database defaults.
+
+.SH OPTIONS
+
+.IP \-c\ \fIcapacity\fP
+Number of IP addreses to populate the pool with. Defaults to 65536,
+or the maximum number that can be provisioned between the start and
+end of the range.
+.IP \-d\ \fIdialect\fP
+SQL dialect to use in producing the output.
+.IP \-e\ \fIrange_end\fP
+End IP address in the pool range. Either IPv4 or IPv6 addresses are
+allowed.
+.IP \-f\ \fIraddb_dir\fP
+Directory containing the FreeRADIUS configuration. If this option
+is specified, then \fBrlm_sqlippool_tool\fP will parse the configuration
+and attempt to talk directly to the database server specified in
+the FreeRADIUS configuration.
+.IP \-i\ \fIinstance\fP
+Used in conjuction with -f. Specifies the name of the sql module
+instance to parse in the FreeRADIUS configuration. Defaults to \fIsql\fP.
+.IP \-p\ \fIpool_name\fP
+The pool name to populate.
+.IP \-s\ \fIrange_start\fP
+Start IP address in the pool range. Either IPv4 or IPv6 addresses
+are allowed.
+.IP \-t\ \fItable_name\fP
+Name of the table in the database to populate.
+.IP \-x\ \fIexisting_ips_file\fP
+A file containing exsiting IP addresses in the pool. Use of this allows
+for more controlled growth of a sparesly populated pool.
+.IP \-y\ \fIpool_defs_yaml_file\fP
+A YAML formatted file containing specifications for a number of pools.
+
+.SH EXAMPLES
+To produce MySQL formatted SQL for a pool named \fIlocal\fP populated with
+addresses from 10.0.0.1 to 10.0.0.199:
+.PP
+.nf
+.RS
+$ rlm_sqlippool_tool -p local -s 10.0.0.1 -e 10.0.0.199 \\
+ -t dhcpippool -d mysql
+.RE
+.fi
+.PP
+To do the same but directly interacting with the SQL module configured
+in the FreeRADIUS configuration under \fI/etc/raddb\fP:
+.PP
+.nf
+.RS
+$ rlm_sqlippool_tool -p local -s 10.0.0.1 -e 10.0.0.199 \\
+ -t dhcpippool -f /etc/raddb
+.RE
+.fi
+.PP
+To use a YAML file to specify the pool ranges to be populated, outputting
+PostgreSQL formatted SQL:
+.PP
+.nf
+.RS
+$ rlm_sqlippool_tool -y pools.yaml -t dhcpippool -d postgresql
+.RE
+.fi
+.PP
+
+.SH YAML FORMAT
+
+A YAML file to populate multiple pools should be formatted like this:
+.PP
+.nf
+.RS
+pool_with_a_single_contiguous_range:
+ - start: 192.0.2.3
+ end: 192.0.2.250
+
+pool_with_a_single_sparse_range:
+ - start: 10.10.10.0
+ end: 10.10.20.255
+ capacity: 200
+
+pool_with_multiple_ranges:
+ - start: 10.10.10.1
+ end: 10.10.10.253
+ - start: 10.10.100.0
+ end: 10.10.199.255
+ capacity: 1000
+
+v6_pool_with_contiguous_range:
+ - start: '2001:db8:1:2:3:4:5:10'
+ end: '2001:db8:1:2:3:4:5:7f'
+
+v6_pool_with_sparse_range:
+ - start: '2001:db8:1:2::'
+ end: '2001:db8:1:2:ffff:ffff:ffff:ffff'
+ capacity: 200
+.RE
+.ni
+.PP
+
+.SH PREREQUISITES
+
+To output formatted SQL, the Perl Template::Toolkit module is required.
+
+Direct connection to databases is done using Perl DBI. The appropriate
+Perl DBD driver needs to be installed to enable this functionality.
+
+.SH SEE ALSO
+radiusd.conf(5), raddb/mods-available/sql
+.SH AUTHORS
+Nick Porter <nick@portercomputing.co.uk>
diff --git a/mibs/FREERADIUS-MGMT-MIB.mib b/mibs/FREERADIUS-MGMT-MIB.mib
new file mode 100644
index 0000000..8cb4009
--- /dev/null
+++ b/mibs/FREERADIUS-MGMT-MIB.mib
@@ -0,0 +1,38 @@
+FREERADIUS-MGMT-MIB DEFINITIONS ::= BEGIN
+
+IMPORTS
+ MODULE-IDENTITY,
+ OBJECT-IDENTITY
+ FROM SNMPv2-SMI
+ freeRadiusMgmt
+ FROM FREERADIUS-SMI
+ SnmpAdminString
+ FROM SNMP-FRAMEWORK-MIB;
+
+freeradiusObjects MODULE-IDENTITY
+ LAST-UPDATED "200712170000Z"
+ ORGANIZATION "FreeRADIUS Project"
+ CONTACT-INFO
+ "FreeRADIUS Network Object Model Environment project
+
+ see http://www.freeradius.org for contact persons of a particular
+ area or subproject of FREERADIUS.
+
+ Administrative contact for MIB module:
+
+ Alan DeKok
+
+ email: aland@freeradius.org"
+ DESCRIPTION
+ "Generic objects used by notification MIBs"
+ ::= { freeRadiusMgmt 1 }
+
+radiusObject OBJECT-TYPE
+ SYNTAX SnmpAdminString
+ MAX-ACCESS accessible-for-notify
+ STATUS current
+ DESCRIPTION
+ "A generic object"
+ ::= { freeradiusObjects 1 }
+
+END
diff --git a/mibs/FREERADIUS-NOTIFICATION-MIB.mib b/mibs/FREERADIUS-NOTIFICATION-MIB.mib
new file mode 100644
index 0000000..3f8e0eb
--- /dev/null
+++ b/mibs/FREERADIUS-NOTIFICATION-MIB.mib
@@ -0,0 +1,180 @@
+FREERADIUS-NOTIFICATION-MIB DEFINITIONS ::= BEGIN
+ IMPORTS
+ MODULE-IDENTITY, NOTIFICATION-TYPE
+ FROM SNMPv2-SMI
+ freeradiusObjects
+ FROM FREERADIUS-MGMT-MIB
+ freeRadius
+ FROM FREERADIUS-SMI
+ radiusAuthServerAddress,radiusAuthClientServerPortNumber
+ FROM RADIUS-AUTH-CLIENT-MIB
+ radiusAuthServIdent
+ FROM RADIUS-AUTH-SERVER-MIB
+ radiusd
+ FROM FREERADIUS-PRODUCT-RADIUSD-MIB;
+
+freeRadiusNotificationMib MODULE-IDENTITY
+ LAST-UPDATED "201012170000Z"
+ ORGANIZATION "FREERADIUS project"
+ CONTACT-INFO
+ "FreeRADIUS Network Object Model Environment project
+
+ see http://www.freeradius.org for contact persons of a particular
+ area or subproject of FREERADIUS.
+
+ Administrative contact for MIB module:
+
+ Alan DeKok
+
+ email: aland@freeradius.org"
+ DESCRIPTION
+ "FreeRADIUS Notification MIBs."
+ ::= { freeRadius 4 }
+
+serverGlobal OBJECT IDENTIFIER ::= { freeRadiusNotificationMib 1 }
+
+serverStart NOTIFICATION-TYPE
+ OBJECTS { radiusObject }
+ STATUS current
+ DESCRIPTION "Notification that the server has started"
+ ::= { serverGlobal 1 }
+
+serverStop NOTIFICATION-TYPE
+ OBJECTS { radiusObject }
+ STATUS current
+ DESCRIPTION "Notification that the server is stopping"
+ ::= { serverGlobal 2 }
+
+serverMaxRequests NOTIFICATION-TYPE
+ OBJECTS { radiusObject }
+ STATUS current
+ DESCRIPTION "Notification that the server has hit the max_requests limit"
+ ::= { serverGlobal 3 }
+
+serverSignal OBJECT IDENTIFIER ::= { serverGlobal 4 }
+
+signalHup NOTIFICATION-TYPE
+ OBJECTS { radiusObject }
+ STATUS current
+ DESCRIPTION "Notification that the server has received a HUP signal"
+ ::= { serverSignal 1 }
+
+signalTerm NOTIFICATION-TYPE
+ OBJECTS { radiusObject }
+ STATUS current
+ DESCRIPTION "Notification that the server has received a TERM signal"
+ ::= { serverSignal 2 }
+
+serverThread OBJECT IDENTIFIER ::= { serverGlobal 5 }
+
+threadStart NOTIFICATION-TYPE
+ OBJECTS { radiusObject }
+ STATUS current
+ DESCRIPTION "Notification that a thread has started"
+ ::= { serverThread 1 }
+
+threadStop NOTIFICATION-TYPE
+ OBJECTS { radiusObject }
+ STATUS current
+ DESCRIPTION "Notification that a thread has stopped"
+ ::= { serverThread 2 }
+
+threadUnresponsive NOTIFICATION-TYPE
+ OBJECTS { radiusObject }
+ STATUS current
+ DESCRIPTION "Notification that a child thread is unresponsive"
+ ::= { serverThread 3 }
+
+threadMaxThreads NOTIFICATION-TYPE
+ OBJECTS { radiusObject }
+ STATUS current
+ DESCRIPTION "Notification that the max_threads limit has been reached"
+ ::= { serverThread 4 }
+
+serverModules OBJECT IDENTIFIER ::= { freeRadiusNotificationMib 2 }
+
+serverModuleGeneric OBJECT IDENTIFIER ::= { serverModules 1 }
+
+serverModuleConnectionUp NOTIFICATION-TYPE
+ OBJECTS { radiusdModuleName,
+ radiusdModuleInstance }
+ STATUS current
+ DESCRIPTION "Notification that the module has opened a new connection"
+ ::= { serverModuleGeneric 1 }
+
+serverModuleConnectionDown NOTIFICATION-TYPE
+ OBJECTS { radiusdModuleName,
+ radiusdModuleInstance }
+ STATUS current
+ DESCRIPTION "Notification that the module has dropped a connection"
+ ::= { serverModuleGeneric 2 }
+
+serverModuleConnectionNone NOTIFICATION-TYPE
+ OBJECTS { radiusdModuleName,
+ radiusdModuleInstance }
+ STATUS current
+ DESCRIPTION "Notification that the module has no connections"
+ ::= { serverModuleGeneric 3 }
+
+serverModuleConnectionFail NOTIFICATION-TYPE
+ OBJECTS { radiusdModuleName,
+ radiusdModuleInstance }
+ STATUS current
+ DESCRIPTION "Notification that the module has failed to open a new connection"
+ ::= { serverModuleGeneric 4 }
+
+serverModuleHup NOTIFICATION-TYPE
+ OBJECTS { radiusdModuleName,
+ radiusdModuleInstance }
+ STATUS current
+ DESCRIPTION "Notification that the module has been HUP'd via radmin"
+ ::= { serverModuleGeneric 5 }
+
+homeServer OBJECT IDENTIFIER ::= { freeRadiusNotificationMib 3 }
+
+--
+-- For now, we only support IPv4 traps, and we support only UDP.
+-- We can add IPv6 and TCP / TLS later.
+--
+-- We also use the "authserver" fields for both authentication and accounting
+-- servers.
+--
+homeServerAlive NOTIFICATION-TYPE
+ OBJECTS { radiusAuthServerAddress,
+ radiusAuthClientServerPortNumber,
+ radiusAuthServIdent }
+ STATUS current
+ DESCRIPTION "Notification that a home server is alive"
+ ::= { homeServer 1 }
+
+homeServerZombie NOTIFICATION-TYPE
+ OBJECTS { radiusAuthServerAddress,
+ radiusAuthClientServerPortNumber,
+ radiusAuthServIdent }
+ STATUS current
+ DESCRIPTION "Notification that a home server is zombie"
+ ::= { homeServer 2 }
+
+homeServerDead NOTIFICATION-TYPE
+ OBJECTS { radiusAuthServerAddress,
+ radiusAuthClientServerPortNumber,
+ radiusAuthServIdent }
+ STATUS current
+ DESCRIPTION "Notification that a home server is dead"
+ ::= { homeServer 3 }
+
+homeServerPool OBJECT IDENTIFIER ::= { freeRadiusNotificationMib 4 }
+
+homeServerPoolNormal NOTIFICATION-TYPE
+ OBJECTS { radiusdConfigName }
+ STATUS current
+ DESCRIPTION "Notification that the pool is operating normally"
+ ::= { homeServerPool 1 }
+
+homeServerPoolFallback NOTIFICATION-TYPE
+ OBJECTS { radiusdConfigName }
+ STATUS current
+ DESCRIPTION "Notification that the pool is in fallback mode"
+ ::= { homeServerPool 2 }
+
+END
diff --git a/mibs/FREERADIUS-PRODUCT-RADIUSD-MIB.mib b/mibs/FREERADIUS-PRODUCT-RADIUSD-MIB.mib
new file mode 100644
index 0000000..daa08c2
--- /dev/null
+++ b/mibs/FREERADIUS-PRODUCT-RADIUSD-MIB.mib
@@ -0,0 +1,75 @@
+FREERADIUS-PRODUCT-RADIUSD-MIB DEFINITIONS ::= BEGIN
+
+IMPORTS
+ MODULE-IDENTITY,
+ OBJECT-IDENTITY
+ FROM SNMPv2-SMI
+ SnmpAdminString
+ FROM SNMP-FRAMEWORK-MIB
+ freeRadiusProducts
+ FROM FREERADIUS-SMI;
+
+freeradius MODULE-IDENTITY
+ LAST-UPDATED "200712170000Z"
+ ORGANIZATION "FreeRADIUS Project"
+ CONTACT-INFO
+ "FreeRADIUS Network Object Model Environment project
+
+ see http://www.freeradius.org for contact persons of a particular
+ area or subproject of FREERADIUS.
+
+ Administrative contact for MIB module:
+
+ Alan DeKok
+
+ email: aland@freeradius.org"
+ DESCRIPTION
+ "The product registrations for the FreeRADIUS SNMP subagent.
+ These registrations are guaranteed to be unique and are used
+ for SMUX registration by default (if not overridden manually)."
+ ::= { freeRadiusProducts 1 }
+
+radiusd OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "radiusd is the RADIUS protocol deamon of the FreeRADIUS
+ project."
+ ::= { freeradius 1 }
+
+radiusdConfig OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "Information about the server configuration"
+ ::= { radiusd 2 }
+
+radiusdConfigName OBJECT-TYPE
+ SYNTAX SnmpAdminString
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The name of a configuration item"
+ ::= { radiusdConfig 1 }
+
+radiusdModule OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "Information about modules associated with the server"
+ ::= { radiusd 3 }
+
+radiusdModuleName OBJECT-TYPE
+ SYNTAX SnmpAdminString
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The name the module (e.g. 'foo' for rlm_foo)"
+ ::= { radiusdModule 1 }
+
+radiusdModuleInstance OBJECT-TYPE
+ SYNTAX SnmpAdminString
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The instance name the module (e.g. 'sql2' for sql sql2 {...})"
+ ::= { radiusdModule 2 }
+
+END
diff --git a/mibs/FREERADIUS-SMI.mib b/mibs/FREERADIUS-SMI.mib
new file mode 100644
index 0000000..b4981ba
--- /dev/null
+++ b/mibs/FREERADIUS-SMI.mib
@@ -0,0 +1,52 @@
+FREERADIUS-SMI DEFINITIONS ::= BEGIN
+
+IMPORTS
+ MODULE-IDENTITY,
+ OBJECT-IDENTITY,
+ enterprises
+ FROM SNMPv2-SMI;
+
+freeRadius MODULE-IDENTITY
+ LAST-UPDATED "200712170000Z"
+ ORGANIZATION "FREERADIUS project"
+ CONTACT-INFO
+ "FreeRADIUS Network Object Model Environment project
+
+ see http://www.freeradius.org for contact persons of a particular
+ area or subproject of FREERADIUS.
+
+ Administrative contact for MIB module:
+
+ Alan DeKok
+
+ email: aland@freeradius.org"
+ DESCRIPTION
+ "The Structure of FREERADIUS."
+ ::= { enterprises 11344 } -- assigned by IANA
+
+freeRadiusProducts OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "freeRadiusProducts is the root OBJECT IDENTIFIER from
+ which sysObjectID values are assigned."
+ ::= { freeRadius 1 }
+
+freeRadiusMgmt OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "freeRadiusMgmt defines the subtree for production FREERADIUS related
+ MIB registrations."
+ ::= { freeRadius 2 }
+
+freeRadiusTest OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "freeRadiusTest defines the subtree for testing FREERADIUS related
+ MIB registrations."
+ ::= { freeRadius 3 }
+
+-- 4 is the notification MIB
+
+-- more to come if necessary.
+
+END
diff --git a/mibs/RADIUS-ACC-CLIENT-MIB.mib b/mibs/RADIUS-ACC-CLIENT-MIB.mib
new file mode 100644
index 0000000..417a2d5
--- /dev/null
+++ b/mibs/RADIUS-ACC-CLIENT-MIB.mib
@@ -0,0 +1,647 @@
+ RADIUS-ACC-CLIENT-MIB DEFINITIONS ::= BEGIN
+
+ IMPORTS
+ MODULE-IDENTITY, OBJECT-TYPE, OBJECT-IDENTITY,
+ Counter32, Integer32, Gauge32,
+ IpAddress, TimeTicks, mib-2 FROM SNMPv2-SMI
+ SnmpAdminString FROM SNMP-FRAMEWORK-MIB
+ InetAddressType, InetAddress,
+ InetPortNumber FROM INET-ADDRESS-MIB
+ MODULE-COMPLIANCE, OBJECT-GROUP FROM SNMPv2-CONF;
+
+
+ radiusAccClientMIB MODULE-IDENTITY
+ LAST-UPDATED "200608210000Z" -- 21 August 2006
+ ORGANIZATION "IETF RADIUS Extensions Working Group."
+ CONTACT-INFO
+ " Bernard Aboba
+ Microsoft
+ One Microsoft Way
+ Redmond, WA 98052
+ US
+ Phone: +1 425 936 6605
+ EMail: bernarda@microsoft.com"
+ DESCRIPTION
+ "The MIB module for entities implementing the client
+ side of the Remote Authentication Dial-In User Service
+ (RADIUS) accounting protocol. Copyright (C) The
+ Internet Society (2006). This version of this MIB
+ module is part of RFC 4670; see the RFC itself for
+ full legal notices."
+ REVISION "200608210000Z" -- 21 August 2006
+ DESCRIPTION
+ "Revised version as published in RFC 4670.
+ This version obsoletes that of RFC 2620 by
+ deprecating the MIB table containing IPv4-only
+ address formats and defining a new table to add support
+ for version-neutral IP address formats. The remaining
+ MIB objects from RFC 2620 are carried forward into this
+ version."
+ REVISION "199906110000Z" -- 11 Jun 1999
+ DESCRIPTION "Initial version as published in RFC 2620."
+ ::= { radiusAccounting 2 }
+
+ radiusMIB OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The OID assigned to RADIUS MIB work by the IANA."
+ ::= { mib-2 67 }
+
+ radiusAccounting OBJECT IDENTIFIER ::= {radiusMIB 2}
+
+ radiusAccClientMIBObjects OBJECT IDENTIFIER
+ ::= { radiusAccClientMIB 1 }
+
+ radiusAccClient OBJECT IDENTIFIER
+ ::= { radiusAccClientMIBObjects 1 }
+
+ radiusAccClientInvalidServerAddresses OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of RADIUS Accounting-Response packets
+ received from unknown addresses."
+ ::= { radiusAccClient 1 }
+ radiusAccClientIdentifier OBJECT-TYPE
+ SYNTAX SnmpAdminString
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The NAS-Identifier of the RADIUS accounting client.
+ This is not necessarily the same as sysName in MIB
+ II."
+ REFERENCE "RFC 2865 section 5.32"
+ ::= { radiusAccClient 2 }
+
+ radiusAccServerTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF RadiusAccServerEntry
+ MAX-ACCESS not-accessible
+ STATUS deprecated
+ DESCRIPTION
+ "The (conceptual) table listing the RADIUS accounting
+ servers with which the client shares a secret."
+ ::= { radiusAccClient 3 }
+
+ radiusAccServerEntry OBJECT-TYPE
+ SYNTAX RadiusAccServerEntry
+ MAX-ACCESS not-accessible
+ STATUS deprecated
+ DESCRIPTION
+ "An entry (conceptual row) representing a RADIUS
+ accounting server with which the client shares a
+ secret."
+ INDEX { radiusAccServerIndex }
+ ::= { radiusAccServerTable 1 }
+
+ RadiusAccServerEntry ::= SEQUENCE {
+ radiusAccServerIndex Integer32,
+ radiusAccServerAddress IpAddress,
+ radiusAccClientServerPortNumber Integer32,
+ radiusAccClientRoundTripTime TimeTicks,
+ radiusAccClientRequests Counter32,
+ radiusAccClientRetransmissions Counter32,
+ radiusAccClientResponses Counter32,
+ radiusAccClientMalformedResponses Counter32,
+ radiusAccClientBadAuthenticators Counter32,
+ radiusAccClientPendingRequests Gauge32,
+ radiusAccClientTimeouts Counter32,
+ radiusAccClientUnknownTypes Counter32,
+ radiusAccClientPacketsDropped Counter32
+ }
+
+ radiusAccServerIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..2147483647)
+ MAX-ACCESS not-accessible
+ STATUS deprecated
+ DESCRIPTION
+ "A number uniquely identifying each RADIUS
+ Accounting server with which this client
+ communicates."
+ ::= { radiusAccServerEntry 1 }
+
+ radiusAccServerAddress OBJECT-TYPE
+ SYNTAX IpAddress
+ MAX-ACCESS read-only
+ STATUS deprecated
+ DESCRIPTION
+ "The IP address of the RADIUS accounting server
+ referred to in this table entry."
+ ::= { radiusAccServerEntry 2 }
+
+ radiusAccClientServerPortNumber OBJECT-TYPE
+ SYNTAX Integer32 (0..65535)
+ MAX-ACCESS read-only
+ STATUS deprecated
+ DESCRIPTION
+ "The UDP port the client is using to send requests to
+ this server."
+ REFERENCE "RFC 2866 section 3"
+ ::= { radiusAccServerEntry 3 }
+
+ radiusAccClientRoundTripTime OBJECT-TYPE
+ SYNTAX TimeTicks
+ MAX-ACCESS read-only
+ STATUS deprecated
+ DESCRIPTION
+ "The time interval between the most recent
+ Accounting-Response and the Accounting-Request that
+ matched it from this RADIUS accounting server."
+ REFERENCE "RFC 2866 section 2"
+ ::= { radiusAccServerEntry 4 }
+
+ -- Request/Response statistics
+ --
+ -- Requests = Responses + PendingRequests + ClientTimeouts
+ --
+ -- Responses - MalformedResponses - BadAuthenticators -
+ -- UnknownTypes - PacketsDropped = Successfully received
+
+ radiusAccClientRequests OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS deprecated
+ DESCRIPTION
+ "The number of RADIUS Accounting-Request packets
+ sent. This does not include retransmissions."
+ REFERENCE "RFC 2866 section 4.1"
+ ::= { radiusAccServerEntry 5 }
+
+ radiusAccClientRetransmissions OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS deprecated
+ DESCRIPTION
+ "The number of RADIUS Accounting-Request packets
+ retransmitted to this RADIUS accounting server.
+ Retransmissions include retries where the
+ Identifier and Acct-Delay have been updated, as
+ well as those in which they remain the same."
+ REFERENCE "RFC 2866 section 2"
+ ::= { radiusAccServerEntry 6 }
+
+ radiusAccClientResponses OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS deprecated
+ DESCRIPTION
+ "The number of RADIUS packets received on the
+ accounting port from this server."
+ REFERENCE "RFC 2866 section 4.2"
+ ::= { radiusAccServerEntry 7 }
+
+ radiusAccClientMalformedResponses OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS deprecated
+ DESCRIPTION
+ "The number of malformed RADIUS Accounting-Response
+ packets received from this server. Malformed packets
+ include packets with an invalid length. Bad
+ authenticators and unknown types are not included as
+ malformed accounting responses."
+ REFERENCE "RFC 2866 section 3"
+ ::= { radiusAccServerEntry 8 }
+
+ radiusAccClientBadAuthenticators OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS deprecated
+ DESCRIPTION
+ "The number of RADIUS Accounting-Response
+ packets that contained invalid authenticators
+ received from this server."
+ REFERENCE "RFC 2866 section 3"
+ ::= { radiusAccServerEntry 9 }
+
+ radiusAccClientPendingRequests OBJECT-TYPE
+ SYNTAX Gauge32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS deprecated
+ DESCRIPTION
+ "The number of RADIUS Accounting-Request packets
+ sent to this server that have not yet timed out or
+ received a response. This variable is incremented
+ when an Accounting-Request is sent and decremented
+ due to receipt of an Accounting-Response, a timeout,
+ or a retransmission."
+ REFERENCE "RFC 2866 section 2"
+ ::= { radiusAccServerEntry 10 }
+
+ radiusAccClientTimeouts OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "timeouts"
+ MAX-ACCESS read-only
+ STATUS deprecated
+ DESCRIPTION
+ "The number of accounting timeouts to this server.
+ After a timeout, the client may retry to the same
+ server, send to a different server, or give up.
+ A retry to the same server is counted as a
+ retransmit as well as a timeout. A send to a different
+ server is counted as an Accounting-Request as well as
+ a timeout."
+ REFERENCE "RFC 2866 section 2"
+ ::= { radiusAccServerEntry 11 }
+
+ radiusAccClientUnknownTypes OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS deprecated
+ DESCRIPTION
+ "The number of RADIUS packets of unknown type that
+ were received from this server on the accounting port."
+ REFERENCE "RFC 2866 section 4"
+ ::= { radiusAccServerEntry 12 }
+
+ radiusAccClientPacketsDropped OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS deprecated
+ DESCRIPTION
+ "The number of RADIUS packets that were received from
+ this server on the accounting port and dropped for some
+ other reason."
+ ::= { radiusAccServerEntry 13 }
+
+
+ -- New MIB objects added in this revision
+
+ radiusAccServerExtTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF RadiusAccServerExtEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The (conceptual) table listing the RADIUS accounting
+ servers with which the client shares a secret."
+ ::= { radiusAccClient 4 }
+
+ radiusAccServerExtEntry OBJECT-TYPE
+ SYNTAX RadiusAccServerExtEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "An entry (conceptual row) representing a RADIUS
+ accounting server with which the client shares a
+ secret."
+ INDEX { radiusAccServerExtIndex }
+ ::= { radiusAccServerExtTable 1 }
+
+ RadiusAccServerExtEntry ::= SEQUENCE {
+ radiusAccServerExtIndex Integer32,
+ radiusAccServerInetAddressType InetAddressType,
+ radiusAccServerInetAddress InetAddress,
+ radiusAccClientServerInetPortNumber InetPortNumber,
+ radiusAccClientExtRoundTripTime TimeTicks,
+ radiusAccClientExtRequests Counter32,
+ radiusAccClientExtRetransmissions Counter32,
+ radiusAccClientExtResponses Counter32,
+ radiusAccClientExtMalformedResponses Counter32,
+ radiusAccClientExtBadAuthenticators Counter32,
+ radiusAccClientExtPendingRequests Gauge32,
+ radiusAccClientExtTimeouts Counter32,
+ radiusAccClientExtUnknownTypes Counter32,
+ radiusAccClientExtPacketsDropped Counter32,
+ radiusAccClientCounterDiscontinuity TimeTicks
+ }
+
+ radiusAccServerExtIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..2147483647)
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A number uniquely identifying each RADIUS
+ Accounting server with which this client
+ communicates."
+ ::= { radiusAccServerExtEntry 1 }
+
+
+ radiusAccServerInetAddressType OBJECT-TYPE
+ SYNTAX InetAddressType
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The type of address format used for the
+ radiusAccServerInetAddress object."
+ ::= { radiusAccServerExtEntry 2 }
+
+
+ radiusAccServerInetAddress OBJECT-TYPE
+ SYNTAX InetAddress
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The IP address of the RADIUS accounting
+ server referred to in this table entry, using
+ the version-neutral IP address format."
+ ::= { radiusAccServerExtEntry 3 }
+
+ radiusAccClientServerInetPortNumber OBJECT-TYPE
+ SYNTAX InetPortNumber ( 1..65535 )
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The UDP port the client is using to send requests
+ to this accounting server. The value zero (0) is
+ invalid."
+ REFERENCE "RFC 2866 section 3"
+ ::= { radiusAccServerExtEntry 4 }
+
+
+ radiusAccClientExtRoundTripTime OBJECT-TYPE
+ SYNTAX TimeTicks
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The time interval between the most recent
+ Accounting-Response and the Accounting-Request that
+ matched it from this RADIUS accounting server."
+ REFERENCE "RFC 2866 section 2"
+ ::= { radiusAccServerExtEntry 5 }
+
+ -- Request/Response statistics
+ --
+ -- Requests = Responses + PendingRequests + ClientTimeouts
+ --
+ -- Responses - MalformedResponses - BadAuthenticators -
+ -- UnknownTypes - PacketsDropped = Successfully received
+
+ radiusAccClientExtRequests OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of RADIUS Accounting-Request packets
+ sent. This does not include retransmissions.
+ This counter may experience a discontinuity when the
+ RADIUS Accounting Client module within the managed
+ entity is reinitialized, as indicated by the current
+ value of radiusAccClientCounterDiscontinuity."
+ REFERENCE "RFC 2866 section 4.1"
+ ::= { radiusAccServerExtEntry 6 }
+
+ radiusAccClientExtRetransmissions OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of RADIUS Accounting-Request packets
+ retransmitted to this RADIUS accounting server.
+ Retransmissions include retries where the
+ Identifier and Acct-Delay have been updated, as
+ well as those in which they remain the same.
+ This counter may experience a discontinuity when the
+ RADIUS Accounting Client module within the managed
+ entity is reinitialized, as indicated by the current
+ value of radiusAccClientCounterDiscontinuity."
+ REFERENCE "RFC 2866 section 2"
+ ::= { radiusAccServerExtEntry 7 }
+
+ radiusAccClientExtResponses OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of RADIUS packets received on the
+ accounting port from this server. This counter
+ may experience a discontinuity when the RADIUS
+ Accounting Client module within the managed entity is
+ reinitialized, as indicated by the current value of
+ radiusAccClientCounterDiscontinuity."
+ REFERENCE "RFC 2866 section 4.2"
+ ::= { radiusAccServerExtEntry 8 }
+
+ radiusAccClientExtMalformedResponses OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of malformed RADIUS Accounting-Response
+ packets received from this server. Malformed packets
+ include packets with an invalid length. Bad
+ authenticators and unknown types are not included as
+ malformed accounting responses. This counter may
+ experience a discontinuity when the RADIUS Accounting
+ Client module within the managed entity is
+ reinitialized, as indicated by the current
+ value of radiusAccClientCounterDiscontinuity."
+ REFERENCE "RFC 2866 section 3"
+ ::= { radiusAccServerExtEntry 9 }
+
+ radiusAccClientExtBadAuthenticators OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of RADIUS Accounting-Response
+ packets that contained invalid authenticators
+ received from this server. This counter may
+ experience a discontinuity when the RADIUS
+ Accounting Client module within the managed
+ entity is reinitialized, as indicated by the
+ current value of
+ radiusAccClientCounterDiscontinuity."
+ REFERENCE "RFC 2866 section 3"
+ ::= { radiusAccServerExtEntry 10 }
+
+ radiusAccClientExtPendingRequests OBJECT-TYPE
+ SYNTAX Gauge32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of RADIUS Accounting-Request packets
+ sent to this server that have not yet timed out or
+ received a response. This variable is incremented
+ when an Accounting-Request is sent and decremented
+ due to receipt of an Accounting-Response, a timeout,
+ or a retransmission. This counter may experience a
+ discontinuity when the RADIUS Accounting Client module
+ within the managed entity is reinitialized, as
+ indicated by the current value of
+ radiusAccClientCounterDiscontinuity."
+ REFERENCE "RFC 2866 section 2"
+ ::= { radiusAccServerExtEntry 11 }
+
+ radiusAccClientExtTimeouts OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "timeouts"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of accounting timeouts to this server.
+ After a timeout, the client may retry to the same
+ server, send to a different server, or give up.
+ A retry to the same server is counted as a
+ retransmit as well as a timeout. A send to a different
+ server is counted as an Accounting-Request as well as
+ a timeout. This counter may experience a discontinuity
+ when the RADIUS Accounting Client module within the
+ managed entity is reinitialized, as indicated by the
+ current value of radiusAccClientCounterDiscontinuity."
+ REFERENCE "RFC 2866 section 2"
+ ::= { radiusAccServerExtEntry 12 }
+
+ radiusAccClientExtUnknownTypes OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of RADIUS packets of unknown type that
+ were received from this server on the accounting port.
+ This counter may experience a discontinuity when the
+ RADIUS Accounting Client module within the managed
+ entity is reinitialized, as indicated by the current
+ value of radiusAccClientCounterDiscontinuity."
+ REFERENCE "RFC 2866 section 4"
+ ::= { radiusAccServerExtEntry 13 }
+
+ radiusAccClientExtPacketsDropped OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of RADIUS packets that were received from
+ this server on the accounting port and dropped for some
+ other reason. This counter may experience a
+ discontinuity when the RADIUS Accounting Client module
+ within the managed entity is reinitialized, as indicated
+ by the current value of
+ radiusAccClientCounterDiscontinuity."
+ ::= { radiusAccServerExtEntry 14 }
+
+ radiusAccClientCounterDiscontinuity OBJECT-TYPE
+ SYNTAX TimeTicks
+ UNITS "centiseconds"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of centiseconds since the last
+ discontinuity in the RADIUS Accounting Client
+ counters. A discontinuity may be the result of a
+ reinitialization of the RADIUS Accounting Client
+ module within the managed entity."
+ ::= { radiusAccServerExtEntry 15 }
+
+
+ -- conformance information
+
+ radiusAccClientMIBConformance OBJECT IDENTIFIER
+ ::= { radiusAccClientMIB 2 }
+
+ radiusAccClientMIBCompliances OBJECT IDENTIFIER
+ ::= { radiusAccClientMIBConformance 1 }
+
+ radiusAccClientMIBGroups OBJECT IDENTIFIER
+ ::= { radiusAccClientMIBConformance 2 }
+
+
+ -- units of conformance
+
+ radiusAccClientMIBCompliance MODULE-COMPLIANCE
+ STATUS deprecated
+ DESCRIPTION
+ "The compliance statement for accounting clients
+ implementing the RADIUS Accounting Client MIB.
+ Implementation of this module is for IPv4-only
+ entities, or for backwards compatibility use with
+ entities that support both IPv4 and IPv6."
+ MODULE -- this module
+ MANDATORY-GROUPS { radiusAccClientMIBGroup }
+
+ ::= { radiusAccClientMIBCompliances 1 }
+
+
+ radiusAccClientExtMIBCompliance MODULE-COMPLIANCE
+ STATUS current
+ DESCRIPTION
+ "The compliance statement for accounting
+ clients implementing the RADIUS Accounting
+ Client IPv6 Extensions MIB. Implementation of
+ this module is for entities that support IPv6,
+ or support IPv4 and IPv6."
+ MODULE -- this module
+ MANDATORY-GROUPS { radiusAccClientExtMIBGroup }
+
+ OBJECT radiusAccServerInetAddressType
+ SYNTAX InetAddressType { ipv4(1), ipv6(2) }
+ DESCRIPTION
+ "An implementation is only required to support
+ IPv4 and globally unique IPv6 addresses."
+
+ OBJECT radiusAccServerInetAddress
+ SYNTAX InetAddress ( SIZE (4|16) )
+ DESCRIPTION
+ "An implementation is only required to support
+ IPv4 and globally unique IPv6 addresses."
+
+ ::= { radiusAccClientMIBCompliances 2 }
+
+
+ -- units of conformance
+
+ radiusAccClientMIBGroup OBJECT-GROUP
+ OBJECTS { radiusAccClientIdentifier,
+ radiusAccClientInvalidServerAddresses,
+ radiusAccServerAddress,
+ radiusAccClientServerPortNumber,
+ radiusAccClientRoundTripTime,
+ radiusAccClientRequests,
+ radiusAccClientRetransmissions,
+ radiusAccClientResponses,
+ radiusAccClientMalformedResponses,
+ radiusAccClientBadAuthenticators,
+ radiusAccClientPendingRequests,
+ radiusAccClientTimeouts,
+ radiusAccClientUnknownTypes,
+ radiusAccClientPacketsDropped
+ }
+ STATUS deprecated
+ DESCRIPTION
+ "The basic collection of objects providing management of
+ RADIUS Accounting Clients."
+ ::= { radiusAccClientMIBGroups 1 }
+
+
+ radiusAccClientExtMIBGroup OBJECT-GROUP
+ OBJECTS { radiusAccClientIdentifier,
+ radiusAccClientInvalidServerAddresses,
+ radiusAccServerInetAddressType,
+ radiusAccServerInetAddress,
+ radiusAccClientServerInetPortNumber,
+ radiusAccClientExtRoundTripTime,
+ radiusAccClientExtRequests,
+ radiusAccClientExtRetransmissions,
+ radiusAccClientExtResponses,
+ radiusAccClientExtMalformedResponses,
+ radiusAccClientExtBadAuthenticators,
+ radiusAccClientExtPendingRequests,
+ radiusAccClientExtTimeouts,
+ radiusAccClientExtUnknownTypes,
+ radiusAccClientExtPacketsDropped,
+ radiusAccClientCounterDiscontinuity
+ }
+ STATUS current
+ DESCRIPTION
+ "The basic collection of objects providing management of
+ RADIUS Accounting Clients."
+ ::= { radiusAccClientMIBGroups 2 }
+
+
+ END
diff --git a/mibs/RADIUS-ACC-SERVER-MIB.mib b/mibs/RADIUS-ACC-SERVER-MIB.mib
new file mode 100644
index 0000000..ca5516b
--- /dev/null
+++ b/mibs/RADIUS-ACC-SERVER-MIB.mib
@@ -0,0 +1,732 @@
+RADIUS-ACC-SERVER-MIB DEFINITIONS ::= BEGIN
+
+IMPORTS
+ MODULE-IDENTITY, OBJECT-TYPE, OBJECT-IDENTITY,
+ Counter32, Integer32,
+ IpAddress, TimeTicks, mib-2 FROM SNMPv2-SMI
+ SnmpAdminString FROM SNMP-FRAMEWORK-MIB
+ InetAddressType, InetAddress FROM INET-ADDRESS-MIB
+ MODULE-COMPLIANCE, OBJECT-GROUP FROM SNMPv2-CONF;
+
+radiusAccServMIB MODULE-IDENTITY
+ LAST-UPDATED "200608210000Z" -- 21 August 2006
+ ORGANIZATION "IETF RADIUS Extensions Working Group."
+ CONTACT-INFO
+ " Bernard Aboba
+ Microsoft
+ One Microsoft Way
+ Redmond, WA 98052
+ US
+
+ Phone: +1 425 936 6605
+ EMail: bernarda@microsoft.com"
+ DESCRIPTION
+ "The MIB module for entities implementing the server
+ side of the Remote Authentication Dial-In User
+ Service (RADIUS) accounting protocol. Copyright (C)
+ The Internet Society (2006). This version of this
+ MIB module is part of RFC 4671; see the RFC itself
+ for full legal notices."
+ REVISION "200608210000Z" -- 21 August 2006
+ DESCRIPTION
+ "Revised version as published in RFC 4671. This
+ version obsoletes that of RFC 2621 by deprecating
+ the MIB table containing IPv4-only address formats
+ and defining a new table to add support for version-
+ neutral IP address formats. The remaining MIB objects
+ from RFC 2621 are carried forward into this version."
+ REVISION "199906110000Z" -- 11 Jun 1999
+ DESCRIPTION "Initial version as published in RFC 2621."
+ ::= { radiusAccounting 1 }
+
+radiusMIB OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The OID assigned to RADIUS MIB work by the IANA."
+ ::= { mib-2 67 }
+
+radiusAccounting OBJECT IDENTIFIER ::= {radiusMIB 2}
+
+radiusAccServMIBObjects OBJECT IDENTIFIER
+ ::= { radiusAccServMIB 1 }
+
+radiusAccServ OBJECT IDENTIFIER
+ ::= { radiusAccServMIBObjects 1 }
+
+radiusAccServIdent OBJECT-TYPE
+ SYNTAX SnmpAdminString
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The implementation identification string for the
+ RADIUS accounting server software in use on the
+ system, for example, 'FNS-2.1'."
+ ::= {radiusAccServ 1}
+
+radiusAccServUpTime OBJECT-TYPE
+ SYNTAX TimeTicks
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "If the server has a persistent state (e.g., a
+ process), this value will be the time elapsed (in
+ hundredths of a second) since the server process was
+ started. For software without persistent state, this
+ value will be zero."
+ ::= {radiusAccServ 2}
+
+radiusAccServResetTime OBJECT-TYPE
+ SYNTAX TimeTicks
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "If the server has a persistent state (e.g., a process)
+ and supports a 'reset' operation (e.g., can be told to
+ re-read configuration files), this value will be the
+ time elapsed (in hundredths of a second) since the
+ server was 'reset.' For software that does not
+ have persistence or does not support a 'reset'
+ operation, this value will be zero."
+ ::= {radiusAccServ 3}
+
+radiusAccServConfigReset OBJECT-TYPE
+ SYNTAX INTEGER { other(1),
+ reset(2),
+ initializing(3),
+ running(4)}
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "Status/action object to reinitialize any persistent
+ server state. When set to reset(2), any persistent
+ server state (such as a process) is reinitialized as
+ if the server had just been started. This value will
+ never be returned by a read operation. When read,
+ one of the following values will be returned:
+ other(1) - server in some unknown state;
+ initializing(3) - server (re)initializing;
+ running(4) - server currently running."
+ ::= {radiusAccServ 4}
+
+-- New Stats proposed by Dale E. Reed Jr (daler@iea.com)
+
+radiusAccServTotalRequests OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of packets received on the
+ accounting port."
+ REFERENCE "RFC 2866 section 4.1"
+ ::= { radiusAccServ 5 }
+
+radiusAccServTotalInvalidRequests OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of RADIUS Accounting-Request packets
+ received from unknown addresses."
+ REFERENCE "RFC 2866 sections 2, 4.1"
+ ::= { radiusAccServ 6 }
+
+radiusAccServTotalDupRequests OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of duplicate RADIUS Accounting-Request
+ packets received."
+ REFERENCE "RFC 2866 section 4.1"
+ ::= { radiusAccServ 7 }
+
+radiusAccServTotalResponses OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of RADIUS Accounting-Response packets
+ sent."
+ REFERENCE "RFC 2866 section 4.2"
+ ::= { radiusAccServ 8 }
+
+radiusAccServTotalMalformedRequests OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of malformed RADIUS Accounting-Request
+ packets received. Bad authenticators or unknown
+ types are not included as malformed Access-Requests."
+ REFERENCE "RFC 2866 section 3"
+ ::= { radiusAccServ 9 }
+
+radiusAccServTotalBadAuthenticators OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of RADIUS Accounting-Request packets
+ that contained an invalid authenticator."
+ REFERENCE "RFC 2866 section 3"
+ ::= { radiusAccServ 10 }
+
+radiusAccServTotalPacketsDropped OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of incoming packets silently discarded
+ for a reason other than malformed, bad authenticators,
+ or unknown types."
+ REFERENCE "RFC 2866 section 3"
+ ::= { radiusAccServ 11 }
+
+radiusAccServTotalNoRecords OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of RADIUS Accounting-Request packets
+ that were received and responded to but not
+ recorded."
+ ::= { radiusAccServ 12 }
+
+radiusAccServTotalUnknownTypes OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of RADIUS packets of unknown type that
+ were received."
+ REFERENCE "RFC 2866 section 4"
+ ::= { radiusAccServ 13 }
+
+-- End of new
+
+radiusAccClientTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF RadiusAccClientEntry
+ MAX-ACCESS not-accessible
+ STATUS deprecated
+ DESCRIPTION
+ "The (conceptual) table listing the RADIUS accounting
+ clients with which the server shares a secret."
+ ::= { radiusAccServ 14 }
+
+radiusAccClientEntry OBJECT-TYPE
+ SYNTAX RadiusAccClientEntry
+ MAX-ACCESS not-accessible
+ STATUS deprecated
+ DESCRIPTION
+ "An entry (conceptual row) representing a RADIUS
+ accounting client with which the server shares a
+ secret."
+ INDEX { radiusAccClientIndex }
+ ::= { radiusAccClientTable 1 }
+
+RadiusAccClientEntry ::= SEQUENCE {
+ radiusAccClientIndex Integer32,
+ radiusAccClientAddress IpAddress,
+ radiusAccClientID SnmpAdminString,
+ radiusAccServPacketsDropped Counter32,
+ radiusAccServRequests Counter32,
+ radiusAccServDupRequests Counter32,
+ radiusAccServResponses Counter32,
+ radiusAccServBadAuthenticators Counter32,
+ radiusAccServMalformedRequests Counter32,
+ radiusAccServNoRecords Counter32,
+ radiusAccServUnknownTypes Counter32
+}
+
+radiusAccClientIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..2147483647)
+ MAX-ACCESS not-accessible
+ STATUS deprecated
+ DESCRIPTION
+ "A number uniquely identifying each RADIUS accounting
+ client with which this server communicates."
+ ::= { radiusAccClientEntry 1 }
+
+radiusAccClientAddress OBJECT-TYPE
+ SYNTAX IpAddress
+ MAX-ACCESS read-only
+ STATUS deprecated
+ DESCRIPTION
+ "The NAS-IP-Address of the RADIUS accounting client
+ referred to in this table entry."
+ ::= { radiusAccClientEntry 2 }
+
+radiusAccClientID OBJECT-TYPE
+ SYNTAX SnmpAdminString
+ MAX-ACCESS read-only
+ STATUS deprecated
+ DESCRIPTION
+ "The NAS-Identifier of the RADIUS accounting client
+ referred to in this table entry. This is not
+ necessarily the same as sysName in MIB II."
+ REFERENCE "RFC 2865 section 5.32"
+ ::= { radiusAccClientEntry 3 }
+
+-- Server Counters
+--
+-- Requests - DupRequests - BadAuthenticators - MalformedRequests -
+-- UnknownTypes - PacketsDropped - Responses = Pending
+--
+-- Requests - DupRequests - BadAuthenticators - MalformedRequests -
+-- UnknownTypes - PacketsDropped - NoRecords = entries logged
+
+radiusAccServPacketsDropped OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS deprecated
+ DESCRIPTION
+ "The number of incoming packets received
+ from this client and silently discarded
+ for a reason other than malformed, bad
+ authenticators, or unknown types."
+ REFERENCE "RFC 2866 section 3"
+ ::= { radiusAccClientEntry 4 }
+
+radiusAccServRequests OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS deprecated
+ DESCRIPTION
+ "The number of packets received from this
+ client on the accounting port."
+ REFERENCE "RFC 2866 section 4.1"
+ ::= { radiusAccClientEntry 5 }
+
+radiusAccServDupRequests OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS deprecated
+ DESCRIPTION
+ "The number of duplicate RADIUS Accounting-Request
+ packets received from this client."
+ REFERENCE "RFC 2866 section 4.1"
+ ::= { radiusAccClientEntry 6 }
+
+radiusAccServResponses OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS deprecated
+ DESCRIPTION
+ "The number of RADIUS Accounting-Response packets
+ sent to this client."
+ REFERENCE "RFC 2866 section 4.2"
+ ::= { radiusAccClientEntry 7 }
+
+radiusAccServBadAuthenticators OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS deprecated
+ DESCRIPTION
+ "The number of RADIUS Accounting-Request packets
+ that contained invalid authenticators received
+ from this client."
+ REFERENCE "RFC 2866 section 3"
+ ::= { radiusAccClientEntry 8 }
+
+radiusAccServMalformedRequests OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS deprecated
+ DESCRIPTION
+ "The number of malformed RADIUS Accounting-Request
+ packets that were received from this client.
+ Bad authenticators and unknown types
+ are not included as malformed Accounting-Requests."
+ REFERENCE "RFC 2866 section 3"
+ ::= { radiusAccClientEntry 9 }
+
+radiusAccServNoRecords OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS deprecated
+ DESCRIPTION
+ "The number of RADIUS Accounting-Request packets
+ that were received and responded to but not
+ recorded."
+ ::= { radiusAccClientEntry 10 }
+
+radiusAccServUnknownTypes OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS deprecated
+ DESCRIPTION
+ "The number of RADIUS packets of unknown type that
+ were received from this client."
+ REFERENCE "RFC 2866 section 4"
+ ::= { radiusAccClientEntry 11 }
+
+
+radiusAccClientExtTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF RadiusAccClientExtEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The (conceptual) table listing the RADIUS accounting
+ clients with which the server shares a secret."
+ ::= { radiusAccServ 15 }
+
+radiusAccClientExtEntry OBJECT-TYPE
+ SYNTAX RadiusAccClientExtEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "An entry (conceptual row) representing a RADIUS
+ accounting client with which the server shares a
+ secret."
+ INDEX { radiusAccClientExtIndex }
+ ::= { radiusAccClientExtTable 1 }
+
+RadiusAccClientExtEntry ::= SEQUENCE {
+ radiusAccClientExtIndex Integer32,
+ radiusAccClientInetAddressType InetAddressType,
+ radiusAccClientInetAddress InetAddress,
+ radiusAccClientExtID SnmpAdminString,
+ radiusAccServExtPacketsDropped Counter32,
+ radiusAccServExtRequests Counter32,
+ radiusAccServExtDupRequests Counter32,
+ radiusAccServExtResponses Counter32,
+ radiusAccServExtBadAuthenticators Counter32,
+ radiusAccServExtMalformedRequests Counter32,
+ radiusAccServExtNoRecords Counter32,
+ radiusAccServExtUnknownTypes Counter32,
+ radiusAccServerCounterDiscontinuity TimeTicks
+}
+
+radiusAccClientExtIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..2147483647)
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A number uniquely identifying each RADIUS accounting
+ client with which this server communicates."
+ ::= { radiusAccClientExtEntry 1 }
+
+ radiusAccClientInetAddressType OBJECT-TYPE
+ SYNTAX InetAddressType
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The type of address format used for the
+ radiusAccClientInetAddress object."
+ ::= { radiusAccClientExtEntry 2 }
+
+ radiusAccClientInetAddress OBJECT-TYPE
+ SYNTAX InetAddress
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The IP address of the RADIUS accounting
+ client referred to in this table entry, using
+ the IPv6 address format."
+ ::= { radiusAccClientExtEntry 3 }
+
+radiusAccClientExtID OBJECT-TYPE
+ SYNTAX SnmpAdminString
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The NAS-Identifier of the RADIUS accounting client
+ referred to in this table entry. This is not
+ necessarily the same as sysName in MIB II."
+ REFERENCE "RFC 2865 section 5.32"
+ ::= { radiusAccClientExtEntry 4 }
+
+-- Server Counters
+--
+-- Requests - DupRequests - BadAuthenticators - MalformedRequests -
+-- UnknownTypes - PacketsDropped - Responses = Pending
+--
+-- Requests - DupRequests - BadAuthenticators - MalformedRequests -
+-- UnknownTypes - PacketsDropped - NoRecords = entries logged
+
+radiusAccServExtPacketsDropped OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of incoming packets received from this
+ client and silently discarded for a reason other
+ than malformed, bad authenticators, or unknown types.
+ This counter may experience a discontinuity when the
+ RADIUS Accounting Server module within the managed
+ entity is reinitialized, as indicated by the current
+ value of radiusAccServerCounterDiscontinuity."
+ REFERENCE "RFC 2866 section 3"
+ ::= { radiusAccClientExtEntry 5 }
+
+radiusAccServExtRequests OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of packets received from this
+ client on the accounting port. This counter
+ may experience a discontinuity when the
+ RADIUS Accounting Server module within the
+ managed entity is reinitialized, as indicated by
+ the current value of
+ radiusAccServerCounterDiscontinuity."
+ REFERENCE "RFC 2866 section 4.1"
+ ::= { radiusAccClientExtEntry 6 }
+
+radiusAccServExtDupRequests OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of duplicate RADIUS Accounting-Request
+ packets received from this client. This counter
+ may experience a discontinuity when the RADIUS
+ Accounting Server module within the managed
+ entity is reinitialized, as indicated by the
+ current value of
+ radiusAccServerCounterDiscontinuity."
+ REFERENCE "RFC 2866 section 4.1"
+ ::= { radiusAccClientExtEntry 7 }
+
+radiusAccServExtResponses OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of RADIUS Accounting-Response packets
+ sent to this client. This counter may experience
+ a discontinuity when the RADIUS Accounting Server
+ module within the managed entity is reinitialized,
+ as indicated by the current value of
+ radiusAccServerCounterDiscontinuity."
+ REFERENCE "RFC 2866 section 4.2"
+ ::= { radiusAccClientExtEntry 8 }
+
+radiusAccServExtBadAuthenticators OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of RADIUS Accounting-Request packets
+ that contained invalid authenticators received
+ from this client. This counter may experience a
+ discontinuity when the RADIUS Accounting Server
+ module within the managed entity is reinitialized,
+ as indicated by the current value of
+ radiusAccServerCounterDiscontinuity."
+ REFERENCE "RFC 2866 section 3"
+ ::= { radiusAccClientExtEntry 9 }
+
+radiusAccServExtMalformedRequests OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of malformed RADIUS Accounting-Request
+ packets that were received from this client.
+ Bad authenticators and unknown types are not
+ included as malformed Accounting-Requests. This
+ counter may experience a discontinuity when the
+ RADIUS Accounting Server module within the managed
+ entity is reinitialized, as indicated by the current
+ value of radiusAccServerCounterDiscontinuity."
+ REFERENCE "RFC 2866 section 3"
+ ::= { radiusAccClientExtEntry 10 }
+
+radiusAccServExtNoRecords OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of RADIUS Accounting-Request packets
+ that were received and responded to but not
+ recorded. This counter may experience a
+ discontinuity when the RADIUS Accounting Server
+ module within the managed entity is reinitialized,
+ as indicated by the current value of
+ radiusAccServerCounterDiscontinuity."
+ ::= { radiusAccClientExtEntry 11 }
+
+radiusAccServExtUnknownTypes OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of RADIUS packets of unknown type that
+ were received from this client. This counter may
+ experience a discontinuity when the RADIUS Accounting
+ Server module within the managed entity is
+ reinitialized, as indicated by the current value of
+ radiusAccServerCounterDiscontinuity."
+ REFERENCE "RFC 2866 section 4"
+ ::= { radiusAccClientExtEntry 12 }
+
+radiusAccServerCounterDiscontinuity OBJECT-TYPE
+ SYNTAX TimeTicks
+ UNITS "centiseconds"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of centiseconds since the last
+ discontinuity in the RADIUS Accounting Server
+ counters. A discontinuity may be the result of
+ a reinitialization of the RADIUS Accounting Server
+ module within the managed entity."
+ ::= { radiusAccClientExtEntry 13 }
+
+
+-- conformance information
+
+radiusAccServMIBConformance OBJECT IDENTIFIER
+ ::= { radiusAccServMIB 2 }
+
+radiusAccServMIBCompliances OBJECT IDENTIFIER
+ ::= { radiusAccServMIBConformance 1 }
+
+radiusAccServMIBGroups OBJECT IDENTIFIER
+ ::= { radiusAccServMIBConformance 2 }
+
+
+-- compliance statements
+
+radiusAccServMIBCompliance MODULE-COMPLIANCE
+ STATUS deprecated
+ DESCRIPTION
+ "The compliance statement for accounting servers
+ implementing the RADIUS Accounting Server MIB.
+ Implementation of this module is for IPv4-only
+ entities, or for backwards compatibility use with
+ entities that support both IPv4 and IPv6."
+ MODULE -- this module
+ MANDATORY-GROUPS { radiusAccServMIBGroup }
+
+ OBJECT radiusAccServConfigReset
+ WRITE-SYNTAX INTEGER { reset(2) }
+ DESCRIPTION "The only SETable value is 'reset' (2)."
+
+ ::= { radiusAccServMIBCompliances 1 }
+
+radiusAccServExtMIBCompliance MODULE-COMPLIANCE
+ STATUS current
+ DESCRIPTION
+ "The compliance statement for accounting
+ servers implementing the RADIUS Accounting
+ Server IPv6 Extensions MIB. Implementation of
+ this module is for entities that support IPv6,
+ or support IPv4 and IPv6."
+ MODULE -- this module
+ MANDATORY-GROUPS { radiusAccServExtMIBGroup }
+
+ OBJECT radiusAccServConfigReset
+ WRITE-SYNTAX INTEGER { reset(2) }
+ DESCRIPTION "The only SETable value is 'reset' (2)."
+
+ OBJECT radiusAccClientInetAddressType
+ SYNTAX InetAddressType { ipv4(1), ipv6(2) }
+ DESCRIPTION
+ "An implementation is only required to support
+ IPv4 and globally unique IPv6 addresses."
+
+ OBJECT radiusAccClientInetAddress
+ SYNTAX InetAddress ( SIZE (4|16) )
+ DESCRIPTION
+ "An implementation is only required to support
+ IPv4 and globally unique IPv6 addresses."
+
+ ::= { radiusAccServMIBCompliances 2 }
+
+
+-- units of conformance
+
+radiusAccServMIBGroup OBJECT-GROUP
+ OBJECTS {radiusAccServIdent,
+ radiusAccServUpTime,
+ radiusAccServResetTime,
+ radiusAccServConfigReset,
+ radiusAccServTotalRequests,
+ radiusAccServTotalInvalidRequests,
+ radiusAccServTotalDupRequests,
+ radiusAccServTotalResponses,
+ radiusAccServTotalMalformedRequests,
+ radiusAccServTotalBadAuthenticators,
+ radiusAccServTotalPacketsDropped,
+ radiusAccServTotalNoRecords,
+ radiusAccServTotalUnknownTypes,
+ radiusAccClientAddress,
+ radiusAccClientID,
+ radiusAccServPacketsDropped,
+ radiusAccServRequests,
+ radiusAccServDupRequests,
+ radiusAccServResponses,
+ radiusAccServBadAuthenticators,
+ radiusAccServMalformedRequests,
+ radiusAccServNoRecords,
+ radiusAccServUnknownTypes
+ }
+ STATUS deprecated
+ DESCRIPTION
+ "The collection of objects providing management of
+ a RADIUS Accounting Server."
+ ::= { radiusAccServMIBGroups 1 }
+
+radiusAccServExtMIBGroup OBJECT-GROUP
+ OBJECTS {radiusAccServIdent,
+ radiusAccServUpTime,
+ radiusAccServResetTime,
+ radiusAccServConfigReset,
+ radiusAccServTotalRequests,
+ radiusAccServTotalInvalidRequests,
+ radiusAccServTotalDupRequests,
+ radiusAccServTotalResponses,
+ radiusAccServTotalMalformedRequests,
+ radiusAccServTotalBadAuthenticators,
+ radiusAccServTotalPacketsDropped,
+ radiusAccServTotalNoRecords,
+ radiusAccServTotalUnknownTypes,
+ radiusAccClientInetAddressType,
+ radiusAccClientInetAddress,
+ radiusAccClientExtID,
+ radiusAccServExtPacketsDropped,
+ radiusAccServExtRequests,
+ radiusAccServExtDupRequests,
+ radiusAccServExtResponses,
+ radiusAccServExtBadAuthenticators,
+ radiusAccServExtMalformedRequests,
+ radiusAccServExtNoRecords,
+ radiusAccServExtUnknownTypes,
+ radiusAccServerCounterDiscontinuity
+ }
+ STATUS current
+ DESCRIPTION
+ "The collection of objects providing management of
+ a RADIUS Accounting Server."
+ ::= { radiusAccServMIBGroups 2 }
+
+END
+
diff --git a/mibs/RADIUS-AUTH-CLIENT-MIB.mib b/mibs/RADIUS-AUTH-CLIENT-MIB.mib
new file mode 100644
index 0000000..0954c59
--- /dev/null
+++ b/mibs/RADIUS-AUTH-CLIENT-MIB.mib
@@ -0,0 +1,708 @@
+ RADIUS-AUTH-CLIENT-MIB DEFINITIONS ::= BEGIN
+
+ IMPORTS
+ MODULE-IDENTITY, OBJECT-TYPE, OBJECT-IDENTITY,
+ Counter32, Integer32, Gauge32,
+ IpAddress, TimeTicks, mib-2 FROM SNMPv2-SMI
+ SnmpAdminString FROM SNMP-FRAMEWORK-MIB
+ InetAddressType, InetAddress,
+ InetPortNumber FROM INET-ADDRESS-MIB
+ MODULE-COMPLIANCE, OBJECT-GROUP FROM SNMPv2-CONF;
+
+
+ radiusAuthClientMIB MODULE-IDENTITY
+ LAST-UPDATED "200608210000Z" -- 21 August 2006
+ ORGANIZATION "IETF RADIUS Extensions Working Group."
+ CONTACT-INFO
+ " Bernard Aboba
+ Microsoft
+ One Microsoft Way
+ Redmond, WA 98052
+ US
+ Phone: +1 425 936 6605
+ EMail: bernarda@microsoft.com"
+ DESCRIPTION
+ "The MIB module for entities implementing the client
+ side of the Remote Authentication Dial-In User Service
+ (RADIUS) authentication protocol. Copyright (C) The
+ Internet Society (2006). This version of this MIB
+ module is part of RFC 4668; see the RFC itself for
+ full legal notices."
+ REVISION "200608210000Z" -- 21 August 2006
+ DESCRIPTION
+ "Revised version as published in RFC 4668. This
+ version obsoletes that of RFC 2618 by deprecating
+ the MIB table containing IPv4-only address formats
+ and defining a new table to add support for version
+ neutral IP address formats. The remaining MIB objects
+ from RFC 2618 are carried forward into this version."
+ REVISION "199906110000Z" -- 11 Jun 1999
+ DESCRIPTION "Initial version as published in RFC 2618."
+ ::= { radiusAuthentication 2 }
+
+ radiusMIB OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The OID assigned to RADIUS MIB work by the IANA."
+ ::= { mib-2 67 }
+
+ radiusAuthentication OBJECT IDENTIFIER ::= {radiusMIB 1}
+
+ radiusAuthClientMIBObjects OBJECT IDENTIFIER
+ ::= { radiusAuthClientMIB 1 }
+
+ radiusAuthClient OBJECT IDENTIFIER
+ ::= { radiusAuthClientMIBObjects 1 }
+
+ radiusAuthClientInvalidServerAddresses OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of RADIUS Access-Response packets
+ received from unknown addresses."
+ ::= { radiusAuthClient 1 }
+
+ radiusAuthClientIdentifier OBJECT-TYPE
+ SYNTAX SnmpAdminString
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The NAS-Identifier of the RADIUS authentication client.
+ This is not necessarily the same as sysName in MIB II."
+ REFERENCE "RFC 2865 section 5.32"
+ ::= { radiusAuthClient 2 }
+
+ radiusAuthServerTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF RadiusAuthServerEntry
+ MAX-ACCESS not-accessible
+ STATUS deprecated
+ DESCRIPTION
+ "The (conceptual) table listing the RADIUS authentication
+ servers with which the client shares a secret."
+ ::= { radiusAuthClient 3 }
+
+ radiusAuthServerEntry OBJECT-TYPE
+ SYNTAX RadiusAuthServerEntry
+ MAX-ACCESS not-accessible
+ STATUS deprecated
+ DESCRIPTION
+ "An entry (conceptual row) representing a RADIUS
+ authentication server with which the client shares
+ a secret."
+ INDEX { radiusAuthServerIndex }
+ ::= { radiusAuthServerTable 1 }
+
+ RadiusAuthServerEntry ::= SEQUENCE {
+ radiusAuthServerIndex Integer32,
+ radiusAuthServerAddress IpAddress,
+ radiusAuthClientServerPortNumber Integer32,
+ radiusAuthClientRoundTripTime TimeTicks,
+ radiusAuthClientAccessRequests Counter32,
+ radiusAuthClientAccessRetransmissions Counter32,
+ radiusAuthClientAccessAccepts Counter32,
+ radiusAuthClientAccessRejects Counter32,
+ radiusAuthClientAccessChallenges Counter32,
+ radiusAuthClientMalformedAccessResponses Counter32,
+ radiusAuthClientBadAuthenticators Counter32,
+ radiusAuthClientPendingRequests Gauge32,
+ radiusAuthClientTimeouts Counter32,
+ radiusAuthClientUnknownTypes Counter32,
+ radiusAuthClientPacketsDropped Counter32
+ }
+
+ radiusAuthServerIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..2147483647)
+ MAX-ACCESS not-accessible
+ STATUS deprecated
+ DESCRIPTION
+ "A number uniquely identifying each RADIUS
+ Authentication server with which this client
+ communicates."
+ ::= { radiusAuthServerEntry 1 }
+
+ radiusAuthServerAddress OBJECT-TYPE
+ SYNTAX IpAddress
+ MAX-ACCESS read-only
+ STATUS deprecated
+ DESCRIPTION
+ "The IP address of the RADIUS authentication server
+ referred to in this table entry."
+ ::= { radiusAuthServerEntry 2 }
+
+ radiusAuthClientServerPortNumber OBJECT-TYPE
+ SYNTAX Integer32 (0..65535)
+ MAX-ACCESS read-only
+ STATUS deprecated
+ DESCRIPTION
+ "The UDP port the client is using to send requests to
+ this server."
+ REFERENCE "RFC 2865 section 3"
+ ::= { radiusAuthServerEntry 3 }
+
+ radiusAuthClientRoundTripTime OBJECT-TYPE
+ SYNTAX TimeTicks
+ MAX-ACCESS read-only
+ STATUS deprecated
+ DESCRIPTION
+ "The time interval (in hundredths of a second) between
+ the most recent Access-Reply/Access-Challenge and the
+ Access-Request that matched it from this RADIUS
+ authentication server."
+ ::= { radiusAuthServerEntry 4 }
+
+ -- Request/Response statistics
+ --
+ -- TotalIncomingPackets = Accepts + Rejects + Challenges +
+ -- UnknownTypes
+ --
+ -- TotalIncomingPackets - MalformedResponses -
+ -- BadAuthenticators - UnknownTypes - PacketsDropped =
+ -- Successfully received
+ --
+ -- AccessRequests + PendingRequests + ClientTimeouts =
+ -- Successfully received
+ --
+ --
+
+ radiusAuthClientAccessRequests OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS deprecated
+ DESCRIPTION
+ "The number of RADIUS Access-Request packets sent
+ to this server. This does not include retransmissions."
+ REFERENCE "RFC 2865 section 4.1"
+ ::= { radiusAuthServerEntry 5 }
+
+ radiusAuthClientAccessRetransmissions OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS deprecated
+ DESCRIPTION
+ "The number of RADIUS Access-Request packets
+ retransmitted to this RADIUS authentication server."
+ REFERENCE "RFC 2865 sections 2.5, 4.1"
+ ::= { radiusAuthServerEntry 6 }
+
+ radiusAuthClientAccessAccepts OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS deprecated
+ DESCRIPTION
+ "The number of RADIUS Access-Accept packets
+ (valid or invalid) received from this server."
+ REFERENCE "RFC 2865 section 4.2"
+ ::= { radiusAuthServerEntry 7 }
+
+ radiusAuthClientAccessRejects OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS deprecated
+ DESCRIPTION
+ "The number of RADIUS Access-Reject packets
+ (valid or invalid) received from this server."
+ REFERENCE "RFC 2865 section 4.3"
+ ::= { radiusAuthServerEntry 8 }
+ radiusAuthClientAccessChallenges OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS deprecated
+ DESCRIPTION
+ "The number of RADIUS Access-Challenge packets
+ (valid or invalid) received from this server."
+ REFERENCE "RFC 2865 section 4.4"
+ ::= { radiusAuthServerEntry 9 }
+
+ -- "Access-Response" includes an Access-Accept, Access-Challenge
+ -- or Access-Reject
+
+ radiusAuthClientMalformedAccessResponses OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS deprecated
+ DESCRIPTION
+ "The number of malformed RADIUS Access-Response
+ packets received from this server.
+ Malformed packets include packets with
+ an invalid length. Bad authenticators or
+ Message Authenticator attributes or unknown types
+ are not included as malformed access responses."
+ ::= { radiusAuthServerEntry 10 }
+
+ radiusAuthClientBadAuthenticators OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS deprecated
+ DESCRIPTION
+ "The number of RADIUS Access-Response packets
+ containing invalid authenticators or Message
+ Authenticator attributes received from this server."
+ REFERENCE "RFC 2865 section 3, RFC 2869 section 5.14"
+ ::= { radiusAuthServerEntry 11 }
+
+ radiusAuthClientPendingRequests OBJECT-TYPE
+ SYNTAX Gauge32
+ MAX-ACCESS read-only
+ STATUS deprecated
+ DESCRIPTION
+ "The number of RADIUS Access-Request packets
+ destined for this server that have not yet timed out
+ or received a response. This variable is incremented
+ when an Access-Request is sent and decremented due to
+ receipt of an Access-Accept, Access-Reject,
+ Access-Challenge, timeout, or retransmission."
+ REFERENCE "RFC 2865 section 2"
+ ::= { radiusAuthServerEntry 12 }
+
+ radiusAuthClientTimeouts OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "timeouts"
+ MAX-ACCESS read-only
+ STATUS deprecated
+ DESCRIPTION
+ "The number of authentication timeouts to this server.
+ After a timeout, the client may retry to the same
+ server, send to a different server, or
+ give up. A retry to the same server is counted as a
+ retransmit as well as a timeout. A send to a different
+ server is counted as a Request as well as a timeout."
+ REFERENCE "RFC 2865 section 2, RFC 2869 section 2.3.2"
+ ::= { radiusAuthServerEntry 13 }
+
+ radiusAuthClientUnknownTypes OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS deprecated
+ DESCRIPTION
+ "The number of RADIUS packets of unknown type that
+ were received from this server on the authentication
+ port."
+ ::= { radiusAuthServerEntry 14 }
+
+ radiusAuthClientPacketsDropped OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS deprecated
+ DESCRIPTION
+ "The number of RADIUS packets that were
+ received from this server on the authentication port
+ and dropped for some other reason."
+ ::= { radiusAuthServerEntry 15 }
+
+
+ -- New MIB Objects in this revision
+
+ radiusAuthServerExtTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF RadiusAuthServerExtEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The (conceptual) table listing the RADIUS authentication
+ servers with which the client shares a secret."
+ ::= { radiusAuthClient 4 }
+
+ radiusAuthServerExtEntry OBJECT-TYPE
+ SYNTAX RadiusAuthServerExtEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "An entry (conceptual row) representing a RADIUS
+ authentication server with which the client shares
+ a secret."
+ INDEX { radiusAuthServerExtIndex }
+ ::= { radiusAuthServerExtTable 1 }
+
+ RadiusAuthServerExtEntry ::= SEQUENCE {
+ radiusAuthServerExtIndex Integer32,
+ radiusAuthServerInetAddressType InetAddressType,
+ radiusAuthServerInetAddress InetAddress,
+ radiusAuthClientServerInetPortNumber InetPortNumber,
+ radiusAuthClientExtRoundTripTime TimeTicks,
+ radiusAuthClientExtAccessRequests Counter32,
+ radiusAuthClientExtAccessRetransmissions Counter32,
+ radiusAuthClientExtAccessAccepts Counter32,
+ radiusAuthClientExtAccessRejects Counter32,
+ radiusAuthClientExtAccessChallenges Counter32,
+ radiusAuthClientExtMalformedAccessResponses Counter32,
+ radiusAuthClientExtBadAuthenticators Counter32,
+ radiusAuthClientExtPendingRequests Gauge32,
+ radiusAuthClientExtTimeouts Counter32,
+ radiusAuthClientExtUnknownTypes Counter32,
+ radiusAuthClientExtPacketsDropped Counter32,
+ radiusAuthClientCounterDiscontinuity TimeTicks
+ }
+
+ radiusAuthServerExtIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..2147483647)
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A number uniquely identifying each RADIUS
+ Authentication server with which this client
+ communicates."
+ ::= { radiusAuthServerExtEntry 1 }
+ radiusAuthServerInetAddressType OBJECT-TYPE
+ SYNTAX InetAddressType
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The type of address format used for the
+ radiusAuthServerInetAddress object."
+ ::= { radiusAuthServerExtEntry 2 }
+
+ radiusAuthServerInetAddress OBJECT-TYPE
+ SYNTAX InetAddress
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The IP address of the RADIUS authentication
+ server referred to in this table entry, using
+ the version-neutral IP address format."
+ ::= { radiusAuthServerExtEntry 3 }
+
+ radiusAuthClientServerInetPortNumber OBJECT-TYPE
+ SYNTAX InetPortNumber ( 1..65535 )
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The UDP port the client is using to send requests
+ to this server. The value of zero (0) is invalid."
+ REFERENCE "RFC 2865 section 3"
+ ::= { radiusAuthServerExtEntry 4 }
+
+ radiusAuthClientExtRoundTripTime OBJECT-TYPE
+ SYNTAX TimeTicks
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The time interval (in hundredths of a second) between
+ the most recent Access-Reply/Access-Challenge and the
+ Access-Request that matched it from this RADIUS
+ authentication server."
+ REFERENCE "RFC 2865 section 2"
+ ::= { radiusAuthServerExtEntry 5 }
+
+ -- Request/Response statistics
+ --
+ -- TotalIncomingPackets = Accepts + Rejects + Challenges +
+ -- UnknownTypes
+ --
+ -- TotalIncomingPackets - MalformedResponses -
+ -- BadAuthenticators - UnknownTypes - PacketsDropped =
+ -- Successfully received
+ --
+ -- AccessRequests + PendingRequests + ClientTimeouts =
+ -- Successfully received
+ --
+ --
+
+ radiusAuthClientExtAccessRequests OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of RADIUS Access-Request packets sent
+ to this server. This does not include retransmissions.
+ This counter may experience a discontinuity when the
+ RADIUS Client module within the managed entity is
+ reinitialized, as indicated by the current value of
+ radiusAuthClientCounterDiscontinuity."
+ REFERENCE "RFC 2865 section 4.1"
+ ::= { radiusAuthServerExtEntry 6 }
+
+ radiusAuthClientExtAccessRetransmissions OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of RADIUS Access-Request packets
+ retransmitted to this RADIUS authentication server.
+ This counter may experience a discontinuity when
+ the RADIUS Client module within the managed entity
+ is reinitialized, as indicated by the current value
+ of radiusAuthClientCounterDiscontinuity."
+ REFERENCE "RFC 2865 sections 2.5, 4.1"
+ ::= { radiusAuthServerExtEntry 7 }
+
+ radiusAuthClientExtAccessAccepts OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of RADIUS Access-Accept packets
+ (valid or invalid) received from this server.
+ This counter may experience a discontinuity when
+ the RADIUS Client module within the managed entity
+ is reinitialized, as indicated by the current value
+ of radiusAuthClientCounterDiscontinuity."
+ REFERENCE "RFC 2865 section 4.2"
+ ::= { radiusAuthServerExtEntry 8 }
+
+ radiusAuthClientExtAccessRejects OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of RADIUS Access-Reject packets
+ (valid or invalid) received from this server.
+ This counter may experience a discontinuity when
+ the RADIUS Client module within the managed
+ entity is reinitialized, as indicated by the
+ current value of
+ radiusAuthClientCounterDiscontinuity."
+ REFERENCE "RFC 2865 section 4.3"
+ ::= { radiusAuthServerExtEntry 9 }
+
+ radiusAuthClientExtAccessChallenges OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of RADIUS Access-Challenge packets
+ (valid or invalid) received from this server.
+ This counter may experience a discontinuity when
+ the RADIUS Client module within the managed
+ entity is reinitialized, as indicated by the
+ current value of
+ radiusAuthClientCounterDiscontinuity."
+ REFERENCE "RFC 2865 section 4.4"
+ ::= { radiusAuthServerExtEntry 10 }
+
+ -- "Access-Response" includes an Access-Accept, Access-Challenge,
+ -- or Access-Reject
+
+ radiusAuthClientExtMalformedAccessResponses OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of malformed RADIUS Access-Response
+ packets received from this server.
+ Malformed packets include packets with
+ an invalid length. Bad authenticators or
+ Message Authenticator attributes or unknown types
+ are not included as malformed access responses.
+ This counter may experience a discontinuity when
+ the RADIUS Client module within the managed entity
+ is reinitialized, as indicated by the current value
+ of radiusAuthClientCounterDiscontinuity."
+ REFERENCE "RFC 2865 sections 3, 4"
+ ::= { radiusAuthServerExtEntry 11 }
+
+ radiusAuthClientExtBadAuthenticators OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of RADIUS Access-Response packets
+ containing invalid authenticators or Message
+ Authenticator attributes received from this server.
+ This counter may experience a discontinuity when
+ the RADIUS Client module within the managed entity
+ is reinitialized, as indicated by the current value
+ of radiusAuthClientCounterDiscontinuity."
+ REFERENCE "RFC 2865 section 3"
+ ::= { radiusAuthServerExtEntry 12 }
+
+ radiusAuthClientExtPendingRequests OBJECT-TYPE
+ SYNTAX Gauge32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of RADIUS Access-Request packets
+ destined for this server that have not yet timed out
+ or received a response. This variable is incremented
+ when an Access-Request is sent and decremented due to
+ receipt of an Access-Accept, Access-Reject,
+ Access-Challenge, timeout, or retransmission."
+ REFERENCE "RFC 2865 section 2"
+ ::= { radiusAuthServerExtEntry 13 }
+
+ radiusAuthClientExtTimeouts OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "timeouts"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of authentication timeouts to this server.
+ After a timeout, the client may retry to the same
+ server, send to a different server, or
+ give up. A retry to the same server is counted as a
+ retransmit as well as a timeout. A send to a different
+ server is counted as a Request as well as a timeout.
+ This counter may experience a discontinuity when the
+ RADIUS Client module within the managed entity is
+ reinitialized, as indicated by the current value of
+ radiusAuthClientCounterDiscontinuity."
+ REFERENCE "RFC 2865 sections 2.5, 4.1"
+ ::= { radiusAuthServerExtEntry 14 }
+
+ radiusAuthClientExtUnknownTypes OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of RADIUS packets of unknown type that
+ were received from this server on the authentication
+ port. This counter may experience a discontinuity
+ when the RADIUS Client module within the managed
+ entity is reinitialized, as indicated by the current
+ value of radiusAuthClientCounterDiscontinuity."
+ REFERENCE "RFC 2865 section 4"
+ ::= { radiusAuthServerExtEntry 15 }
+
+ radiusAuthClientExtPacketsDropped OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of RADIUS packets that were
+ received from this server on the authentication port
+ and dropped for some other reason. This counter may
+ experience a discontinuity when the RADIUS Client
+ module within the managed entity is reinitialized,
+ as indicated by the current value of
+ radiusAuthClientCounterDiscontinuity."
+ ::= { radiusAuthServerExtEntry 16 }
+
+ radiusAuthClientCounterDiscontinuity OBJECT-TYPE
+ SYNTAX TimeTicks
+ UNITS "centiseconds"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of centiseconds since the last discontinuity
+ in the RADIUS Client counters. A discontinuity may
+ be the result of a reinitialization of the RADIUS
+ Client module within the managed entity."
+ ::= { radiusAuthServerExtEntry 17 }
+
+
+ -- conformance information
+
+ radiusAuthClientMIBConformance OBJECT IDENTIFIER
+ ::= { radiusAuthClientMIB 2 }
+
+ radiusAuthClientMIBCompliances OBJECT IDENTIFIER
+ ::= { radiusAuthClientMIBConformance 1 }
+
+ radiusAuthClientMIBGroups OBJECT IDENTIFIER
+ ::= { radiusAuthClientMIBConformance 2 }
+
+
+ -- compliance statements
+
+ radiusAuthClientMIBCompliance MODULE-COMPLIANCE
+ STATUS deprecated
+ DESCRIPTION
+ "The compliance statement for authentication clients
+ implementing the RADIUS Authentication Client MIB.
+ Implementation of this module is for IPv4-only
+ entities, or for backwards compatibility use with
+ entities that support both IPv4 and IPv6."
+ MODULE -- this module
+ MANDATORY-GROUPS { radiusAuthClientMIBGroup }
+
+ ::= { radiusAuthClientMIBCompliances 1 }
+
+ radiusAuthClientExtMIBCompliance MODULE-COMPLIANCE
+ STATUS current
+ DESCRIPTION
+ "The compliance statement for authentication
+ clients implementing the RADIUS Authentication
+ Client IPv6 Extensions MIB. Implementation of
+ this module is for entities that support IPv6,
+ or support IPv4 and IPv6."
+ MODULE -- this module
+ MANDATORY-GROUPS { radiusAuthClientExtMIBGroup }
+
+ OBJECT radiusAuthServerInetAddressType
+ SYNTAX InetAddressType { ipv4(1), ipv6(2) }
+ DESCRIPTION
+ "An implementation is only required to support
+ IPv4 and globally unique IPv6 addresses."
+
+ OBJECT radiusAuthServerInetAddress
+ SYNTAX InetAddress ( SIZE (4|16) )
+ DESCRIPTION
+ "An implementation is only required to support
+ IPv4 and globally unique IPv6 addresses."
+ ::= { radiusAuthClientMIBCompliances 2 }
+
+
+ -- units of conformance
+
+ radiusAuthClientMIBGroup OBJECT-GROUP
+ OBJECTS { radiusAuthClientIdentifier,
+ radiusAuthClientInvalidServerAddresses,
+ radiusAuthServerAddress,
+ radiusAuthClientServerPortNumber,
+ radiusAuthClientRoundTripTime,
+ radiusAuthClientAccessRequests,
+ radiusAuthClientAccessRetransmissions,
+ radiusAuthClientAccessAccepts,
+ radiusAuthClientAccessRejects,
+ radiusAuthClientAccessChallenges,
+ radiusAuthClientMalformedAccessResponses,
+ radiusAuthClientBadAuthenticators,
+ radiusAuthClientPendingRequests,
+ radiusAuthClientTimeouts,
+ radiusAuthClientUnknownTypes,
+ radiusAuthClientPacketsDropped
+ }
+ STATUS deprecated
+ DESCRIPTION
+ "The basic collection of objects providing management of
+ RADIUS Authentication Clients."
+ ::= { radiusAuthClientMIBGroups 1 }
+
+
+ radiusAuthClientExtMIBGroup OBJECT-GROUP
+ OBJECTS { radiusAuthClientIdentifier,
+ radiusAuthClientInvalidServerAddresses,
+ radiusAuthServerInetAddressType,
+ radiusAuthServerInetAddress,
+ radiusAuthClientServerInetPortNumber,
+ radiusAuthClientExtRoundTripTime,
+ radiusAuthClientExtAccessRequests,
+ radiusAuthClientExtAccessRetransmissions,
+ radiusAuthClientExtAccessAccepts,
+ radiusAuthClientExtAccessRejects,
+ radiusAuthClientExtAccessChallenges,
+ radiusAuthClientExtMalformedAccessResponses,
+ radiusAuthClientExtBadAuthenticators,
+ radiusAuthClientExtPendingRequests,
+ radiusAuthClientExtTimeouts,
+ radiusAuthClientExtUnknownTypes,
+ radiusAuthClientExtPacketsDropped,
+ radiusAuthClientCounterDiscontinuity
+ }
+ STATUS current
+ DESCRIPTION
+ "The collection of extended objects providing
+ management of RADIUS Authentication Clients
+ using version-neutral IP address format."
+ ::= { radiusAuthClientMIBGroups 2 }
+
+ END
diff --git a/mibs/RADIUS-AUTH-SERVER-MIB.mib b/mibs/RADIUS-AUTH-SERVER-MIB.mib
new file mode 100644
index 0000000..d54aa20
--- /dev/null
+++ b/mibs/RADIUS-AUTH-SERVER-MIB.mib
@@ -0,0 +1,775 @@
+RADIUS-AUTH-SERVER-MIB DEFINITIONS ::= BEGIN
+
+IMPORTS
+ MODULE-IDENTITY, OBJECT-TYPE, OBJECT-IDENTITY,
+ Counter32, Integer32,
+ IpAddress, TimeTicks, mib-2 FROM SNMPv2-SMI
+ SnmpAdminString FROM SNMP-FRAMEWORK-MIB
+ InetAddressType, InetAddress FROM INET-ADDRESS-MIB
+ MODULE-COMPLIANCE, OBJECT-GROUP FROM SNMPv2-CONF;
+
+radiusAuthServMIB MODULE-IDENTITY
+ LAST-UPDATED "200608210000Z" -- 21 August 2006
+ ORGANIZATION "IETF RADIUS Extensions Working Group."
+ CONTACT-INFO
+ " Bernard Aboba
+ Microsoft
+ One Microsoft Way
+ Redmond, WA 98052
+ US
+ Phone: +1 425 936 6605
+ EMail: bernarda@microsoft.com"
+ DESCRIPTION
+ "The MIB module for entities implementing the server
+ side of the Remote Authentication Dial-In User
+ Service (RADIUS) authentication protocol. Copyright
+ (C) The Internet Society (2006). This version of this
+ MIB module is part of RFC 4669; see the RFC itself for
+ full legal notices."
+ REVISION "200608210000Z" -- 21 August 2006
+ DESCRIPTION
+ "Revised version as published in RFC 4669. This
+ version obsoletes that of RFC 2619 by deprecating the
+ MIB table containing IPv4-only address formats and
+ defining a new table to add support for version-neutral
+ IP address formats. The remaining MIB objects from RFC
+ 2619 are carried forward into this version."
+ REVISION "199906110000Z" -- 11 Jun 1999
+ DESCRIPTION "Initial version as published in RFC 2619."
+ ::= { radiusAuthentication 1 }
+
+radiusMIB OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The OID assigned to RADIUS MIB work by the IANA."
+ ::= { mib-2 67 }
+
+radiusAuthentication OBJECT IDENTIFIER ::= {radiusMIB 1}
+
+radiusAuthServMIBObjects OBJECT IDENTIFIER
+ ::= { radiusAuthServMIB 1 }
+
+radiusAuthServ OBJECT IDENTIFIER
+ ::= { radiusAuthServMIBObjects 1 }
+
+radiusAuthServIdent OBJECT-TYPE
+ SYNTAX SnmpAdminString
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The implementation identification string for the
+ RADIUS authentication server software in use on the
+ system, for example, 'FNS-2.1'."
+ ::= {radiusAuthServ 1}
+
+radiusAuthServUpTime OBJECT-TYPE
+ SYNTAX TimeTicks
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "If the server has a persistent state (e.g., a
+ process), this value will be the time elapsed (in
+ hundredths of a second) since the server process
+ was started. For software without persistent state,
+ this value will be zero."
+ ::= {radiusAuthServ 2}
+
+radiusAuthServResetTime OBJECT-TYPE
+ SYNTAX TimeTicks
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "If the server has a persistent state (e.g., a process)
+ and supports a 'reset' operation (e.g., can be told to
+ re-read configuration files), this value will be the
+ time elapsed (in hundredths of a second) since the
+ server was 'reset.' For software that does not
+ have persistence or does not support a 'reset'
+ operation, this value will be zero."
+ ::= {radiusAuthServ 3}
+
+radiusAuthServConfigReset OBJECT-TYPE
+ SYNTAX INTEGER { other(1),
+ reset(2),
+ initializing(3),
+ running(4)}
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "Status/action object to reinitialize any persistent
+ server state. When set to reset(2), any persistent
+ server state (such as a process) is reinitialized as
+ if the server had just been started. This value will
+ never be returned by a read operation. When read,
+ one of the following values will be returned:
+ other(1) - server in some unknown state;
+ initializing(3) - server (re)initializing;
+ running(4) - server currently running."
+ ::= {radiusAuthServ 4}
+
+radiusAuthServTotalAccessRequests OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of packets received on the
+ authentication port."
+ REFERENCE "RFC 2865 section 4.1"
+ ::= { radiusAuthServ 5}
+
+radiusAuthServTotalInvalidRequests OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of RADIUS Access-Request packets
+ received from unknown addresses."
+ REFERENCE "RFC 2865 section 4.1"
+ ::= { radiusAuthServ 6 }
+
+radiusAuthServTotalDupAccessRequests OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of duplicate RADIUS Access-Request
+ packets received."
+ REFERENCE "RFC 2865 section 4.1"
+ ::= { radiusAuthServ 7 }
+
+radiusAuthServTotalAccessAccepts OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of RADIUS Access-Accept packets sent."
+ REFERENCE "RFC 2865 section 4.2"
+ ::= { radiusAuthServ 8 }
+
+radiusAuthServTotalAccessRejects OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of RADIUS Access-Reject packets sent."
+ REFERENCE "RFC 2865 section 4.3"
+ ::= { radiusAuthServ 9 }
+
+radiusAuthServTotalAccessChallenges OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of RADIUS Access-Challenge packets sent."
+ REFERENCE "RFC 2865 section 4.4"
+ ::= { radiusAuthServ 10 }
+
+radiusAuthServTotalMalformedAccessRequests OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of malformed RADIUS Access-Request
+ packets received. Bad authenticators
+ and unknown types are not included as
+ malformed Access-Requests."
+ REFERENCE "RFC 2865 section 4.1"
+ ::= { radiusAuthServ 11 }
+
+radiusAuthServTotalBadAuthenticators OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of RADIUS Authentication-Request packets
+ that contained invalid Message Authenticator
+ attributes received."
+ REFERENCE "RFC 2865 section 3"
+ ::= { radiusAuthServ 12 }
+
+radiusAuthServTotalPacketsDropped OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of incoming packets
+ silently discarded for some reason other
+ than malformed, bad authenticators or
+ unknown types."
+ REFERENCE "RFC 2865 section 3"
+ ::= { radiusAuthServ 13 }
+
+radiusAuthServTotalUnknownTypes OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of RADIUS packets of unknown type that
+ were received."
+ REFERENCE "RFC 2865 section 4"
+ ::= { radiusAuthServ 14 }
+
+
+radiusAuthClientTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF RadiusAuthClientEntry
+ MAX-ACCESS not-accessible
+ STATUS deprecated
+ DESCRIPTION
+ "The (conceptual) table listing the RADIUS
+ authentication clients with which the server shares
+ a secret."
+ ::= { radiusAuthServ 15 }
+
+
+radiusAuthClientEntry OBJECT-TYPE
+ SYNTAX RadiusAuthClientEntry
+ MAX-ACCESS not-accessible
+ STATUS deprecated
+ DESCRIPTION
+ "An entry (conceptual row) representing a RADIUS
+ authentication client with which the server shares a
+ secret."
+ INDEX { radiusAuthClientIndex }
+ ::= { radiusAuthClientTable 1 }
+
+RadiusAuthClientEntry ::= SEQUENCE {
+ radiusAuthClientIndex Integer32,
+ radiusAuthClientAddress IpAddress,
+ radiusAuthClientID SnmpAdminString,
+ radiusAuthServAccessRequests Counter32,
+ radiusAuthServDupAccessRequests Counter32,
+ radiusAuthServAccessAccepts Counter32,
+ radiusAuthServAccessRejects Counter32,
+ radiusAuthServAccessChallenges Counter32,
+ radiusAuthServMalformedAccessRequests Counter32,
+ radiusAuthServBadAuthenticators Counter32,
+ radiusAuthServPacketsDropped Counter32,
+ radiusAuthServUnknownTypes Counter32
+}
+
+radiusAuthClientIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..2147483647)
+ MAX-ACCESS not-accessible
+ STATUS deprecated
+ DESCRIPTION
+ "A number uniquely identifying each RADIUS
+ authentication client with which this server
+ communicates."
+ ::= { radiusAuthClientEntry 1 }
+
+radiusAuthClientAddress OBJECT-TYPE
+ SYNTAX IpAddress
+ MAX-ACCESS read-only
+ STATUS deprecated
+ DESCRIPTION
+ "The NAS-IP-Address of the RADIUS authentication client
+ referred to in this table entry."
+ REFERENCE "RFC 2865 section 2"
+ ::= { radiusAuthClientEntry 2 }
+
+radiusAuthClientID OBJECT-TYPE
+ SYNTAX SnmpAdminString
+ MAX-ACCESS read-only
+ STATUS deprecated
+ DESCRIPTION
+ "The NAS-Identifier of the RADIUS authentication client
+ referred to in this table entry. This is not
+ necessarily the same as sysName in MIB II."
+ REFERENCE "RFC 2865 section 5.32"
+ ::= { radiusAuthClientEntry 3 }
+
+-- Server Counters
+
+--
+-- Responses = AccessAccepts + AccessRejects + AccessChallenges
+--
+-- Requests - DupRequests - BadAuthenticators - MalformedRequests -
+-- UnknownTypes - PacketsDropped - Responses = Pending
+--
+-- Requests - DupRequests - BadAuthenticators - MalformedRequests -
+-- UnknownTypes - PacketsDropped = entries logged
+
+radiusAuthServAccessRequests OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS deprecated
+ DESCRIPTION
+ "The number of packets received on the authentication
+ port from this client."
+ REFERENCE "RFC 2865 section 4.1"
+ ::= { radiusAuthClientEntry 4 }
+
+radiusAuthServDupAccessRequests OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS deprecated
+ DESCRIPTION
+ "The number of duplicate RADIUS Access-Request
+ packets received from this client."
+ REFERENCE "RFC 2865 section 4.1"
+ ::= { radiusAuthClientEntry 5 }
+
+radiusAuthServAccessAccepts OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS deprecated
+ DESCRIPTION
+ "The number of RADIUS Access-Accept packets
+ sent to this client."
+ REFERENCE "RFC 2865 section 4.2"
+ ::= { radiusAuthClientEntry 6 }
+
+radiusAuthServAccessRejects OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS deprecated
+ DESCRIPTION
+ "The number of RADIUS Access-Reject packets
+ sent to this client."
+ REFERENCE "RFC 2865 section 4.3"
+ ::= { radiusAuthClientEntry 7 }
+
+radiusAuthServAccessChallenges OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS deprecated
+ DESCRIPTION
+ "The number of RADIUS Access-Challenge packets
+ sent to this client."
+ REFERENCE "RFC 2865 section 4.4"
+ ::= { radiusAuthClientEntry 8 }
+
+radiusAuthServMalformedAccessRequests OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS deprecated
+ DESCRIPTION
+ "The number of malformed RADIUS Access-Request
+ packets received from this client.
+ Bad authenticators and unknown types are not included
+ as malformed Access-Requests."
+ REFERENCE "RFC 2865 section 3"
+ ::= { radiusAuthClientEntry 9 }
+
+radiusAuthServBadAuthenticators OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS deprecated
+ DESCRIPTION
+ "The number of RADIUS Authentication-Request packets
+ that contained invalid Message Authenticator
+ attributes received from this client."
+ REFERENCE "RFC 2865 section 3"
+ ::= { radiusAuthClientEntry 10 }
+
+radiusAuthServPacketsDropped OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS deprecated
+ DESCRIPTION
+ "The number of incoming packets from this
+ client silently discarded for some reason other
+ than malformed, bad authenticators or
+ unknown types."
+ REFERENCE "RFC 2865 section 3"
+ ::= { radiusAuthClientEntry 11 }
+
+radiusAuthServUnknownTypes OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS deprecated
+ DESCRIPTION
+ "The number of RADIUS packets of unknown type that
+ were received from this client."
+ REFERENCE "RFC 2865 section 4"
+ ::= { radiusAuthClientEntry 12 }
+
+radiusAuthClientExtTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF RadiusAuthClientExtEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The (conceptual) table listing the RADIUS
+ authentication clients with which the server shares
+ a secret."
+ ::= { radiusAuthServ 16 }
+
+radiusAuthClientExtEntry OBJECT-TYPE
+ SYNTAX RadiusAuthClientExtEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "An entry (conceptual row) representing a RADIUS
+ authentication client with which the server shares a
+ secret."
+ INDEX { radiusAuthClientExtIndex }
+ ::= { radiusAuthClientExtTable 1 }
+
+RadiusAuthClientExtEntry ::= SEQUENCE {
+ radiusAuthClientExtIndex Integer32,
+ radiusAuthClientInetAddressType InetAddressType,
+ radiusAuthClientInetAddress InetAddress,
+ radiusAuthClientExtID SnmpAdminString,
+ radiusAuthServExtAccessRequests Counter32,
+ radiusAuthServExtDupAccessRequests Counter32,
+ radiusAuthServExtAccessAccepts Counter32,
+ radiusAuthServExtAccessRejects Counter32,
+ radiusAuthServExtAccessChallenges Counter32,
+ radiusAuthServExtMalformedAccessRequests Counter32,
+ radiusAuthServExtBadAuthenticators Counter32,
+ radiusAuthServExtPacketsDropped Counter32,
+ radiusAuthServExtUnknownTypes Counter32,
+ radiusAuthServCounterDiscontinuity TimeTicks
+}
+
+radiusAuthClientExtIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..2147483647)
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A number uniquely identifying each RADIUS
+ authentication client with which this server
+ communicates."
+ ::= { radiusAuthClientExtEntry 1 }
+
+radiusAuthClientInetAddressType OBJECT-TYPE
+ SYNTAX InetAddressType
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The type of address format used for the
+ radiusAuthClientInetAddress object."
+ ::= { radiusAuthClientExtEntry 2 }
+
+ radiusAuthClientInetAddress OBJECT-TYPE
+ SYNTAX InetAddress
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The IP address of the RADIUS authentication
+ client referred to in this table entry, using
+ the version-neutral IP address format."
+ ::= { radiusAuthClientExtEntry 3 }
+
+
+radiusAuthClientExtID OBJECT-TYPE
+ SYNTAX SnmpAdminString
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The NAS-Identifier of the RADIUS authentication client
+ referred to in this table entry. This is not
+ necessarily the same as sysName in MIB II."
+ REFERENCE "RFC 2865 section 5.32"
+ ::= { radiusAuthClientExtEntry 4 }
+
+-- Server Counters
+
+--
+-- Responses = AccessAccepts + AccessRejects + AccessChallenges
+--
+-- Requests - DupRequests - BadAuthenticators - MalformedRequests -
+-- UnknownTypes - PacketsDropped - Responses = Pending
+--
+-- Requests - DupRequests - BadAuthenticators - MalformedRequests -
+-- UnknownTypes - PacketsDropped = entries logged
+
+radiusAuthServExtAccessRequests OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of packets received on the authentication
+ port from this client. This counter may experience a
+ discontinuity when the RADIUS Server module within the
+ managed entity is reinitialized, as indicated by the
+ current value of radiusAuthServCounterDiscontinuity."
+ REFERENCE "RFC 2865 section 4.1"
+ ::= { radiusAuthClientExtEntry 5 }
+
+radiusAuthServExtDupAccessRequests OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of duplicate RADIUS Access-Request
+ packets received from this client. This counter may
+ experience a discontinuity when the RADIUS Server
+ module within the managed entity is reinitialized, as
+ indicated by the current value of
+ radiusAuthServCounterDiscontinuity."
+ REFERENCE "RFC 2865 section 4.1"
+ ::= { radiusAuthClientExtEntry 6 }
+
+radiusAuthServExtAccessAccepts OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of RADIUS Access-Accept packets
+ sent to this client. This counter may experience a
+ discontinuity when the RADIUS Server module within the
+ managed entity is reinitialized, as indicated by the
+ current value of radiusAuthServCounterDiscontinuity."
+ REFERENCE "RFC 2865 section 4.2"
+ ::= { radiusAuthClientExtEntry 7 }
+
+radiusAuthServExtAccessRejects OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of RADIUS Access-Reject packets
+ sent to this client. This counter may experience a
+ discontinuity when the RADIUS Server module within the
+ managed entity is reinitialized, as indicated by the
+ current value of radiusAuthServCounterDiscontinuity."
+ REFERENCE "RFC 2865 section 4.3"
+ ::= { radiusAuthClientExtEntry 8 }
+
+radiusAuthServExtAccessChallenges OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of RADIUS Access-Challenge packets
+ sent to this client. This counter may experience a
+ discontinuity when the RADIUS Server module within the
+ managed entity is reinitialized, as indicated by the
+ current value of radiusAuthServCounterDiscontinuity."
+ REFERENCE "RFC 2865 section 4.4"
+ ::= { radiusAuthClientExtEntry 9 }
+
+radiusAuthServExtMalformedAccessRequests OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of malformed RADIUS Access-Request
+ packets received from this client. Bad authenticators
+ and unknown types are not included as malformed
+ Access-Requests. This counter may experience a
+ discontinuity when the RADIUS Server module within the
+ managed entity is reinitialized, as indicated by the
+ current value of radiusAuthServCounterDiscontinuity."
+ REFERENCE "RFC 2865 sections 3, 4.1"
+ ::= { radiusAuthClientExtEntry 10 }
+
+radiusAuthServExtBadAuthenticators OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of RADIUS Authentication-Request packets
+ that contained invalid Message Authenticator
+ attributes received from this client. This counter
+ may experience a discontinuity when the RADIUS Server
+ module within the managed entity is reinitialized, as
+ indicated by the current value of
+ radiusAuthServCounterDiscontinuity."
+ REFERENCE "RFC 2865 section 3"
+ ::= { radiusAuthClientExtEntry 11 }
+
+radiusAuthServExtPacketsDropped OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of incoming packets from this client
+ silently discarded for some reason other than
+ malformed, bad authenticators or unknown types.
+ This counter may experience a discontinuity when the
+ RADIUS Server module within the managed entity is
+ reinitialized, as indicated by the current value of
+ radiusAuthServCounterDiscontinuity."
+ REFERENCE "RFC 2865 section 3"
+ ::= { radiusAuthClientExtEntry 12 }
+
+radiusAuthServExtUnknownTypes OBJECT-TYPE
+ SYNTAX Counter32
+ UNITS "packets"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of RADIUS packets of unknown type that
+ were received from this client. This counter may
+ experience a discontinuity when the RADIUS Server
+ module within the managed entity is reinitialized, as
+ indicated by the current value of
+ radiusAuthServCounterDiscontinuity."
+ REFERENCE "RFC 2865 section 4"
+ ::= { radiusAuthClientExtEntry 13 }
+
+radiusAuthServCounterDiscontinuity OBJECT-TYPE
+ SYNTAX TimeTicks
+ UNITS "centiseconds"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of centiseconds since the last
+ discontinuity in the RADIUS Server counters.
+ A discontinuity may be the result of a
+ reinitialization of the RADIUS Server module
+ within the managed entity."
+ ::= { radiusAuthClientExtEntry 14 }
+
+-- conformance information
+
+radiusAuthServMIBConformance OBJECT IDENTIFIER
+ ::= { radiusAuthServMIB 2 }
+
+radiusAuthServMIBCompliances OBJECT IDENTIFIER
+ ::= { radiusAuthServMIBConformance 1 }
+
+radiusAuthServMIBGroups OBJECT IDENTIFIER
+ ::= { radiusAuthServMIBConformance 2 }
+
+-- compliance statements
+
+radiusAuthServMIBCompliance MODULE-COMPLIANCE
+ STATUS deprecated
+ DESCRIPTION
+ "The compliance statement for authentication
+ servers implementing the RADIUS Authentication
+ Server MIB. Implementation of this module is for
+ IPv4-only entities, or for backwards compatibility
+ use with entities that support both IPv4 and
+ IPv6."
+ MODULE -- this module
+ MANDATORY-GROUPS { radiusAuthServMIBGroup }
+
+ OBJECT radiusAuthServConfigReset
+ WRITE-SYNTAX INTEGER { reset(2) }
+ DESCRIPTION "The only SETable value is 'reset' (2)."
+
+ ::= { radiusAuthServMIBCompliances 1 }
+
+
+radiusAuthServMIBExtCompliance MODULE-COMPLIANCE
+ STATUS current
+ DESCRIPTION
+ "The compliance statement for authentication
+ servers implementing the RADIUS Authentication
+ Server IPv6 Extensions MIB. Implementation of
+ this module is for entities that support IPv6,
+ or support IPv4 and IPv6."
+ MODULE -- this module
+ MANDATORY-GROUPS { radiusAuthServExtMIBGroup }
+
+ OBJECT radiusAuthServConfigReset
+ WRITE-SYNTAX INTEGER { reset(2) }
+ DESCRIPTION "The only SETable value is 'reset' (2)."
+
+ OBJECT radiusAuthClientInetAddressType
+ SYNTAX InetAddressType { ipv4(1), ipv6(2) }
+ DESCRIPTION
+ "An implementation is only required to support
+ IPv4 and globally unique IPv6 addresses."
+
+ OBJECT radiusAuthClientInetAddress
+ SYNTAX InetAddress ( SIZE (4|16) )
+ DESCRIPTION
+ "An implementation is only required to support
+ IPv4 and globally unique IPv6 addresses."
+
+ ::= { radiusAuthServMIBCompliances 2 }
+
+
+-- units of conformance
+
+radiusAuthServMIBGroup OBJECT-GROUP
+ OBJECTS {radiusAuthServIdent,
+ radiusAuthServUpTime,
+ radiusAuthServResetTime,
+ radiusAuthServConfigReset,
+ radiusAuthServTotalAccessRequests,
+ radiusAuthServTotalInvalidRequests,
+ radiusAuthServTotalDupAccessRequests,
+ radiusAuthServTotalAccessAccepts,
+ radiusAuthServTotalAccessRejects,
+ radiusAuthServTotalAccessChallenges,
+ radiusAuthServTotalMalformedAccessRequests,
+ radiusAuthServTotalBadAuthenticators,
+ radiusAuthServTotalPacketsDropped,
+ radiusAuthServTotalUnknownTypes,
+ radiusAuthClientAddress,
+ radiusAuthClientID,
+ radiusAuthServAccessRequests,
+ radiusAuthServDupAccessRequests,
+ radiusAuthServAccessAccepts,
+ radiusAuthServAccessRejects,
+ radiusAuthServAccessChallenges,
+ radiusAuthServMalformedAccessRequests,
+ radiusAuthServBadAuthenticators,
+ radiusAuthServPacketsDropped,
+ radiusAuthServUnknownTypes
+ }
+ STATUS deprecated
+ DESCRIPTION
+ "The collection of objects providing management of
+ a RADIUS Authentication Server."
+ ::= { radiusAuthServMIBGroups 1 }
+
+radiusAuthServExtMIBGroup OBJECT-GROUP
+ OBJECTS {radiusAuthServIdent,
+ radiusAuthServUpTime,
+ radiusAuthServResetTime,
+ radiusAuthServConfigReset,
+ radiusAuthServTotalAccessRequests,
+ radiusAuthServTotalInvalidRequests,
+ radiusAuthServTotalDupAccessRequests,
+ radiusAuthServTotalAccessAccepts,
+ radiusAuthServTotalAccessRejects,
+ radiusAuthServTotalAccessChallenges,
+ radiusAuthServTotalMalformedAccessRequests,
+ radiusAuthServTotalBadAuthenticators,
+ radiusAuthServTotalPacketsDropped,
+ radiusAuthServTotalUnknownTypes,
+ radiusAuthClientInetAddressType,
+ radiusAuthClientInetAddress,
+ radiusAuthClientExtID,
+ radiusAuthServExtAccessRequests,
+ radiusAuthServExtDupAccessRequests,
+ radiusAuthServExtAccessAccepts,
+ radiusAuthServExtAccessRejects,
+ radiusAuthServExtAccessChallenges,
+ radiusAuthServExtMalformedAccessRequests,
+ radiusAuthServExtBadAuthenticators,
+ radiusAuthServExtPacketsDropped,
+ radiusAuthServExtUnknownTypes,
+ radiusAuthServCounterDiscontinuity
+ }
+ STATUS current
+ DESCRIPTION
+ "The collection of objects providing management of
+ a RADIUS Authentication Server."
+ ::= { radiusAuthServMIBGroups 2 }
+
+END
diff --git a/mibs/RADIUS-STAT-MIB.mib b/mibs/RADIUS-STAT-MIB.mib
new file mode 100644
index 0000000..35bf00b
--- /dev/null
+++ b/mibs/RADIUS-STAT-MIB.mib
@@ -0,0 +1,349 @@
+RADIUS-STAT-MIB DEFINITIONS ::= BEGIN
+
+IMPORTS
+ MODULE-IDENTITY, OBJECT-TYPE, OBJECT-IDENTITY,
+ Counter32, Integer32,
+ IpAddress, TimeTicks, mib-2 FROM SNMPv2-SMI
+ SnmpAdminString FROM SNMP-FRAMEWORK-MIB;
+
+radiusStatMIB MODULE-IDENTITY
+ LAST-UPDATED "0001020000Z"
+ ORGANIZATION "IETF RADIUS Working Group."
+ CONTACT-INFO
+ " Sergey Poznyakoff
+ email: gray@farlep.net"
+ DESCRIPTION
+ "The MIB module for entities implementing the statistics
+ side of the Remote Access Dialin User Service (RADIUS)
+ authentication protocol."
+ REVISION "0001020000Z"
+ DESCRIPTION "Experimental Version"
+ ::= { radiusStatistics 1 }
+
+radiusMIB OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The OID assigned to RADIUS MIB work by the IANA."
+ ::= { mib-2 67 }
+
+radiusStatistics OBJECT IDENTIFIER ::= {radiusMIB 3}
+
+radiusStatIdent OBJECT-TYPE
+ SYNTAX SnmpAdminString
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The implementation identification string for the
+ RADIUS statistics server software in use on the
+ system"
+ ::= {radiusStatMIB 1}
+
+radiusStatUpTime OBJECT-TYPE
+ SYNTAX TimeTicks
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Time (in hundredths of a second) since the statistics
+ was started."
+ ::= {radiusStatMIB 2}
+
+radiusStatConfigReset OBJECT-TYPE
+ SYNTAX INTEGER { other(1),
+ reset(2),
+ initializing(3),
+ running(4)}
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "Status/action object to reinitialize any persistent
+ server state. When set to reset(2), any persistent
+ server state (such as a process) is reinitialized as if
+ the server had just been started. This value will
+ never be returned by a read operation. When read, one of
+ the following values will be returned:
+ other(1) - server in some unknown state;
+ initializing(3) - server (re)initializing;
+ running(4) - server currently running."
+ ::= {radiusStatMIB 3}
+
+radiusStatTotalLines OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of dialup lines registered by the statistics
+ module"
+ ::= { radiusStatMIB 4}
+
+radiusStatTotalLinesInUse OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number dial-up lines currently in use"
+ ::= { radiusStatMIB 5 }
+
+radiusStatTotalLinesIdle OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number dial-up lines currently idle"
+ ::= { radiusStatMIB 6 }
+
+radiusStatNASTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF RadiusStatNASEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The (conceptual) table listing the available
+ Network Access Servers"
+ ::= { radiusStatMIB 7 }
+
+radiusStatNASEntry OBJECT-TYPE
+ SYNTAX RadiusStatNASEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "An entry (conceptual row) representing a Network
+ Access Server"
+ INDEX { nasIndex }
+ ::= { radiusStatNASTable 1 }
+
+RadiusStatNASEntry ::= SEQUENCE {
+ nasIndex Integer32,
+ nasAddress IpAddress,
+ nasID SnmpAdminString,
+ nasLines Counter32,
+ nasLinesInUse Counter32,
+ nasLinesIdle Counter32,
+}
+
+nasIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..2147483647)
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A number uniquely identifying each NAS"
+ ::= { radiusStatNASEntry 1 }
+
+nasAddress OBJECT-TYPE
+ SYNTAX IpAddress
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The NAS-IP-Address"
+ ::= { radiusStatNASEntry 2 }
+
+nasID OBJECT-TYPE
+ SYNTAX SnmpAdminString
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The NAS-Identifier"
+ ::= { radiusStatNASEntry 3 }
+
+nasLines OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of lines served by the NAS"
+ ::= { radiusStatNASEntry 4 }
+
+nasLinesInUse OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of lines currently in use on this NAS"
+ ::= { radiusStatNASEntry 5 }
+
+nasLinesIdle OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of lines currently idle on this NAS"
+ ::= { radiusStatNASEntry 6 }
+
+radiusStatNASPortTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF RadiusStatNASPortEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The (conceptual) table listing the available ports"
+ ::= { radiusStatMIB 8 }
+
+radiusStatNASPortEntry OBJECT-TYPE
+ SYNTAX RadiusStatNASPortEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "An entry (conceptual row) representing a port"
+ INDEX { PortIndex }
+ ::= { radiusStatNASPortTable 1 }
+
+RadiusStatNASPortEntry ::= SEQUENCE {
+ radiusStatPortIndex Integer32,
+ radiusStatNASIndex Integer32,
+ radiusStatPortID Integer32,
+ radiusStatPortFramedAddress IpAddress,
+ radiusStatPortTotalLogins Counter32,
+ radiusStatPortStatus INTEGER,
+ radiusStatPortStatusDate SnmpAdminString,
+ radiusStatPortUpTime TimeTicks,
+ radiusStatPortLastLoginName SnmpAdminString,
+ radiusStatPortLastLoginDate SnmpAdminString,
+ radiusStatPortLastLogoutDate SnmpAdminString,
+ radiusStatPortIdleTotalTime TimeTicks,
+ radiusStatPortIdleMaxTime TimeTicks,
+ radiusStatPortIdleMaxDate SnmpAdminString,
+ radiusStatPortInUseTotalTime TimeTicks,
+ radiusStatPortInUseMaxTime TimeTicks,
+ radiusStatPortInUseMaxDate SnmpAdminString,
+}
+
+radiusStatPortIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..2147483647)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "A number uniquely identifying each port"
+ ::= { radiusStatNASPortEntry 1 }
+
+radiusStatNASIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..2147483647)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "A number uniquely identifying each port"
+ ::= { radiusStatNASPortEntry 2 }
+
+radiusStatPortID OBJECT-TYPE
+ SYNTAX Integer32 (1..2147483647)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The Port-Identifier"
+ ::= { radiusStatNASPortEntry 3 }
+
+radiusStatPortFramedAddress OBJECT-TYPE
+ SYNTAX IpAddress
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The Port-Identifier"
+ ::= { radiusStatNASPortEntry 4 }
+
+radiusStatPortTotalLogins OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of logins registered so far"
+ ::= { radiusStatNASPortEntry 5 }
+
+radiusStatPortStatus OBJECT-TYPE
+ SYNTAX INTEGER {
+ idle(1),
+ inUse(2)
+ }
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The status of the port"
+ ::= { radiusStatNASPortEntry 6 }
+
+radiusStatPortStatusDate OBJECT-TYPE
+ SYNTAX SnmpAdminString
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Time of the last change in port status"
+ ::= { radiusStatNASPortEntry 7 }
+
+radiusStatPortUpTime OBJECT-TYPE
+ SYNTAX TimeTicks
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Time in thousandths of a second since the port changed its
+ status"
+ ::= { radiusStatNASPortEntry 8 }
+
+radiusStatPortLastLoginName OBJECT-TYPE
+ SYNTAX SnmpAdminString
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The username of the last user logged in on that port"
+ ::= { radiusStatNASPortEntry 9 }
+
+radiusStatPortLastLoginDate OBJECT-TYPE
+ SYNTAX SnmpAdminString
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Time of the last login"
+ ::= { radiusStatNASPortEntry 10 }
+
+radiusStatPortLastLogoutDate OBJECT-TYPE
+ SYNTAX SnmpAdminString
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Time of the last logout"
+ ::= { radiusStatNASPortEntry 11 }
+
+radiusStatPortIdleTotalTime OBJECT-TYPE
+ SYNTAX TimeTicks
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Total time the port was idle"
+ ::= { radiusStatNASPortEntry 12 }
+
+radiusStatPortIdleMaxTime OBJECT-TYPE
+ SYNTAX TimeTicks
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Maximum time the port was idle"
+ ::= { radiusStatNASPortEntry 13 }
+
+radiusStatPortIdleMaxDate OBJECT-TYPE
+ SYNTAX SnmpAdminString
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Date when the maximum idle time was registered"
+ ::= { radiusStatNASPortEntry 14 }
+
+radiusStatPortInUseTotalTime OBJECT-TYPE
+ SYNTAX TimeTicks
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Total time the port was in use"
+ ::= { radiusStatNASPortEntry 15 }
+
+radiusStatPortInUseMaxTime OBJECT-TYPE
+ SYNTAX TimeTicks
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Maximum time the port was in use"
+ ::= { radiusStatNASPortEntry 16 }
+
+radiusStatPortInUseMaxDate OBJECT-TYPE
+ SYNTAX SnmpAdminString
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Date when the maximum in use time was registered"
+ ::= { radiusStatNASPortEntry 17 }
+
+END
+
+
diff --git a/mibs/README b/mibs/README
new file mode 100644
index 0000000..80eaa6d
--- /dev/null
+++ b/mibs/README
@@ -0,0 +1,7 @@
+This directory contains the ASN.1 specification of the SNMP OIDs
+assigned to RADIUS MIB work by the IANA. The specifications in
+RADIUS-ACC-SERVER-MIB.txt and RADIUS-AUTH-SERVER-MIB.txt are
+extracted from RFCs 2621 and 2619 accordingly. The corresponding
+RFCs can be found in subdirectory doc/rfc of the package. Both
+RFCs allow unlimited distribution of the information contained
+therein. \ No newline at end of file
diff --git a/missing b/missing
new file mode 100755
index 0000000..db98974
--- /dev/null
+++ b/missing
@@ -0,0 +1,215 @@
+#! /bin/sh
+# Common wrapper for a few potentially missing GNU programs.
+
+scriptversion=2013-10-28.13; # UTC
+
+# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+# Originally written by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
+
+# 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, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+if test $# -eq 0; then
+ echo 1>&2 "Try '$0 --help' for more information"
+ exit 1
+fi
+
+case $1 in
+
+ --is-lightweight)
+ # Used by our autoconf macros to check whether the available missing
+ # script is modern enough.
+ exit 0
+ ;;
+
+ --run)
+ # Back-compat with the calling convention used by older automake.
+ shift
+ ;;
+
+ -h|--h|--he|--hel|--help)
+ echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due
+to PROGRAM being missing or too old.
+
+Options:
+ -h, --help display this help and exit
+ -v, --version output version information and exit
+
+Supported PROGRAM values:
+ aclocal autoconf autoheader autom4te automake makeinfo
+ bison yacc flex lex help2man
+
+Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and
+'g' are ignored when checking the name.
+
+Send bug reports to <bug-automake@gnu.org>."
+ exit $?
+ ;;
+
+ -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+ echo "missing $scriptversion (GNU Automake)"
+ exit $?
+ ;;
+
+ -*)
+ echo 1>&2 "$0: unknown '$1' option"
+ echo 1>&2 "Try '$0 --help' for more information"
+ exit 1
+ ;;
+
+esac
+
+# Run the given program, remember its exit status.
+"$@"; st=$?
+
+# If it succeeded, we are done.
+test $st -eq 0 && exit 0
+
+# Also exit now if we it failed (or wasn't found), and '--version' was
+# passed; such an option is passed most likely to detect whether the
+# program is present and works.
+case $2 in --version|--help) exit $st;; esac
+
+# Exit code 63 means version mismatch. This often happens when the user
+# tries to use an ancient version of a tool on a file that requires a
+# minimum version.
+if test $st -eq 63; then
+ msg="probably too old"
+elif test $st -eq 127; then
+ # Program was missing.
+ msg="missing on your system"
+else
+ # Program was found and executed, but failed. Give up.
+ exit $st
+fi
+
+perl_URL=http://www.perl.org/
+flex_URL=http://flex.sourceforge.net/
+gnu_software_URL=http://www.gnu.org/software
+
+program_details ()
+{
+ case $1 in
+ aclocal|automake)
+ echo "The '$1' program is part of the GNU Automake package:"
+ echo "<$gnu_software_URL/automake>"
+ echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:"
+ echo "<$gnu_software_URL/autoconf>"
+ echo "<$gnu_software_URL/m4/>"
+ echo "<$perl_URL>"
+ ;;
+ autoconf|autom4te|autoheader)
+ echo "The '$1' program is part of the GNU Autoconf package:"
+ echo "<$gnu_software_URL/autoconf/>"
+ echo "It also requires GNU m4 and Perl in order to run:"
+ echo "<$gnu_software_URL/m4/>"
+ echo "<$perl_URL>"
+ ;;
+ esac
+}
+
+give_advice ()
+{
+ # Normalize program name to check for.
+ normalized_program=`echo "$1" | sed '
+ s/^gnu-//; t
+ s/^gnu//; t
+ s/^g//; t'`
+
+ printf '%s\n' "'$1' is $msg."
+
+ configure_deps="'configure.ac' or m4 files included by 'configure.ac'"
+ case $normalized_program in
+ autoconf*)
+ echo "You should only need it if you modified 'configure.ac',"
+ echo "or m4 files included by it."
+ program_details 'autoconf'
+ ;;
+ autoheader*)
+ echo "You should only need it if you modified 'acconfig.h' or"
+ echo "$configure_deps."
+ program_details 'autoheader'
+ ;;
+ automake*)
+ echo "You should only need it if you modified 'Makefile.am' or"
+ echo "$configure_deps."
+ program_details 'automake'
+ ;;
+ aclocal*)
+ echo "You should only need it if you modified 'acinclude.m4' or"
+ echo "$configure_deps."
+ program_details 'aclocal'
+ ;;
+ autom4te*)
+ echo "You might have modified some maintainer files that require"
+ echo "the 'autom4te' program to be rebuilt."
+ program_details 'autom4te'
+ ;;
+ bison*|yacc*)
+ echo "You should only need it if you modified a '.y' file."
+ echo "You may want to install the GNU Bison package:"
+ echo "<$gnu_software_URL/bison/>"
+ ;;
+ lex*|flex*)
+ echo "You should only need it if you modified a '.l' file."
+ echo "You may want to install the Fast Lexical Analyzer package:"
+ echo "<$flex_URL>"
+ ;;
+ help2man*)
+ echo "You should only need it if you modified a dependency" \
+ "of a man page."
+ echo "You may want to install the GNU Help2man package:"
+ echo "<$gnu_software_URL/help2man/>"
+ ;;
+ makeinfo*)
+ echo "You should only need it if you modified a '.texi' file, or"
+ echo "any other file indirectly affecting the aspect of the manual."
+ echo "You might want to install the Texinfo package:"
+ echo "<$gnu_software_URL/texinfo/>"
+ echo "The spurious makeinfo call might also be the consequence of"
+ echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might"
+ echo "want to install GNU make:"
+ echo "<$gnu_software_URL/make/>"
+ ;;
+ *)
+ echo "You might have modified some files without having the proper"
+ echo "tools for further handling them. Check the 'README' file, it"
+ echo "often tells you about the needed prerequisites for installing"
+ echo "this package. You may also peek at any GNU archive site, in"
+ echo "case some other package contains this missing '$1' program."
+ ;;
+ esac
+}
+
+give_advice "$1" | sed -e '1s/^/WARNING: /' \
+ -e '2,$s/^/ /' >&2
+
+# Propagate the correct exit status (expected to be 127 for a program
+# not found, 63 for a program that failed due to version mismatch).
+exit $st
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/raddb/.gitignore b/raddb/.gitignore
new file mode 100644
index 0000000..9daa835
--- /dev/null
+++ b/raddb/.gitignore
@@ -0,0 +1,6 @@
+dictionary
+radiusd.conf
+sites-enabled
+mods-enabled
+radrelay.conf
+test.conf
diff --git a/raddb/README.rst b/raddb/README.rst
new file mode 100644
index 0000000..e3c41a7
--- /dev/null
+++ b/raddb/README.rst
@@ -0,0 +1,665 @@
+Upgrading to Version 3.2
+========================
+
+.. contents:: Sections
+ :depth: 2
+
+.. important::
+ The configuration for 3.2 is compatible with 3.0. The only change
+ is that the `correct_escapes` configuration has been removed, and
+ is not the default.
+
+Security
+--------
+
+A number of configuration items have moved into the "security"
+subsection of radiusd.conf. If you use these, you should move them.
+Otherwise, they can be ignored.
+
+The list of moved options is::
+
+ chroot
+ user
+ group
+ allow_core_dumps
+ reject_delay
+ status_server
+
+These entries should be moved from "radiusd.conf" to the "security"
+subsection of that file.
+
+Naming
+------
+
+Many names used by configuration items were inconsistent in earlier
+versions of the server. These names have been unified in version 3.
+
+If a file is being referenced or created the config item ``filename``
+is used.
+
+If a file is being created, the initial permissions are set by the
+``permissions`` config item.
+
+If a directory hierarchy needs to be created, the permissions are set
+by ``dir_permissions``.
+
+If an external host is referenced in the context of a module the
+``server`` config item is used.
+
+Unless the config item is a well recognised portmanteau
+(as ``filename`` is for example), it must be written as multiple
+distinct words separated by underscores ``_``.
+
+The configuration items ``file``, ``script_file``, ``module``,
+``detail``, ``detailfile``, ``attrsfile``, ``perm``, ``dirperm``,
+``detailperm``, and ``hostname`` are deprecated. As well as any false
+portmanteaus, and configuration items that used hyphens as word
+delimiters. e.g. ``foo-bar`` has been changed to ``foo_bar``. Please
+update your module configuration to use the new syntax.
+
+In most cases the server will tell you the replacement config item to
+use. As always, run the server in debugging mode to see these
+messages.
+
+Modules Directory
+-----------------
+
+As of version 3, the ``modules/`` directory no longer exists.
+
+Instead, all "example" modules have been put into the
+``mods-available/`` directory. Modules which can be loaded by the
+server are placed in the ``mods-enabled/`` directory. All of the
+modules in that directory will be loaded. This means that the
+``instantiate`` section of radiusd.conf is less important. The only
+reason to list a module in the ``instantiate`` section is to force
+ordering when the modules are loaded.
+
+Modules can be enabled by creating a soft link. For module ``foo``, do::
+
+ $ cd raddb/mods-enabled
+ $ ln -s ../mods-available/foo
+
+To create "local" versions of the modules, we suggest copying the file
+instead. This leaves the original file (with documentation) in the
+``mods-available/`` directory. Local changes should go into the
+``mods-enabled/`` directory.
+
+Module-specific configuration files are now in the ``mods-config/``
+directory. This change allows for better organization, and means that
+there are fewer files in the main ``raddb`` directory. See
+``mods-config/README.rst`` for more details.
+
+Changed Modules
+---------------
+
+The following modules have been changed.
+
+
+rlm_sql
+~~~~~~~
+
+The SQL configuration has been moved from ``sql.conf`` to
+``mods-available/sql``. The ``sqlippool.conf`` file has also been
+moved to ``mods-available/sqlippool``.
+
+The SQL module configuration has been changed. The old connection
+pool options are no longer accepted::
+
+ num_sql_socks
+ connect_failure_retry_delay
+ lifetime
+ max_queries
+
+Instead, a connection pool configuration is used. This configuration
+contains all of the functionality of the previous configuration, but
+in a more generic form. It also is used in multiple modules, meaning
+that there are fewer different configuration items. The mapping
+between the configuration items is::
+
+ num_sql_socks -> pool { max }
+ connect_failure_retry_delay -> pool { retry_delay }
+ lifetime -> pool { lifetime }
+ max_queries -> pool { uses }
+
+The pool configuration adds a number of new configuration options,
+which allow the administrator to better control how FreeRADIUS uses
+SQL connection pools.
+
+The following parameters have been changed::
+
+ trace -> removed
+ tracefile -> logfile
+
+The logfile is intended to log SQL queries performed. If you need to
+debug the server, use debugging mode. If ``logfile`` is set, then
+*all* SQL queries will go to ``logfile``.
+
+You can now use a NULL SQL database::
+
+ driver = rlm_sql_null
+
+This is an empty driver which will always return "success". It is
+intended to be used to replace the ``sql_log`` module, and to work in
+conjunction with the ``radsqlrelay`` program. Simply take your normal
+configuration for raddb/mods-enabled/sql, and set::
+
+ driver = rlm_sql_null
+ ...
+ logfile = ${radacctdir}/sql.log
+
+All of the SQL queries will be logged to that file. The connection
+pool does not need to be configured for the ``null`` SQL driver. It
+can be left as-is, or deleted from the SQL configuration file.
+
+rlm_sql_sybase
+~~~~~~~~~~~~~~
+
+The ``rlm_sql_sybase`` module has been renamed to ``rlm_sql_freetds``
+and the old ``rlm_sql_freetds`` module has been removed.
+
+``rlm_sql_sybase`` used the newer ct-lib API, and ``rlm_sql_freetds``
+used an older API and was incomplete.
+
+The new ``rlm_sql_freetds`` module now also supports database
+selection on connection startup so ``use`` statements no longer
+have to be included in queries.
+
+sql/dialup.conf
+~~~~~~~~~~~~~~~
+
+Queries for post-auth and accounting calls have been re-arranged. The
+SQL module will now expand the 'reference' configuration item in the
+appropriate sub-section, and resolve this to a configuration
+item. This behaviour is similar to rlm_linelog. This dynamic
+expansion allows for a dynamic mapping between accounting types and
+SQL queries. Previously, the mapping was fixed. Any "new" accounting
+type was ignored by the module. Now, support for any accounting type
+can be added by just adding a new target, as below.
+
+Queries from v2 may be manually copied to the new v3
+``dialup.conf`` file (``raddb/mods-config/sql/main/<dialect>/queries.conf``).
+When doing this you may also need to update references to the
+accounting tables, as their definitions will now be outside of
+the subsection containing the query.
+
+The mapping from old "fixed" query to new "dynamic" query is as follows::
+
+ accounting_onoff_query -> accounting.type.accounting-on.query
+ accounting_update_query -> accounting.type.interim-update.query
+ accounting_update_query_alt +> accounting.type.interim-update.query
+ accounting_start_query -> accounting.type.start.query
+ accounting_start_query_alt +> accounting.type.start.query
+ accounting_stop_query -> accounting.type.stop.query
+ accounting_stop_query_alt +> accounting.type.stop.query
+ postauth_query -> post-auth.query
+
+Alternatively a v2 config may be patched to work with the
+v3 module by adding the following::
+
+ accounting {
+ reference = "%{tolower:type.%{Acct-Status-Type}.query}"
+ type {
+ accounting-on {
+ query = "${....accounting_onoff_query}"
+ }
+ accounting-off {
+ query = "${....accounting_onoff_query}"
+ }
+ start {
+ query = "${....accounting_start_query}"
+ query = "${....accounting_start_query_alt}"
+ }
+ interim-update {
+ query = "${....accounting_update_query}"
+ query = "${....accounting_update_query_alt}"
+ }
+ stop {
+ query = "${....accounting_stop_query}"
+ query = "${....accounting_stop_query_alt}"
+ }
+ }
+ }
+
+ post-auth {
+ query = "${..postauth_query}"
+ }
+
+In general, it is safer to migrate the configuration rather than
+trying to "patch" it, to make it look like a v2 configuration.
+
+Note that the sub-sections holding the queries are labelled
+``accounting-on``, and not ``accounting_on``. The reason is that the
+names of these sections are taken directly from the
+``Accounting-Request`` packet, and the ``Acct-Status-Type`` field.
+The ``sql`` module looks at the value of that field, and then looks
+for a section of that name, in order to find the query to use.
+
+That process means that the server can be extended to support any new
+value of ``Acct-Status-Type``, simply by adding a named sub-section,
+and a query. This behavior is preferable to that of v2, which had
+hard-coded queries for certain ``Acct-Status-Type`` values, and was
+ignored all other values.
+
+rlm_ldap
+~~~~~~~~
+
+The LDAP module configuration has been substantially changed. Please
+read ``raddb/mods-available/ldap``. It now uses a connection pool,
+just like the SQL module.
+
+Many of the configuration items remain the same, but they have been
+moved into subsections. This change is largely cosmetic, but it makes
+the configuration clearer. Instead of having a large set of random
+configuration items, they are now organized into logical groups.
+
+You will need to read your old LDAP configuration, and migrate it
+manually to the new configuration. Simply copying the old
+configuration WILL NOT WORK.
+
+Users upgrading from v2 who used to call the ldap module in
+``post-auth`` should now set ``edir_autz = yes``, and remove the ``ldap``
+module from the ``post-auth`` section.
+
+rlm_ldap and LDAP-Group
+~~~~~~~~~~~~~~~~~~~~~~~
+
+In v2 the registration of the ``LDAP-Group`` pair comparison was done
+by the last instance of rlm_ldap to be instantiated. In v3 this has
+changed so that only the default ``ldap {}`` instance registers
+``LDAP-Group``.
+
+If ``<instance>-LDAP-Group`` is already used throughout your configuration
+no changes will be needed.
+
+rlm_ldap authentication
+~~~~~~~~~~~~~~~~~~~~~~~
+
+In v2 the LDAP module had a ``set_auth_type`` configuration item,
+which forced ``Auth-Type := ldap``. This was removed in 3.x.x as it
+often did not work, and was not consistent with the rest of the
+server. We generally recommend that LDAP should be used as a
+database, and that FreeRADIUS should do authentication.
+
+The only reason to use ``Auth-Type := ldap`` is when the LDAP server
+will not supply the "known good" password to FreeRADIUS, *and* where
+the Access-Request contains User-Password. This situation happens
+only for Active Directory. If you think you need to force ``Auth-Type
+:= ldap`` in other situations, you are very likely to be wrong.
+
+The following is an example of what should be inserted into the
+``authorize {}`` and ``authenticate {}`` sections of the relevant
+virtual-servers, to get functionality equivalent to v2.x::
+
+ authorize {
+ ...
+ ldap
+ if ((ok || updated) && User-Password) {
+ update control {
+ Auth-Type := ldap
+ }
+ }
+ ...
+ }
+
+ authenticate {
+ ...
+ Auth-Type ldap {
+ ldap
+ }
+ ...
+ }
+
+rlm_eap
+~~~~~~~
+
+The EAP configuration has been moved from ``eap.conf`` to
+``mods-available/eap``. A new ``pwd`` subsection has been added for
+EAP-PWD.
+
+rlm_expiration & rlm_logintime
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The rlm_expiration and rlm_logintime modules no longer add a ``Reply-Message``,
+the same behaviour can be achieved checking the return code of the module and
+adding the ``Reply-Message`` with unlang::
+
+ expiration
+ if (userlock) {
+ update reply {
+ Reply-Message := "Your account has expired"
+ }
+ }
+
+rlm_unix
+~~~~~~~~
+
+The ``unix`` module does not have an ``authenticate`` section. So you
+cannot set ``Auth-Type := System``. The ``unix`` module has also been
+deleted from the examples in ``sites-available/``. Listing it there
+has been deprecated for many years.
+
+The PAP module can do crypt authentication. It should be used instead
+of Unix authentication.
+
+The Unix module still can pull the passwords from ``/etc/passwd``, or
+``/etc/shadow``. This is done by listing it in the ``authorize``
+section, as is done in the examples in ``sites-available/``. However,
+some systems using NIS or NSS will not supply passwords to the
+``unix`` module. For those systems, we recommend putting users and
+passwords into a database, instead of relying on ``/etc/passwd``.
+
+rlm_preprocess
+~~~~~~~~~~~~~~
+
+In v2 ``huntroups`` and ``users`` files were loaded from default locations
+without being configured explicitly. Since 3.x.x you need to set
+``huntgroups`` and ``users`` configuration item(s) in module section in order
+to get them being processed.
+
+New Modules
+-----------
+
+rlm_date
+~~~~~~~~
+
+Instances of rlm_date register an xlat method which can translate
+integer and date values to an arbitrarily formatted date time
+string, or an arbitrarily formated time string to an integer,
+depending on the attribute type passed.
+
+rlm_rest
+~~~~~~~~
+
+The ``rest`` module is used to translate RADIUS requests into
+RESTfull HTTP requests. Currently supported body types are JSON
+and POST.
+
+rlm_unpack
+~~~~~~~~~~
+
+The ``unpack`` module is used to turn data buried inside of binary
+attributes. e.g. if we have ``Class = 0x00000001020304`` then::
+
+ Tmp-Integer-0 := "%{unpack:&Class 4 short}"
+
+will unpack octets 4 and 5 as a "short", which has value 0x0304.
+All integers are assumed to be in network byte order.
+
+rlm_yubikey
+~~~~~~~~~~~
+
+The ``yubikey`` module can be used to forward yubikey OTP token
+values to a Yubico validation server, or decrypt the token
+using a PSK.
+
+Deleted Modules
+---------------
+
+The following modules have been deleted, and are no longer supported
+in Version 3. If you are using one of these modules, your
+configuration can probably be changed to not need it. Otherwise email
+the freeradius-devel list, and ask about the module.
+
+rlm_acct_unique
+~~~~~~~~~~~~~~~
+
+This module has been replaced by the "acct_unique" policy. See
+raddb/policy.d/accounting.
+
+The method for calculating the value of acct_unique has changed.
+However, as this method was configurable, this change should not
+matter. The only issue is in having a v2 and v3 server writing to the
+same database at the same time. They will calculate different values
+for Acct-Unique-Id.
+
+rlm_acctlog
+~~~~~~~~~~~
+
+You should use rlm_linelog instead. That module has a superset of the
+acctlog functionality.
+
+rlm_attr_rewrite
+~~~~~~~~~~~~~~~~
+
+The attr_rewrite module looked for an attribute, and then re-wrote it,
+or created a new attribute. All of that can be done in "unlang".
+
+A sample configuration in "unlang" is::
+
+ if (request:Calling-Station-Id) {
+ update request {
+ Calling-Station-Id := "...."
+ }
+ }
+
+We suggest updating all uses of attr_rewrite to use unlang instead.
+
+rlm_checkval
+~~~~~~~~~~~~
+
+The checkval module compared two attributes. All of that can be done in "unlang"::
+
+ if (&request:Calling-Station-Id == &control:Calling-Station-Id) {
+ ok
+ }
+
+We suggest updating all uses of checkval to use unlang instead.
+
+rlm_dbm
+~~~~~~~
+
+No one seems to use it. There is no sample configuration for it.
+There is no speed advantage to using it over the "files" module.
+Modern systems are fast enough that 10K entries can be read from the
+"users" file in about 10ms. If you need more users than that, use a
+real database such as SQL.
+
+rlm_fastusers
+~~~~~~~~~~~~~
+
+No one seems to use it. It has been deprecated since Version 2.0.0.
+The "files" module was rewritten so that the "fastusers" module was no
+longer necessary.
+
+rlm_policy
+~~~~~~~~~~
+
+No one seems to use it. Almost all of its functionality is available
+via "unlang".
+
+rlm_sim_files
+~~~~~~~~~~~~~
+
+The rlm_sim_files module has been deleted. It was never marked "stable",
+and was never used in a production environment. There are better ways
+to test EAP.
+
+If you want similar functionality, see rlm_passwd. It can read CSV
+files, and create attributes from them.
+
+rlm_sql_log
+~~~~~~~~~~~
+
+This has been replaced with the "null" sql driver. See
+raddb/mods-available/sql for an example configuration.
+
+The main SQL module has more functionality than rlm_sql_log, and
+results in less code in the server.
+
+Other Functionality
+-------------------
+
+The following is a list of new / changed functionality.
+
+RadSec
+~~~~~~
+
+RadSec (or RADIUS over TLS) is now supported. RADIUS over bare TCP
+is also supported, but is recommended only for secure networks.
+
+See ``sites-available/tls`` for complete details on using TLS. The server
+can both receive incoming TLS connections, and also originate outgoing
+TLS connections.
+
+The TLS configuration is taken from the old EAP-TLS configuration. It
+is largely identical to the old EAP-TLS configuration, so it should be
+simple to use and configure. It re-uses much of the EAP-TLS code,
+so it is well-tested and reliable.
+
+Once RadSec is enabled, normal debugging mode will not work. This is
+because the TLS code requires threading to work properly. Instead of doing::
+
+ $ radiusd -X
+
+you will need to do::
+
+ $ radiusd -fxx -l stdout
+
+That's the price to pay for using RadSec. This limitation may be
+lifted in a future version of the server.
+
+
+PAP and User-Password
+~~~~~~~~~~~~~~~~~~~~~
+
+From version 3 onwards the server no longer supports authenticating
+against a cleartext password in the 'User-Password' attribute. Any
+occurences of this (for instance, in the users file) should now be changed
+to 'Cleartext-Password' instead.
+
+e.g. change entries like this::
+
+ bob User-Password == "hello"
+
+to ones like this::
+
+ bob Cleartext-Password := "hello"
+
+
+If this is not done, authentication will likely fail. The server will
+also print a helpful message in debugging mode.
+
+If it really is impossible to do this, the following unlang inserted above
+the call to the pap module may be used to copy User-Password to the correct
+attribute::
+
+ if (!control:Cleartext-Password && control:User-Password) {
+ update control {
+ Cleartext-Password := "%{control:User-Password}"
+ }
+ }
+
+However, this should only be seen as a temporary, not permanent, fix.
+It is better to fix your databases to use the correct configuration.
+
+Unlang
+~~~~~~
+
+The unlang policy language is compatible with v2, but has a number of
+new features. See ``man unlang`` for complete documentation.
+
+ERRORS
+
+Many more errors are caught when the server is starting up. Syntax
+errors in ``unlang`` are caught, and a helpful error message is
+printed. The error message points to the exact place where the error
+occurred::
+
+ ./raddb/sites-enabled/default[230]: Parse error in condition
+ ERROR: if (User-Name ! "bob") {
+ ERROR: ^ Invalid operator
+
+``update`` sections are more generic. Instead of doing ``update
+reply``, you can do the following::
+
+ update {
+ reply:Class := 0x0000
+ control:Cleartext-Password := "hello"
+ }
+
+This change means that you need fewer ``update`` sections.
+
+COMPARISONS
+
+Attribute comparisons can be done via the ``&`` operator. When you
+needed to compare two attributes, the old comparison style was::
+
+ if (User-Name == "%{control:Tmp-String-0}") {
+
+This syntax is inefficient, as the ``Tmp-String-0`` attribute would be
+printed to an intermediate string, causing unnecessary work. You can
+now instead compare the two attributes directly::
+
+ if (&User-Name == &control:Tmp-String-0) {
+
+See ``man unlang`` for more details.
+
+CASTS
+
+Casts are now permitted. This allows you to force type-specific
+comparisons::
+
+ if (<ipaddr>"%{sql: SELECT...}" == 127.0.0.1) {
+
+This forces the string returned by the SELECT to be treated as an IP
+address, and compare to ``127.0.0.1``. Previously, the comparison
+would have been done as a simple string comparison.
+
+NETWORKS
+
+IP networks are now supported::
+
+ if (127.0.0.1/32 == 127.0.0.1) {
+
+Will be ``true``. The various comparison operators can be used to
+check IP network membership::
+
+ if (127/8 > 127.0.0.1) {
+
+Returns ``true``, because ``127.0.0.1`` is within the ``127/8``
+network. However, the following comparison will return ``false``::
+
+ if (127/8 > 192.168.0.1) {
+
+because ``192.168.0.1`` is outside of the ``127/8`` network.
+
+OPTIMIZATION
+
+As ``unlang`` is now pre-compiled, many compile-time optimizations are
+done. This means that the debug output may not be exactly the same as
+what is in the configuration files::
+
+ if (0 && (User-Name == "bob')) {
+
+The result will always be ``false``, as the ``if 0`` prevents the
+following ``&& ...`` from being evaluated.
+
+Not only that, but the entire contents of that section will be ignored
+entirely::
+
+ if (0) {
+ this_module_does_not_exist
+ and_this_one_does_not_exist_either
+ }
+
+In v2, that configuration would result in a parse error, as there is
+no module called ``this_module_does_not_exist``. In v3, that text is
+ignored. This ability allows you to have dynamic configurations where
+certain parts are used (or not) depending on compile-time configuration.
+
+Similarly, conditions which always evaluate to ``true`` will be
+optimized away::
+
+ if (1) {
+ files
+ }
+
+That configuration will never show the ``if (1)`` output in debugging mode.
+
+
+Dialup_admin
+------------
+
+The dialup_admin directory has been removed. No one stepped forward
+to maintain it, and the code had not been changed in many years.
+
diff --git a/raddb/all.mk b/raddb/all.mk
new file mode 100644
index 0000000..a7f4f14
--- /dev/null
+++ b/raddb/all.mk
@@ -0,0 +1,152 @@
+#
+# The list of files to install.
+#
+LOCAL_FILES := clients.conf dictionary templates.conf experimental.conf \
+ proxy.conf radiusd.conf trigger.conf README.rst panic.gdb
+
+DEFAULT_SITES := default inner-tunnel
+LOCAL_SITES := $(addprefix raddb/sites-enabled/,$(DEFAULT_SITES))
+
+DEFAULT_MODULES := always attr_filter chap date \
+ detail detail.log digest dynamic_clients eap \
+ echo exec expiration expr files linelog logintime \
+ mschap ntlm_auth pap passwd preprocess radutmp realm \
+ replicate soh sradutmp totp unix unpack utf8
+
+LOCAL_MODULES := $(addprefix raddb/mods-enabled/,$(DEFAULT_MODULES))
+
+LOCAL_CERT_FILES := Makefile README.md xpextensions \
+ ca.cnf server.cnf inner-server.cnf \
+ client.cnf bootstrap
+
+#
+# We don't create the installed certs if we're building a package,
+# OR if OpenSSL is not available.
+#
+ifeq "$(PACKAGE)" ""
+ifneq "$(OPENSSL_LIBS)" ""
+LOCAL_CERT_PRODUCTS := $(addprefix $(R)$(raddbdir)/certs/,ca.key ca.pem \
+ client.key client.pem server.key server.pem)
+endif
+endif
+
+LEGACY_LINKS := $(addprefix $(R)$(raddbdir)/,users huntgroups hints)
+
+RADDB_DIRS := certs mods-available mods-enabled policy.d \
+ sites-available sites-enabled \
+ $(patsubst raddb/%,%,$(shell find raddb/mods-config -type d -print))
+
+# Installed directories
+INSTALL_RADDB_DIRS := $(R)$(raddbdir)/ $(addprefix $(R)$(raddbdir)/, $(RADDB_DIRS))
+
+# Grab files from the various subdirectories
+INSTALL_FILES := $(wildcard raddb/sites-available/* raddb/mods-available/*) \
+ $(addprefix raddb/,$(LOCAL_FILES)) \
+ $(addprefix raddb/certs/,$(LOCAL_CERT_FILES)) \
+ $(shell find raddb/mods-config -type f -print) \
+ $(shell find raddb/policy.d -type f -print)
+
+# Re-write local files to installed files, filtering out editor backups
+INSTALL_RADDB := $(patsubst raddb/%,$(R)$(raddbdir)/%,\
+ $(filter-out %~,$(INSTALL_FILES)))
+
+all: build.raddb
+
+build.raddb: $(LOCAL_SITES) $(LOCAL_MODULES)
+
+clean: clean.raddb
+
+install: install.raddb
+
+# Local build rules
+raddb/sites-enabled raddb/mods-enabled:
+ @echo INSTALL $@
+ @$(INSTALL) -d -m 750 $@
+
+# Set up the default modules for running in-source builds
+raddb/mods-enabled/%: raddb/mods-available/% | raddb/mods-enabled
+ @echo "LN-S $@"
+ @cd $(dir $@) && ln -sf ../mods-available/$(notdir $@)
+
+# Set up the default sites for running in-source builds
+raddb/sites-enabled/%: raddb/sites-available/% | raddb/sites-enabled
+ @echo "LN-S $@"
+ @cd $(dir $@) && ln -sf ../sites-available/$(notdir $@)
+
+# Installation rules for directories. Note permissions are 750!
+$(INSTALL_RADDB_DIRS):
+ @echo INSTALL $(patsubst $(R)$(raddbdir)%,raddb%,$@)
+ @$(INSTALL) -d -m 750 $@
+
+# The installed files have ORDER dependencies. This means that they
+# will be installed if the target doesn't exist. And they won't be
+# installed if the target already exists, even if it is out of date.
+#
+# This dependency lets us install the server on top of an existing
+# system, hopefully without breaking anything.
+
+ifeq "$(wildcard $(R)$(raddbdir)/mods-available/)" ""
+INSTALL_RADDB += $(patsubst raddb/%,$(R)$(raddbdir)/%,\
+ $(filter-out %~,$(LOCAL_MODULES)))
+
+# Installation rules for mods-enabled. Note ORDER dependencies
+$(R)$(raddbdir)/mods-enabled/%: | $(R)$(raddbdir)/mods-available/%
+ @cd $(dir $@) && ln -sf ../mods-available/$(notdir $@)
+endif
+
+ifeq "$(wildcard $(R)$(raddbdir)/sites-available/)" ""
+INSTALL_RADDB += $(patsubst raddb/%,$(R)$(raddbdir)/%,\
+ $(filter-out %~,$(LOCAL_SITES)))
+
+# Installation rules for sites-enabled. Note ORDER dependencies
+$(R)$(raddbdir)/sites-enabled/%: | $(R)$(raddbdir)/sites-available/%
+ @cd $(dir $@) && ln -sf ../sites-available/$(notdir $@)
+endif
+
+# Installation rules for plain modules.
+$(R)$(raddbdir)/%: | raddb/%
+ @echo INSTALL $(patsubst $(R)$(raddbdir)/%,raddb/%,$@)
+ @$(INSTALL) -m 640 $(patsubst $(R)$(raddbdir)/%,raddb/%,$@) $@
+
+# Create symbolic links for legacy files
+$(R)$(raddbdir)/huntgroups: $(R)$(modconfdir)/preprocess/huntgroups
+ @[ -e $@ ] || echo LN-S $(patsubst $(R)$(raddbdir)/%,raddb/%,$@)
+ @[ -e $@ ] || ln -s $(patsubst $(R)$(raddbdir)/%,./%,$<) $@
+
+$(R)$(raddbdir)/hints: $(R)$(modconfdir)/preprocess/hints
+ @[ -e $@ ] || echo LN-S $(patsubst $(R)$(raddbdir)/%,raddb/%,$@)
+ @[ -e $@ ] || ln -s $(patsubst $(R)$(raddbdir)/%,./%,$<) $@
+
+$(R)$(raddbdir)/users: $(R)$(modconfdir)/files/authorize
+ @[ -e $@ ] || echo LN-S $(patsubst $(R)$(raddbdir)/%,raddb/%,$@)
+ @[ -e $@ ] || ln -s $(patsubst $(R)$(raddbdir)/%,./%,$<) $@
+
+ifneq "$(LOCAL_CERT_PRODUCTS)" ""
+$(LOCAL_CERT_PRODUCTS):
+ @echo BOOTSTRAP raddb/certs/
+ @$(MAKE) -C $(R)$(raddbdir)/certs/
+
+# Bootstrap is special
+$(R)$(raddbdir)/certs/bootstrap: | raddb/certs/bootstrap $(LOCAL_CERT_PRODUCTS)
+ @echo INSTALL $(patsubst $(R)$(raddbdir)/%,raddb/%,$@)
+ @$(INSTALL) -m 750 $(patsubst $(R)$(raddbdir)/%,raddb/%,$@) $@
+else
+$(R)$(raddbdir)/certs/bootstrap:
+ @echo INSTALL $(patsubst $(R)$(raddbdir)/%,raddb/%,$@)
+ @$(INSTALL) -m 750 $(patsubst $(R)$(raddbdir)/%,raddb/%,$@) $@
+endif
+
+# List directories before the file targets.
+# It's not clear why GNU Make doesn't deal well with this.
+install.raddb: | $(INSTALL_RADDB_DIRS) $(INSTALL_RADDB) $(LEGACY_LINKS)
+
+clean.raddb:
+ @rm -f *~ $(addprefix raddb/sites-enabled/,$(DEFAULT_SITES)) \
+ $(addprefix raddb/mods-enabled/,$(DEFAULT_MODULES))
+
+#
+# A handy target to find out which triggers are where.
+# Should only be run by SNMP developers.
+#
+triggers:
+ @grep exec_trigger `find src -name "*.c" -print` | grep '"' | sed -e 's/.*,//' -e 's/ *"//' -e 's/");.*//'
diff --git a/raddb/certs/.gitignore b/raddb/certs/.gitignore
new file mode 100644
index 0000000..45e1bcb
--- /dev/null
+++ b/raddb/certs/.gitignore
@@ -0,0 +1,13 @@
+*.pem
+*.key
+*.crt
+*.csr
+*.p12
+*.old
+*.attr
+*.crl
+dh
+index.txt
+random
+serial
+passwords.mk
diff --git a/raddb/certs/Makefile b/raddb/certs/Makefile
new file mode 100644
index 0000000..c9fbc9e
--- /dev/null
+++ b/raddb/certs/Makefile
@@ -0,0 +1,186 @@
+######################################################################
+#
+# Make file to be installed in /etc/raddb/certs to enable
+# the easy creation of certificates.
+#
+# See the README file in this directory for more information.
+#
+# $Id$
+#
+######################################################################
+
+DH_KEY_SIZE = 2048
+OPENSSL = openssl
+EXTERNAL_CA = $(wildcard external_ca.*)
+
+ifneq "$(EXTERNAL_CA)" ""
+PARTIAL = -partial_chain
+endif
+
+#
+# Set the passwords
+#
+include passwords.mk
+
+######################################################################
+#
+# Make the necessary files, but not client certificates.
+#
+######################################################################
+.PHONY: all
+all: index.txt serial dh ca server client
+
+.PHONY: client
+client: client.pem
+
+.PHONY: ca
+ca: ca.der ca.crl
+
+.PHONY: server
+server: server.pem server.vrfy
+
+.PHONY: inner-server
+inner-server: inner-server.pem inner-server.vrfy
+
+.PHONY: verify
+verify: server.vrfy client.vrfy
+
+passwords.mk: server.cnf ca.cnf client.cnf inner-server.cnf
+ @echo "PASSWORD_SERVER = '$(shell grep output_password server.cnf | sed 's/.*=//;s/^ *//')'" > $@
+ @echo "PASSWORD_INNER = '$(shell grep output_password inner-server.cnf | sed 's/.*=//;s/^ *//')'" >> $@
+ @echo "PASSWORD_CA = '$(shell grep output_password ca.cnf | sed 's/.*=//;s/^ *//')'" >> $@
+ @echo "PASSWORD_CLIENT = '$(shell grep output_password client.cnf | sed 's/.*=//;s/^ *//')'" >> $@
+ @echo "USER_NAME = '$(shell grep emailAddress client.cnf | grep '@' | sed 's/.*=//;s/^ *//')'" >> $@
+ @echo "CA_DEFAULT_DAYS = '$(shell grep default_days ca.cnf | sed 's/.*=//;s/^ *//')'" >> $@
+
+######################################################################
+#
+# Diffie-Hellman parameters
+#
+######################################################################
+dh:
+ $(OPENSSL) dhparam -out dh -2 $(DH_KEY_SIZE)
+
+######################################################################
+#
+# Create a new self-signed CA certificate
+#
+######################################################################
+ca.key ca.pem: ca.cnf
+ @[ -f index.txt ] || $(MAKE) index.txt
+ @[ -f serial ] || $(MAKE) serial
+ $(OPENSSL) req -new -x509 -keyout ca.key -out ca.pem \
+ -days $(CA_DEFAULT_DAYS) -config ./ca.cnf \
+ -passin pass:$(PASSWORD_CA) -passout pass:$(PASSWORD_CA)
+ chmod g+r ca.key
+
+ca.der: ca.pem
+ $(OPENSSL) x509 -inform PEM -outform DER -in ca.pem -out ca.der
+
+ca.crl: ca.pem
+ $(OPENSSL) ca -gencrl -keyfile ca.key -cert ca.pem -config ./ca.cnf -out ca-crl.pem -key $(PASSWORD_CA)
+ $(OPENSSL) crl -in ca-crl.pem -outform der -out ca.crl
+ rm ca-crl.pem
+
+######################################################################
+#
+# Create a new server certificate, signed by the above CA.
+#
+######################################################################
+server.csr server.key: server.cnf
+ $(OPENSSL) req -new -out server.csr -keyout server.key -config ./server.cnf
+ chmod g+r server.key
+
+server.crt: ca.key ca.pem server.csr
+ $(OPENSSL) ca -batch -keyfile ca.key -cert ca.pem -in server.csr -key $(PASSWORD_CA) -out server.crt -extensions xpserver_ext -extfile xpextensions -config ./server.cnf
+
+server.p12: server.crt
+ $(OPENSSL) pkcs12 -export -in server.crt -inkey server.key -out server.p12 -passin pass:$(PASSWORD_SERVER) -passout pass:$(PASSWORD_SERVER)
+ chmod g+r server.p12
+
+server.pem: server.p12
+ $(OPENSSL) pkcs12 -in server.p12 -out server.pem -passin pass:$(PASSWORD_SERVER) -passout pass:$(PASSWORD_SERVER)
+ chmod g+r server.pem
+
+.PHONY: server.vrfy
+server.vrfy: ca.pem
+ @$(OPENSSL) verify $(PARTIAL) -CAfile ca.pem server.pem
+
+######################################################################
+#
+# Create a new client certificate, signed by the the above server
+# certificate.
+#
+######################################################################
+client.csr client.key: client.cnf
+ $(OPENSSL) req -new -out client.csr -keyout client.key -config ./client.cnf
+ chmod g+r client.key
+
+client.crt: ca.key ca.pem client.csr
+ $(OPENSSL) ca -batch -keyfile ca.key -cert ca.pem -in client.csr -key $(PASSWORD_CA) -out client.crt -extensions xpclient_ext -extfile xpextensions -config ./client.cnf
+
+client.p12: client.crt
+ $(OPENSSL) pkcs12 -export -in client.crt -inkey client.key -out client.p12 -passin pass:$(PASSWORD_CLIENT) -passout pass:$(PASSWORD_CLIENT)
+ chmod g+r client.p12
+ cp client.p12 $(USER_NAME).p12
+
+client.pem: client.p12
+ $(OPENSSL) pkcs12 -in client.p12 -out client.pem -passin pass:$(PASSWORD_CLIENT) -passout pass:$(PASSWORD_CLIENT)
+ chmod g+r client.pem
+ cp client.pem $(USER_NAME).pem
+
+.PHONY: client.vrfy
+client.vrfy: ca.pem client.pem
+ c_rehash .
+ $(OPENSSL) verify -CApath . client.pem
+
+######################################################################
+#
+# Create a new inner-server certificate, signed by the above CA.
+#
+######################################################################
+inner-server.csr inner-server.key: inner-server.cnf
+ $(OPENSSL) req -new -out inner-server.csr -keyout inner-server.key -config ./inner-server.cnf
+ chmod g+r inner-server.key
+
+inner-server.crt: ca.key ca.pem inner-server.csr
+ $(OPENSSL) ca -batch -keyfile ca.key -cert ca.pem -in inner-server.csr -key $(PASSWORD_CA) -out inner-server.crt -extensions xpserver_ext -extfile xpextensions -config ./inner-server.cnf
+
+inner-server.p12: inner-server.crt
+ $(OPENSSL) pkcs12 -export -in inner-server.crt -inkey inner-server.key -out inner-server.p12 -passin pass:$(PASSWORD_INNER) -passout pass:$(PASSWORD_INNER)
+ chmod g+r inner-server.p12
+
+inner-server.pem: inner-server.p12
+ $(OPENSSL) pkcs12 -in inner-server.p12 -out inner-server.pem -passin pass:$(PASSWORD_INNER) -passout pass:$(PASSWORD_INNER)
+ chmod g+r inner-server.pem
+
+.PHONY: inner-server.vrfy
+inner-server.vrfy: ca.pem
+ @$(OPENSSL) verify $(PARTIAL) -CAfile ca.pem inner-server.pem
+
+######################################################################
+#
+# Miscellaneous rules.
+#
+######################################################################
+index.txt:
+ @touch index.txt
+
+serial:
+ @echo '01' > serial
+
+print:
+ $(OPENSSL) x509 -text -in server.crt
+
+printca:
+ $(OPENSSL) x509 -text -in ca.pem
+
+clean:
+ @rm -f *~ *old client.csr client.key client.crt client.p12 client.pem
+
+#
+# Make a target that people won't run too often.
+#
+destroycerts:
+ rm -f *~ dh *.csr *.crt *.p12 *.der *.pem *.key index.txt* \
+ serial* *\.0 *\.1 ca-crl.pem ca.crl
diff --git a/raddb/certs/README.md b/raddb/certs/README.md
new file mode 100644
index 0000000..1d73f99
--- /dev/null
+++ b/raddb/certs/README.md
@@ -0,0 +1,248 @@
+# Certificate Documentation
+
+This directory contains scripts to create the server certificates. To
+make a set of default (i.e. test) certificates, simply type:
+
+```
+$ ./bootstrap
+```
+
+The `openssl` command will be run against the sample configuration
+files included here, and will make a self-signed certificate authority
+(i.e. root CA), and a server certificate. This "root CA" should be
+installed on any client machine needing to do EAP-TLS, PEAP, or
+EAP-TTLS.
+
+The Extended Key Usage (EKU) fields for "TLS web server" will be
+automatically included in the server certificate. Without those
+extensions many clients will refuse to authenticate to FreeRADIUS.
+
+The root CA and the "XP Extensions" file also contain a
+crlDistributionPoints attribute. Many systems need this to be present
+in order to validate the RADIUS server certificate. The RADIUS server
+must have the URI defined but the CA need not have...however it is
+best practice for a CA to have a revocation URI. Note that whilst the
+Windows Mobile client cannot actually use the CRL when doing 802.1X it
+is recommended that the URI be an actual working URL and contain a
+revocation format file as there may be other OS behaviour at play and
+future OSes that may do something with that URI.
+
+For Windows, you will need to import the `p12` and/or the `der` format
+of the certificates. Linux systems need the `pem` format.
+
+In general, you should use self-signed certificates for 802.1X (EAP)
+authentication. When you list root CAs from other organisations in
+the `ca_file`, you permit them to masquerade as you, to authenticate
+your users, and to issue client certificates for EAP-TLS.
+
+If you already have CA and server certificates, rename (or delete)
+this directory, and create a new `certs` directory containing your
+certificates. Note that the `make install` command will **not**
+over-write your existing `raddb/certs` directory.
+
+
+## New Installations of FreeRADIUS
+
+We suggest that new installations use the test certificates for
+initial tests, and then create real certificates to use for normal
+user authentication. See the instructions below for how to create the
+various certificates. The old test certificates can be deleted by
+running the following command:
+
+```
+$ make destroycerts
+```
+
+Then, follow the instructions below for creating real certificates.
+
+If you do not want to enable EAP-TLS, PEAP, or EAP-TTLS, then delete
+the relevant sub-sections from the `raddb/mods-available/eap` file.
+See the comments in that file for more information.
+
+
+## Making a root Certificate
+
+We recommend using a private certificate authority (CA). While it can
+be difficult to install this CA on multiple client machines, it is (in
+general) more secure.
+
+```
+$ vi ca.cnf
+```
+
+Edit `default_days` to set the desired lifetime of the CA certificate.
+
+Edit the `input_password` and `output_password` fields to be the
+password for the CA certificate.
+
+Edit the `[certificate_authority]` section to have the correct values
+for your country, state, etc.
+
+Create the CA certificate:
+
+```
+$ make ca.pem
+```
+
+Then the `DER` format needed by Windows:
+
+```
+$ make ca.der
+```
+
+
+## Making a Server Certificate
+
+The following steps will let you create a server certificate for use
+with TLS-based EAP methods, such as EAP-TLS, PEAP, and TTLS. Follow
+similar steps to create an `inner-server.pem` file, for use with
+EAP-TLS that is tunneled inside of another TLS-based EAP method.
+
+```
+$ vi server.cnf
+```
+
+Edit `default_days` to set the lifetime of the server certificate.
+The maximum for this is 825 for compatibility with all client devices.
+
+Edit the `input_password` and `output_password` fields to be the
+password for the server certificate.
+
+Edit the `[server]` section to have the correct values for your
+country, state, etc. Be sure that the `commonName` field here is
+different from the `commonName` for the CA certificate.
+
+Create the server certificate:
+
+```
+$ make server
+```
+
+
+### Making a certificate for a public CA
+
+If you wish to use an existing certificate authority, you can
+create a certificate signing request for the server certificate, edit
+`server.cnf` as above, and run the following command.
+
+```
+$ make server.csr
+```
+
+This step creates a "Certificate Signing Request" suitable for
+submission to a public CA.
+
+
+## Making a Client certificate
+
+Client certificates are used by EAP-TLS, and optionally by EAP-TTLS
+and PEAP. The following steps outline how to create a client
+certificate that is signed by the CA certificate created above. You
+will have to have the password for the CA certificate in the
+`input_password` and `output_password` fields of the `ca.cnf` file.
+
+```
+$ vi client.cnf
+```
+
+Edit `default_days` to set the lifetime of the client certificate.
+
+Edit the `input_password` and `output_password` fields to be the
+password for the client certificate. You will have to give these
+passwords to the end user who will be using the certificates.
+
+Edit the `[client]` section to have the correct values for your
+country, state, etc. Be sure that the `commonName` field here is
+the `User-Name` which will be used for logins!
+
+```
+$ make client
+```
+
+The users certificate will be in `emailAddress.pem`,
+e.g. `user@example.com.pem`.
+
+To create another client certificate, just repeat the steps for
+making a client certificate, being sure to enter a different login
+name for `commonName`, and a different password.
+
+
+## Performance
+
+EAP performance for EAP-TLS, TTLS, and PEAP is dominated by SSL
+calculations. That is, a normal system can handle PAP
+authentication at a rate of 10k packets/s. However, SSL involves
+RSA calculations, which are very expensive. To benchmark your system,
+do:
+
+```
+$ openssl speed rsa
+```
+
+or
+
+```
+$ openssl speed rsa2048
+```
+
+to test 2048 bit keys.
+
+The number that is printed is the **maximum** number of
+authentications per second which can be done for EAP-TLS (or TTLS,
+or PEAP). In practice, you will see results much lower than this
+number, i.e. the actual EAP-TLS performance may be half of the
+number printed here.
+
+The reason is that EAP requires many round-trip packets, whereas
+`openssl speed rsa2028` only does RSA calculations, and nothing else.
+
+
+## Compatibility
+
+The certificates created using this method are known to be compatible
+with ALL operating systems. Some common issues are:
+
+* iOS and macOS have requirements on certificates. See:
+ https://support.apple.com/en-us/HT210176
+
+* Many systems require certain OIDs in the certificates
+ (`id-kp-serverAuth` for `TLS Web server authentication`).
+ If the certificate does not contain these fields, the system
+ will stop doing EAP. The most visible effect is that the client
+ starts EAP, gets a few Access-Challenge packets, and then a little
+ while later re-starts EAP. If this happens, see the FAQ, and the
+ comments in `raddb/mods-available/eap` for how to fix it.
+
+* All systems requires the root certificates to be on the client PC.
+ If it doesn't have them, you will see the same issue as above.
+
+* Windows XP post SP2 has a bug where it has problems with
+ certificate chains. i.e. if the server certificate is an
+ intermediate one, and not a root one, then authentication
+ will silently fail, as above.
+
+* Some versions of Windows CE cannot handle 4K RSA certificates.
+ They will (again) silently fail, as above.
+
+* In none of these cases will Windows give the end user any
+ reasonable error message describing what went wrong. This leads
+ people to blame the RADIUS server. That blame is misplaced.
+
+* Certificate chains of more than 64K bytes are known to not work.
+ This is partly a problem in FreeRADIUS. However, most clients cannot
+ handle 64K certificate chains. Most Access Points will shut down the
+ EAP session after about 50 round trips, while 64K certificate chains
+ will take about 60 round trips. So don't use large certificate
+ chains. They will only work after everyone upgrades everything in the
+ network.
+
+* All other operating systems are known to work with EAP and
+ FreeRADIUS. This includes Linux, the BSDs, macOS, iOS, Android,
+ Solaris, Symbian, along with all known embedded systems, phones,
+ WiFi devices, etc.
+
+
+## Security Considerations
+
+The default certificate configuration files uses SHA256 for message
+digests for security.
diff --git a/raddb/certs/bootstrap b/raddb/certs/bootstrap
new file mode 100755
index 0000000..57de8cf
--- /dev/null
+++ b/raddb/certs/bootstrap
@@ -0,0 +1,86 @@
+#!/bin/sh
+#
+# This is a wrapper script to create default certificates when the
+# server first starts in debugging mode. Once the certificates have been
+# created, this file should be deleted.
+#
+# Ideally, this program should be run as part of the installation of any
+# binary package. The installation should also ensure that the permissions
+# and owners are correct for the files generated by this script.
+#
+# $Id$
+#
+umask 027
+cd `dirname $0`
+
+make -h > /dev/null 2>&1
+
+#
+# If we have a working "make", then use it. Otherwise, run the commands
+# manually.
+#
+if [ "$?" = "0" ]; then
+ make all
+ exit $?
+fi
+
+#
+# The following commands were created by running "make -n", and edited
+# to remove the trailing backslash, and to add "exit 1" after the commands.
+#
+# Don't edit the following text. Instead, edit the Makefile, and
+# re-generate these commands.
+#
+if [ ! -f dh ]; then
+ openssl dhparam -out dh 2048 || exit 1
+ if [ -e /dev/urandom ] ; then
+ ln -sf /dev/urandom random
+ else
+ date > ./random;
+ fi
+fi
+
+if [ ! -f server.key ]; then
+ openssl req -new -out server.csr -keyout server.key -config ./server.cnf || exit 1
+ chmod g+r server.key
+fi
+
+if [ ! -f ca.key ]; then
+ openssl req -new -x509 -keyout ca.key -out ca.pem -days `grep default_days ca.cnf | sed 's/.*=//;s/^ *//'` -config ./ca.cnf || exit 1
+fi
+
+if [ ! -f index.txt ]; then
+ touch index.txt
+fi
+
+if [ ! -f serial ]; then
+ echo '01' > serial
+fi
+
+if [ ! -f server.crt ]; then
+ openssl ca -batch -keyfile ca.key -cert ca.pem -in server.csr -key `grep output_password ca.cnf | sed 's/.*=//;s/^ *//'` -out server.crt -extensions xpserver_ext -extfile xpextensions -config ./server.cnf || exit 1
+fi
+
+if [ ! -f server.p12 ]; then
+ openssl pkcs12 -export -in server.crt -inkey server.key -out server.p12 -passin pass:`grep output_password server.cnf | sed 's/.*=//;s/^ *//'` -passout pass:`grep output_password server.cnf | sed 's/.*=//;s/^ *//'` || exit 1
+ chmod g+r server.p12
+fi
+
+if [ ! -f server.pem ]; then
+ openssl pkcs12 -in server.p12 -out server.pem -passin pass:`grep output_password server.cnf | sed 's/.*=//;s/^ *//'` -passout pass:`grep output_password server.cnf | sed 's/.*=//;s/^ *//'` || exit 1
+ openssl verify -CAfile ca.pem server.pem || exit 1
+ chmod g+r server.pem
+fi
+
+if [ ! -f ca.der ]; then
+ openssl x509 -inform PEM -outform DER -in ca.pem -out ca.der || exit 1
+fi
+
+if [ ! -f client.key ]; then
+ openssl req -new -out client.csr -keyout client.key -config ./client.cnf
+ chmod g+r client.key
+fi
+
+if [ ! -f client.crt ]; then
+ openssl ca -batch -keyfile ca.key -cert ca.pem -in client.csr -key `grep output_password ca.cnf | sed 's/.*=//;s/^ *//'` -out client.crt -extensions xpclient_ext -extfile xpextensions -config ./client.cnf
+fi
diff --git a/raddb/certs/ca.cnf b/raddb/certs/ca.cnf
new file mode 100644
index 0000000..d49991b
--- /dev/null
+++ b/raddb/certs/ca.cnf
@@ -0,0 +1,62 @@
+[ ca ]
+default_ca = CA_default
+
+[ CA_default ]
+dir = ./
+certs = $dir
+crl_dir = $dir/crl
+database = $dir/index.txt
+new_certs_dir = $dir
+certificate = $dir/ca.pem
+serial = $dir/serial
+crl = $dir/crl.pem
+private_key = $dir/ca.key
+RANDFILE = $dir/.rand
+name_opt = ca_default
+cert_opt = ca_default
+default_days = 60
+default_crl_days = 30
+default_md = sha256
+preserve = no
+policy = policy_match
+crlDistributionPoints = URI:http://www.example.org/example_ca.crl
+
+[ policy_match ]
+countryName = match
+stateOrProvinceName = match
+organizationName = match
+organizationalUnitName = optional
+commonName = supplied
+emailAddress = optional
+
+[ policy_anything ]
+countryName = optional
+stateOrProvinceName = optional
+localityName = optional
+organizationName = optional
+organizationalUnitName = optional
+commonName = supplied
+emailAddress = optional
+
+[ req ]
+prompt = no
+distinguished_name = certificate_authority
+default_bits = 2048
+input_password = whatever
+output_password = whatever
+x509_extensions = v3_ca
+
+[certificate_authority]
+countryName = FR
+stateOrProvinceName = Radius
+localityName = Somewhere
+organizationName = Example Inc.
+emailAddress = admin@example.org
+commonName = "Example Certificate Authority"
+
+[v3_ca]
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid:always,issuer:always
+basicConstraints = critical,CA:true
+crlDistributionPoints = URI:http://www.example.org/example_ca.crl
+
diff --git a/raddb/certs/client.cnf b/raddb/certs/client.cnf
new file mode 100644
index 0000000..2650e47
--- /dev/null
+++ b/raddb/certs/client.cnf
@@ -0,0 +1,53 @@
+[ ca ]
+default_ca = CA_default
+
+[ CA_default ]
+dir = ./
+certs = $dir
+crl_dir = $dir/crl
+database = $dir/index.txt
+new_certs_dir = $dir
+certificate = $dir/ca.pem
+serial = $dir/serial
+crl = $dir/crl.pem
+private_key = $dir/ca.key
+RANDFILE = $dir/.rand
+name_opt = ca_default
+cert_opt = ca_default
+default_days = 60
+default_crl_days = 30
+default_md = sha256
+preserve = no
+policy = policy_match
+
+[ policy_match ]
+countryName = match
+stateOrProvinceName = match
+organizationName = match
+organizationalUnitName = optional
+commonName = supplied
+emailAddress = optional
+
+[ policy_anything ]
+countryName = optional
+stateOrProvinceName = optional
+localityName = optional
+organizationName = optional
+organizationalUnitName = optional
+commonName = supplied
+emailAddress = optional
+
+[ req ]
+prompt = no
+distinguished_name = client
+default_bits = 2048
+input_password = whatever
+output_password = whatever
+
+[client]
+countryName = FR
+stateOrProvinceName = Radius
+localityName = Somewhere
+organizationName = Example Inc.
+emailAddress = user@example.org
+commonName = user@example.org
diff --git a/raddb/certs/demoCA/cacert.pem b/raddb/certs/demoCA/cacert.pem
new file mode 100644
index 0000000..7ddff4d
--- /dev/null
+++ b/raddb/certs/demoCA/cacert.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDtjCCAx+gAwIBAgIBADANBgkqhkiG9w0BAQQFADCBnzELMAkGA1UEBhMCQ0Ex
+ETAPBgNVBAgTCFByb3ZpbmNlMRIwEAYDVQQHEwlTb21lIENpdHkxFTATBgNVBAoT
+DE9yZ2FuaXphdGlvbjESMBAGA1UECxMJbG9jYWxob3N0MRswGQYDVQQDExJDbGll
+bnQgY2VydGlmaWNhdGUxITAfBgkqhkiG9w0BCQEWEmNsaWVudEBleGFtcGxlLmNv
+bTAeFw0wNDAxMjUxMzI2MDdaFw0wNjAxMjQxMzI2MDdaMIGfMQswCQYDVQQGEwJD
+QTERMA8GA1UECBMIUHJvdmluY2UxEjAQBgNVBAcTCVNvbWUgQ2l0eTEVMBMGA1UE
+ChMMT3JnYW5pemF0aW9uMRIwEAYDVQQLEwlsb2NhbGhvc3QxGzAZBgNVBAMTEkNs
+aWVudCBjZXJ0aWZpY2F0ZTEhMB8GCSqGSIb3DQEJARYSY2xpZW50QGV4YW1wbGUu
+Y29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDUxbGXJPFkrPH/sYnbHI+/
+9PFDlup8sekPeNaUUXJTd4ld/lLMuZtB6A3etYsSepQ/T1jLxWKHgZL73G/s6fhx
+58Ew01z1GIgX6bEzJJ7dKhx10xBDrodVPOx6d+8mqn10KB25t34XxkRsXdmxiLQy
+UMoCKZY3IqEjpyawC0An/QIDAQABo4H/MIH8MB0GA1UdDgQWBBRo020+Hue8nVoF
+cCHDY9oTZdGt4zCBzAYDVR0jBIHEMIHBgBRo020+Hue8nVoFcCHDY9oTZdGt46GB
+paSBojCBnzELMAkGA1UEBhMCQ0ExETAPBgNVBAgTCFByb3ZpbmNlMRIwEAYDVQQH
+EwlTb21lIENpdHkxFTATBgNVBAoTDE9yZ2FuaXphdGlvbjESMBAGA1UECxMJbG9j
+YWxob3N0MRswGQYDVQQDExJDbGllbnQgY2VydGlmaWNhdGUxITAfBgkqhkiG9w0B
+CQEWEmNsaWVudEBleGFtcGxlLmNvbYIBADAMBgNVHRMEBTADAQH/MA0GCSqGSIb3
+DQEBBAUAA4GBADPAC2ax5Xnvc6BnmCUtq41eVRH8AP0nbYDRL4NHd8Z0P9wnQ/yh
+UHcE5LwJeeT2CsOtnug+bzRzaSKdH3cim6LpgjWdpWMCSgAWPbptbJhsC60or4UT
+L/jw12UBvxt8Lf9ljOHmLAGZe25k4+jUNzNUzpkShHZRU5BjuFu8VIXF
+-----END CERTIFICATE-----
diff --git a/raddb/certs/inner-server.cnf b/raddb/certs/inner-server.cnf
new file mode 100644
index 0000000..2101c2e
--- /dev/null
+++ b/raddb/certs/inner-server.cnf
@@ -0,0 +1,55 @@
+[ ca ]
+default_ca = CA_default
+
+[ CA_default ]
+dir = ./
+certs = $dir
+crl_dir = $dir/crl
+database = $dir/index.txt
+new_certs_dir = $dir
+certificate = $dir/server.pem
+serial = $dir/serial
+crl = $dir/crl.pem
+private_key = $dir/server.key
+RANDFILE = $dir/.rand
+name_opt = ca_default
+cert_opt = ca_default
+default_days = 60
+default_crl_days = 30
+default_md = sha256
+preserve = no
+policy = policy_match
+copy_extensions = copy
+
+[ policy_match ]
+countryName = match
+stateOrProvinceName = match
+organizationName = match
+organizationalUnitName = optional
+commonName = supplied
+emailAddress = optional
+
+[ policy_anything ]
+countryName = optional
+stateOrProvinceName = optional
+localityName = optional
+organizationName = optional
+organizationalUnitName = optional
+commonName = supplied
+emailAddress = optional
+
+[ req ]
+prompt = no
+distinguished_name = server
+default_bits = 2048
+input_password = whatever
+output_password = whatever
+
+[server]
+countryName = FR
+stateOrProvinceName = Radius
+localityName = Somewhere
+organizationName = Example Inc.
+emailAddress = admin@example.org
+commonName = "Example Inner Server Certificate"
+
diff --git a/raddb/certs/ocsp.cnf b/raddb/certs/ocsp.cnf
new file mode 100644
index 0000000..01225d8
--- /dev/null
+++ b/raddb/certs/ocsp.cnf
@@ -0,0 +1,61 @@
+[ ca ]
+default_ca = CA_default
+
+[ CA_default ]
+dir = ./
+certs = $dir
+crl_dir = $dir/crl
+database = $dir/index.txt
+new_certs_dir = $dir
+certificate = $dir/server.pem
+serial = $dir/serial
+crl = $dir/crl.pem
+private_key = $dir/server.key
+RANDFILE = $dir/.rand
+name_opt = ca_default
+cert_opt = ca_default
+default_days = 60
+default_crl_days = 30
+default_md = sha256
+preserve = no
+policy = policy_match
+unique_subject = no
+x509_extensions = v3_ocsp
+
+[ policy_match ]
+countryName = match
+stateOrProvinceName = match
+organizationName = match
+organizationalUnitName = optional
+commonName = supplied
+emailAddress = optional
+
+[ policy_anything ]
+countryName = optional
+stateOrProvinceName = optional
+localityName = optional
+organizationName = optional
+organizationalUnitName = optional
+commonName = supplied
+emailAddress = optional
+
+[ req ]
+prompt = no
+distinguished_name = server
+default_bits = 2048
+input_password = whatever
+output_password = whatever
+
+[ server ]
+countryName = FR
+stateOrProvinceName = Radius
+localityName = Somewhere
+organizationName = Example Inc.
+emailAddress = admin@example.org
+commonName = "Example OCSP Responder Certificate"
+subjectAltName = ocsp.example.org
+
+[ v3_ocsp ]
+basicConstraints = CA:FALSE
+keyUsage = nonRepudiation, digitalSignature, keyEncipherment
+extendedKeyUsage = OCSPSigning
diff --git a/raddb/certs/realms/README.md b/raddb/certs/realms/README.md
new file mode 100644
index 0000000..9f754fa
--- /dev/null
+++ b/raddb/certs/realms/README.md
@@ -0,0 +1,235 @@
+# Multiple Certificate Chains
+
+As of version 3.0.24, FreeRADIUS supports loading multiple certificate
+chains, keyed by a realm name. These chains are in _addition_ to the
+default certificates loaded by the `tls` section.
+
+Loading multiple certificate chains means that the server can have
+different identities. i.e. When a user `bob@example.com` requests
+network access, the server can present an `example.com` certificate.
+On the other hand, when a user `doug@example.org` requests network
+access, the server cna present an `example.org` certificate.
+
+This functionality means that it is possible to configure only one
+`eap` module, and then use multiple certificate chains. Previous
+versions of the server required that the administrator configure
+multiple EAP modules, one for each certificate being used.
+
+The selection can be performed in one of two ways. First, the
+certificates can be loaded dynamically at run-time. Second, the
+certificates can be pre-loaded for speed.
+
+## Dynamic Loading of Certificate Chains
+
+The server can dynamically load a certificate chain by setting a
+special attribute. This has to be done _after_ the server has
+received the EAP identity request, and _before_ the TLS session setup
+has started.
+
+The simplest way to do this is via the following `unlang` statements:
+
+```
+authenticate {
+ ...
+ Auth-Type eap {
+ if ("%{unpack:&EAP-Message 4 byte}" == 1) {
+ update control {
+ TLS-Session-Cert-File := "${certdir}/realms/%{Realm}"
+ }
+ }
+
+ eap
+ }
+ ...
+}
+```
+
+This configuration looks at the `EAP-Message` attribute, and checks if
+it is an EAP-Identity packet. If so, it then adds a special attribute
+`TLS-Session-Cert-File`, with a value based on the `Realm`, from the
+`User-Name`. That setting tells the server to look in the file for a
+certificate.
+
+If the file is there, and contains a correctly formatted `PEM`
+certificate chain, then it is loaded and used.
+
+If the file does not exist, or the file does not contain a correctly
+formatted `PEM` certificate chain, then the user is rejected.
+
+### Format
+
+This file should contain the server certificate, followed by
+intermediate certificates, in order. i.e. If we have a server
+certificate signed by CA1, which is signed by CA2, which is signed by
+a root CA, then the "certificate_file" should contain server.pem,
+followed by CA1.pem, followed by CA2.pem.
+
+When using `ca_file` or `ca_dir`, the file should contain only the
+server certificate.
+
+### Private Key
+
+The private should be placed in the same file as the other
+certificates, but at the start.
+
+```
+private key
+server cert
+...
+ca cert
+```
+
+The private key can also be placed into a separate file. The filename
+should be placed into the `TLS-Session-Cert-Private-Key-File`
+attribute.
+
+For simplicity, the private keys _should not_ have passwords. There
+is essentially no security benefit to "securing" the key with a
+password, and then placing the password into the file system, right
+next to the private key.
+
+### Realms
+
+There is no need to place the certificates into files named for each
+realm. However, it is by far and away the easiest way to manage these
+certificate chains.
+
+For every realm which is handles this way, the `proxy.conf` file
+should define a _local_ realm. That is, it should contain a
+definition such as:
+
+```
+example.org {
+}
+```
+
+This defines the realm `example.org`, and tells FreeRADIUS that there
+are no home servers associated with the realm.
+
+The `suffix` module should also be configured, as per the default
+configuration. i.e. list `suffix` in the `authorize` section _before_
+the `eap` module.
+
+### Caveats
+
+The root CA certificate for the server certificate should be located
+in the `ca_dir`, along with other root CAs. If the root CA is not
+there, then it *must* be included at the end of the file.
+
+These certificates will be loaded and parsed _for every matching
+authentication request_. That limitation means that dynamic loading
+of the certificates is likely be slow, and to severely impact
+performance. The good news is that we can fix that with a little more
+configuration.
+
+## Preloading Certificate Chains
+
+The server can also pre-load certificate chains. In the EAP module,
+you can do:
+
+```
+eap {
+ ...
+ tls {
+ ...
+ realm_dir = ${certdir}/realms/
+ ...
+ }
+ ...
+}
+```
+
+Each file in that directory should be a `PEM` encoded certificate
+chain, as described in the previous section. For safety, every file
+*must* have a `.pem` as the filename extension.
+e.g. `example.org.pem`.
+
+If there is a corresponding private key, it should be placed into a
+`.key` file. e.g. `example.org.key`.
+
+These certificates will be loaded when the server starts, and cached
+for the lifetime of the server. There is no way to reload these
+certificates dynamically, the server must be restarted.
+
+Once the `realm_dir` configuration has been added, the selection of
+certificates is identical to that described in the previous section.
+Just set `TLS-Session-Cert-File`, and the server will figure it out.
+
+However, it is possible to dynamically add new certificate, and have
+the server pick it up. In fact, as the process for choosing
+certificates are the same, the server will do this automatically!
+
+## RadSec
+
+The above configuration applies to RadSec, too, as the `tls`
+configuration in the server is for all TLS functionality, and not just
+EAP.
+
+This means that the server can accept RadSec connections, and then
+present different server certificates to different clients.
+
+For this functionality to work, the certificates for EAP and RadSec
+*should* be in separate directories.
+
+### Clients
+
+RadSec clients can set the SNI to send in the `tls` subsection of the
+`home_server` definition. Look for "SNI" in `sites-available/tls`,
+and see the `hostname` configuration item for documentation.
+
+For example, an identity provider could host multiple sites, but
+present itself with one public IP address. If the RadSec clients do
+not use SNI, then they must be configured with the certificate of the
+identity provider.
+
+When SNI is used, the RadSec clients can be configured with the
+certificate of the hosted system that they're connecting to. This
+ability means that there is no need to change certificates when
+changing providers. In addition, there is no need to change the
+configuration of all RadSec clients when the hosting system changes
+its certifiates. Because the hosting system certificates are never
+used.
+
+Instead, each hosted company is responsible for its own certificates,
+and for its own RadSec clients.
+
+SNI also permits the use of a load balancer such as haproxy. That
+load balancer can terminate the TLS connection, and then use SNI to
+route the underlying RADIUS TCP traffic to a particular host.
+
+### Servers
+
+See the `realm_dir` configuration item in the `tls` subsection for the
+location of the server certificates.
+
+If the server receives an SNI for a realm it does not recognize, it
+will just use the default TLS configuration.
+
+If the realm is recognized (i.e. there is a file in
+`${realm_dir}/%{TLS-Server-Name-Indication}.pem`, then that certificate will be chosen, and
+present to the RadSec client. If there is no such file, then the
+default TLS configuration is used.
+
+The current behavior is to _require_ that the server certificate is in
+a file which taken from
+`${realm_dir}/%{TLS-Server-Name-Indication}.pem`. Only the
+`realm_dir` portion of the filename is configurable. The SNI portion
+is taken from the TLS messages, and the `.pem` suffix is hard-coded in
+the source code.
+
+Taking the filename from an untrusted source is fine here. The
+standard (RFC 6066 Section 3) says that the Server Name Indication
+field is a DNS "A label". Which means that there are a limited number
+of characters allowed:
+
+* `.`, `-`, `a-Z`, `A-Z`, `0-9`
+
+If the SNI contain anything else, the TLS connection is rejected.
+
+Note that if session resumption is enabled for RadSec, the session
+cache *must* also cache the `TLS-Server-Name-Indication` attribute.
+The SNI is sent on resumption for TLS 1.2 and earlier, but it is not
+sent for TLS 1.3. As such, the only way to select the right policy on
+resumption is to check the value of the cached
+TLS-Server-Name-Indication attribute.
+
diff --git a/raddb/certs/server.cnf b/raddb/certs/server.cnf
new file mode 100644
index 0000000..daca18d
--- /dev/null
+++ b/raddb/certs/server.cnf
@@ -0,0 +1,72 @@
+[ ca ]
+default_ca = CA_default
+
+[ CA_default ]
+dir = ./
+certs = $dir
+crl_dir = $dir/crl
+database = $dir/index.txt
+new_certs_dir = $dir
+certificate = $dir/server.pem
+serial = $dir/serial
+crl = $dir/crl.pem
+private_key = $dir/server.key
+RANDFILE = $dir/.rand
+name_opt = ca_default
+cert_opt = ca_default
+default_days = 60
+default_crl_days = 30
+default_md = sha256
+preserve = no
+policy = policy_match
+copy_extensions = copy
+
+[ policy_match ]
+countryName = match
+stateOrProvinceName = match
+organizationName = match
+organizationalUnitName = optional
+commonName = supplied
+emailAddress = optional
+
+[ policy_anything ]
+countryName = optional
+stateOrProvinceName = optional
+localityName = optional
+organizationName = optional
+organizationalUnitName = optional
+commonName = supplied
+emailAddress = optional
+
+[ req ]
+prompt = no
+distinguished_name = server
+default_bits = 2048
+input_password = whatever
+output_password = whatever
+#req_extensions = v3_req
+
+[server]
+countryName = FR
+stateOrProvinceName = Radius
+localityName = Somewhere
+organizationName = Example Inc.
+emailAddress = admin@example.org
+commonName = "Example Server Certificate"
+
+[ v3_req ]
+basicConstraints = CA:FALSE
+keyUsage = nonRepudiation, digitalSignature, keyEncipherment
+subjectAltName = @alt_names
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid:always,issuer:always
+
+# This should be a host name of the RADIUS server.
+# Note that the host name is exchanged in EAP *before*
+# the user machine has network access. So the host name
+# here doesn't really have to match anything in DNS.
+[alt_names]
+DNS.1 = radius.example.com
+
+# NAIRealm from RFC 7585
+otherName.0 = 1.3.6.1.5.5.7.8.8;FORMAT:UTF8,UTF8:*.example.com
diff --git a/raddb/certs/xpextensions b/raddb/certs/xpextensions
new file mode 100644
index 0000000..ae87f42
--- /dev/null
+++ b/raddb/certs/xpextensions
@@ -0,0 +1,75 @@
+#
+# File containing the OIDs required for Windows
+# and iOS
+#
+# http://support.microsoft.com/kb/814394/en-us
+#
+# https://support.apple.com/en-us/HT210176
+#
+[ xpclient_ext]
+extendedKeyUsage = 1.3.6.1.5.5.7.3.2
+crlDistributionPoints = URI:http://www.example.com/example_ca.crl
+
+[ xpserver_ext]
+extendedKeyUsage = 1.3.6.1.5.5.7.3.1
+crlDistributionPoints = URI:http://www.example.com/example_ca.crl
+
+# Enterprise Wi-Fi clients from 2020 onwards which have the
+# Wi-Fi Certified WPA3 Release 2 (December 2019) certification
+# honour the following two policies for enhanced security
+# posture regarding certificate validation:
+#
+# https://www.wi-fi.org/discover-wi-fi/security
+#
+# Adding the 'Trust Override Disabled - STRICT' policy means that
+# the client device is not allowed to request and accept ad-hoc
+# trust decisions from the user ("Is this the certificate you
+# expect here?") and instead aborts authentication until the
+# device has been properly configured using out-of-band means
+# with all the details needed to verify the certificate (i.e.
+# either the tuple (CA, server name) or the literal server cert).
+#
+# Adding the 'Trust Override Disabled - TOFU' policy means that
+# the client device is allowed to ask the end user for such an
+# override exactly once, when first connecting to an unknown
+# network. Once the network is known and the trust decision made,
+# any other certificate that is presented and would require
+# another override is rejected and authentication aborted.
+#
+# Both of these policies provide a protection against rogue
+# authentication servers in that they make sure configurations
+# on end user devices are sufficient to identify the genuine
+# server.
+#
+# The difference is that the TOFU policy allows a leap of faith
+# on first sight of a network ONCE - very much comparable to
+# how SSH establishes trust in a new host. This adds convenience
+# for end users who did not bother to configure their devices
+# beforehand, but adds an element of uncertainty in that the
+# attacker could be present on that first contact with the network.
+#
+# Network administrators who consider the TOFU leap of faith
+# unacceptable should choose STRICT; everyone else gains security
+# by choosing TOFU without giving up on convenience for their
+# end users.
+#
+# For completeness, it is also possible to include none of the
+# two to stay with the "anything goes" that was the situation
+# prior to Wi-Fi Certified WPA3 Release December 2019.
+#
+# This is the 'Trust Override Disabled - STRICT' policy.
+#certificatePolicies = 1.3.6.1.4.1.40808.1.3.1
+# This is the 'Trust Override Disabled - TOFU' policy.
+certificatePolicies = 1.3.6.1.4.1.40808.1.3.2
+
+#
+# Add this to the PKCS#7 keybag attributes holding the client's private key
+# for machine authentication.
+#
+# the presence of this OID tells Windows XP that the cert is intended
+# for use by the computer itself, and not by an end-user.
+#
+# The other solution is to use Microsoft's web certificate server
+# to generate these certs.
+#
+# 1.3.6.1.4.1.311.17.2
diff --git a/raddb/clients.conf b/raddb/clients.conf
new file mode 100644
index 0000000..60f9f4b
--- /dev/null
+++ b/raddb/clients.conf
@@ -0,0 +1,288 @@
+# -*- text -*-
+##
+## clients.conf -- client configuration directives
+##
+## $Id$
+
+#######################################################################
+#
+# Define RADIUS clients (usually a NAS, Access Point, etc.).
+
+#
+# Defines a RADIUS client.
+#
+# '127.0.0.1' is another name for 'localhost'. It is enabled by default,
+# to allow testing of the server after an initial installation. If you
+# are not going to be permitting RADIUS queries from localhost, we suggest
+# that you delete, or comment out, this entry.
+#
+#
+
+#
+# Each client has a "short name" that is used to distinguish it from
+# other clients.
+#
+# In version 1.x, the string after the word "client" was the IP
+# address of the client. In 2.0, the IP address is configured via
+# the "ipaddr" or "ipv6addr" fields. For compatibility, the 1.x
+# format is still accepted.
+#
+client localhost {
+ # Only *one* of ipaddr, ipv4addr, ipv6addr may be specified for
+ # a client.
+ #
+ # ipaddr will accept IPv4 or IPv6 addresses with optional CIDR
+ # notation '/<mask>' to specify ranges.
+ #
+ # ipaddr will accept domain names e.g. example.org resolving
+ # them via DNS.
+ #
+ # If both A and AAAA records are found, A records will be
+ # used in preference to AAAA.
+ ipaddr = 127.0.0.1
+
+ # Same as ipaddr but allows v4 addresses only. Requires A
+ # record for domain names.
+# ipv4addr = * # any. 127.0.0.1 == localhost
+
+ # Same as ipaddr but allows v6 addresses only. Requires AAAA
+ # record for domain names.
+# ipv6addr = :: # any. ::1 == localhost
+
+ #
+ # A note on DNS: We STRONGLY recommend using IP addresses
+ # rather than host names. Using host names means that the
+ # server will do DNS lookups when it starts, making it
+ # dependent on DNS. i.e. If anything goes wrong with DNS,
+ # the server won't start!
+ #
+ # The server also looks up the IP address from DNS once, and
+ # only once, when it starts. If the DNS record is later
+ # updated, the server WILL NOT see that update.
+ #
+
+ #
+ # The transport protocol.
+ #
+ # If unspecified, defaults to "udp", which is the traditional
+ # RADIUS transport. It may also be "tcp", in which case the
+ # server will accept connections from this client ONLY over TCP.
+ #
+ proto = *
+
+ #
+ # The shared secret use to "encrypt" and "sign" packets between
+ # the NAS and FreeRADIUS. You MUST change this secret from the
+ # default, otherwise it's not a secret any more!
+ #
+ # The secret can be any string, up to 8k characters in length.
+ #
+ # Control codes can be entered vi octal encoding,
+ # e.g. "\101\102" == "AB"
+ # Quotation marks can be entered by escaping them,
+ # e.g. "foo\"bar"
+ #
+ # A note on security: The security of the RADIUS protocol
+ # depends COMPLETELY on this secret! We recommend using a
+ # shared secret that is composed of:
+ #
+ # upper case letters
+ # lower case letters
+ # numbers
+ #
+ # And is at LEAST 8 characters long, preferably 16 characters in
+ # length. The secret MUST be random, and should not be words,
+ # phrase, or anything else that is recognisable.
+ #
+ # The default secret below is only for testing, and should
+ # not be used in any real environment.
+ #
+ secret = testing123
+
+ #
+ # Old-style clients do not send a Message-Authenticator
+ # in an Access-Request. RFC 5080 suggests that all clients
+ # SHOULD include it in an Access-Request. The configuration
+ # item below allows the server to require it. If a client
+ # is required to include a Message-Authenticator and it does
+ # not, then the packet will be silently discarded.
+ #
+ # allowed values: yes, no
+ require_message_authenticator = no
+
+ #
+ # The short name is used as an alias for the fully qualified
+ # domain name, or the IP address.
+ #
+ # It is accepted for compatibility with 1.x, but it is no
+ # longer necessary in >= 2.0
+ #
+# shortname = localhost
+
+ #
+ # the following three fields are optional, but may be used by
+ # checkrad.pl for simultaneous use checks
+ #
+
+ #
+ # The nas_type tells 'checkrad.pl' which NAS-specific method to
+ # use to query the NAS for simultaneous use.
+ #
+ # Permitted NAS types are:
+ #
+ # cisco
+ # computone
+ # livingston
+ # juniper
+ # max40xx
+ # multitech
+ # netserver
+ # pathras
+ # patton
+ # portslave
+ # tc
+ # usrhiper
+ # other # for all other types
+
+ #
+ nas_type = other # localhost isn't usually a NAS...
+
+ #
+ # The following two configurations are for future use.
+ # The 'naspasswd' file is currently used to store the NAS
+ # login name and password, which is used by checkrad.pl
+ # when querying the NAS for simultaneous use.
+ #
+# login = !root
+# password = someadminpas
+
+ #
+ # As of 2.0, clients can also be tied to a virtual server.
+ # This is done by setting the "virtual_server" configuration
+ # item, as in the example below.
+ #
+# virtual_server = home1
+
+ #
+ # A pointer to the "home_server_pool" OR a "home_server"
+ # section that contains the CoA configuration for this
+ # client. For an example of a coa home server or pool,
+ # see raddb/sites-available/originate-coa
+# coa_server = coa
+
+ #
+ # Response window for proxied packets. If non-zero,
+ # then the lower of (home, client) response_window
+ # will be used.
+ #
+ # i.e. it can be used to lower the response_window
+ # packets from one client to a home server. It cannot
+ # be used to raise the response_window.
+ #
+# response_window = 10.0
+
+ #
+ # Connection limiting for clients using "proto = tcp".
+ #
+ # This section is ignored for clients sending UDP traffic
+ #
+ limit {
+ #
+ # Limit the number of simultaneous TCP connections from a client
+ #
+ # The default is 16.
+ # Setting this to 0 means "no limit"
+ max_connections = 16
+
+ # The per-socket "max_requests" option does not exist.
+
+ #
+ # The lifetime, in seconds, of a TCP connection. After
+ # this lifetime, the connection will be closed.
+ #
+ # Setting this to 0 means "forever".
+ lifetime = 0
+
+ #
+ # The idle timeout, in seconds, of a TCP connection.
+ # If no packets have been received over the connection for
+ # this time, the connection will be closed.
+ #
+ # Setting this to 0 means "no timeout".
+ #
+ # We STRONGLY RECOMMEND that you set an idle timeout.
+ #
+ idle_timeout = 30
+ }
+}
+
+# IPv6 Client
+client localhost_ipv6 {
+ ipv6addr = ::1
+ secret = testing123
+}
+
+# All IPv6 Site-local clients
+#client sitelocal_ipv6 {
+# ipv6addr = fe80::/16
+# secret = testing123
+#}
+
+#client example.org {
+# ipaddr = radius.example.org
+# secret = testing123
+#}
+
+#
+# You can now specify one secret for a network of clients.
+# When a client request comes in, the BEST match is chosen.
+# i.e. The entry from the smallest possible network.
+#
+#client private-network-1 {
+# ipaddr = 192.0.2.0/24
+# secret = testing123-1
+#}
+
+#client private-network-2 {
+# ipaddr = 198.51.100.0/24
+# secret = testing123-2
+#}
+
+#######################################################################
+#
+# Per-socket client lists. The configuration entries are exactly
+# the same as above, but they are nested inside of a section.
+#
+# You can have as many per-socket client lists as you have "listen"
+# sections, or you can re-use a list among multiple "listen" sections.
+#
+# Un-comment this section, and edit a "listen" section to add:
+# "clients = per_socket_clients". That IP address/port combination
+# will then accept ONLY the clients listed in this section.
+#
+# There are additional considerations when using clients from SQL.
+#
+# A client can be link to a virtual server via modules such as SQL.
+# This link is done via the following process:
+#
+# If there is no listener in a virtual server, SQL clients are added
+# to the global list for that virtual server.
+#
+# If there is a listener, and the first listener does not have a
+# "clients=..." configuration item, SQL clients are added to the
+# global list.
+#
+# If there is a listener, and the first one does have a "clients=..."
+# configuration item, SQL clients are added to that list. The client
+# { ...} ` configured in that list are also added for that listener.
+#
+# The only issue is if you have multiple listeners in a virtual
+# server, each with a different client list, then the SQL clients are
+# added only to the first listener.
+#
+#clients per_socket_clients {
+# client socket_client {
+# ipaddr = 192.0.2.4
+# secret = testing123
+# }
+#}
diff --git a/raddb/debug.conf b/raddb/debug.conf
new file mode 100644
index 0000000..99f0725
--- /dev/null
+++ b/raddb/debug.conf
@@ -0,0 +1,9 @@
+#
+# Minimal configuration file used when debugging the source code.
+#
+# This file should not be installed by "make install", or by any
+# packaging system. It is only for developers.
+#
+#libdir = ${confdir}/../build/lib/
+
+$INCLUDE ${confdir}/radiusd.conf
diff --git a/raddb/dictionary b/raddb/dictionary
new file mode 100644
index 0000000..ad56be7
--- /dev/null
+++ b/raddb/dictionary
@@ -0,0 +1,49 @@
+#
+# This is the local dictionary file which can be
+# edited by local administrators. It will be loaded
+# AFTER the main dictionary files are loaded.
+#
+# FreeRADIUS will automatically load the main dictionary files
+# from:
+#
+# ${prefix}/share/freeradius/dictionary
+#
+# It is no longer necessary for this file to $INCLUDE
+# the main dictionaries. However, if the $INCLUDE
+# line is here, nothing bad will happen.
+#
+# Any new/changed attributes MUST be placed in this file.
+# The pre-defined dictionaries SHOULD NOT be edited.
+#
+# See "man dictionary" for documentation on its format.
+#
+# $Id$
+#
+
+#
+# All local attributes and $INCLUDE's should go into
+# this file.
+#
+
+# If you want to add entries to the dictionary file,
+# which are NOT going to be placed in a RADIUS packet,
+# add them to the 'dictionary.local' file.
+#
+# The numbers you pick should be between 3000 and 4000.
+# These attributes will NOT go into a RADIUS packet.
+#
+# If you want that, you will need to use VSAs. This means
+# requesting allocation of a Private Enterprise Code from
+# http://iana.org. We STRONGLY suggest doing that only if
+# you are a vendor of RADIUS equipment.
+#
+# See RFC 6158 for more details.
+# http://ietf.org/rfc/rfc6158.txt
+#
+
+#
+# These attributes are examples
+#
+#ATTRIBUTE My-Local-String 3000 string
+#ATTRIBUTE My-Local-IPAddr 3001 ipaddr
+#ATTRIBUTE My-Local-Integer 3002 integer
diff --git a/raddb/experimental.conf b/raddb/experimental.conf
new file mode 100644
index 0000000..87d9744
--- /dev/null
+++ b/raddb/experimental.conf
@@ -0,0 +1,116 @@
+#
+# This file contains the configuration for experimental modules.
+#
+# By default, it is NOT included in the build.
+#
+# $Id$
+#
+
+# Configuration for the Python module.
+#
+# Where radiusd is a Python module, radiusd.py, and the
+# function 'authorize' is called. Here is a dummy piece
+# of code:
+#
+# def authorize(params):
+# print params
+# return (5, ('Reply-Message', 'banned'))
+#
+# The RADIUS value-pairs are passed as a tuple of tuple
+# pairs as the first argument, e.g. (('attribute1',
+# 'value1'), ('attribute2', 'value2'))
+#
+# The function return is a tuple with the first element
+# being the return value of the function.
+# The 5 corresponds to RLM_MODULE_USERLOCK. I plan to
+# write the return values as Python symbols to avoid
+# confusion.
+#
+# The remaining tuple members are the string form of
+# value-pairs which are passed on to pairmake().
+#
+python {
+ mod_instantiate = radiusd_test
+ func_instantiate = instantiate
+
+ mod_authorize = radiusd_test
+ func_authorize = authorize
+
+ mod_accounting = radiusd_test
+ func_accounting = accounting
+
+ mod_pre_proxy = radiusd_test
+ func_pre_proxy = pre_proxy
+
+ mod_post_proxy = radiusd_test
+ func_post_proxy = post_proxy
+
+ mod_post_auth = radiusd_test
+ func_post_auth = post_auth
+
+ mod_recv_coa = radiusd_test
+ func_recv_coa = recv_coa
+
+ mod_send_coa = radiusd_test
+ func_send_coa = send_coa
+
+ mod_detach = radiusd_test
+ func_detach = detach
+}
+
+
+# Configuration for the example module. Uncommenting it will cause it
+# to get loaded and initialised, but should have no real effect as long
+# it is not referenced in one of the autz/auth/preacct/acct sections
+example {
+ # Boolean variable.
+ # allowed values: {no, yes}
+ boolean = yes
+
+ # An integer, of any value.
+ integer = 16
+
+ # A string.
+ string = "This is an example configuration string"
+
+ # An IP address, either in dotted quad (1.2.3.4) or hostname
+ # (example.com)
+ ipaddr = 127.0.0.1
+
+ # A subsection
+ mysubsection {
+ anotherinteger = 1000
+ # They nest
+ deeply nested {
+ string = "This is a different string"
+ }
+ }
+}
+
+#
+# To create a dbm users file, do:
+#
+# cat test.users | rlm_dbm_parser -f /etc/raddb/users_db
+#
+# Then add 'dbm' in 'authorize' section.
+#
+# Note that even if the file has a ".db" or ".dbm" extension,
+# you may have to specify it here without that extension. This
+# is because the DBM libraries "helpfully" add a ".db" to the
+# filename, but don't check if it's already there.
+#
+dbm {
+ usersfile = ${confdir}/users_db
+}
+
+# Instantiate a couple instances of the idn module
+idn {
+}
+
+# ...more commonly known as...
+idn idna {
+}
+
+idn idna_lenient {
+ UseSTD3ASCIIRules = no
+}
diff --git a/raddb/home_servers/README.md b/raddb/home_servers/README.md
new file mode 100644
index 0000000..01267b8
--- /dev/null
+++ b/raddb/home_servers/README.md
@@ -0,0 +1,21 @@
+# Dynamic Home Servers
+
+This directory is where dynamic home servers are stored.
+
+Each file in the directory should be named for the home server domain
+name. In the above example, the filename should be
+`${raddb}/home_servers/example.com`. The name of the home server in
+the file should be the same as the filename which contains the home
+server definition.
+
+Each file in the directory should have one, and only one,
+`home_server` definition.
+
+See doc/configuration/dynamic_home_servers.md for more information on
+dynamic home_servers.
+
+See also `mods-config/realm/freeradius-naptr-to-home-server.sh` for a
+sample shell script which creates home servers.
+
+This directory also has a `tls.conf` file which contains site-specific
+TLS configuration for home servers.
diff --git a/raddb/home_servers/tls.conf b/raddb/home_servers/tls.conf
new file mode 100644
index 0000000..7a0a61c
--- /dev/null
+++ b/raddb/home_servers/tls.conf
@@ -0,0 +1,58 @@
+#
+# This file contains the configuration for the "outgoing"
+# radsec connections. It should be included by all of the
+# dynamic home server configuration files.
+#
+# This file should be customized for your local system.
+#
+# See sites-available/tls for an example of configuring a home_server
+# with TLS.
+
+ #
+ # The server does not (yet) support RadSec over DTLS.
+ #
+ proto = tcp
+
+ #
+ # Use "auth" for Eduroam, as it does not do accounting.
+ #
+ # Other sites may allow "auth+acct".
+ #
+ type = auth
+
+ #
+ # The secret for RadSec is ALWAYS "radsec".
+ #
+ secret = radsec
+
+ #
+ # Similarly to HTTP, the client can use Server Name
+ # Indication to inform the RadSec server as to which
+ # domain it is requesting. This selection allows
+ # multiple sites to exist at the same IP address.
+ #
+ # This configuration sets the hostname sent in SNI.
+ #
+# hostname = example.org
+
+ #
+ # Outbound radsec requires a "tls" subsection.
+ #
+ tls {
+ #
+ # This is the *client* certificate used to connect outbound to the radsec server.
+ #
+ # It MUST be signed by a CA which is known to the radsec server.
+ #
+ certificate_file = ${certdir}/radsec-client.pem
+
+ private_key_file = ${certdir}/radsec-client.key
+ private_key_password = whatever
+
+ ca_path = ${cadir}
+
+ #
+ # See sites-available/tls, and the "home_server tls" subsection for more
+ # documentation on which configuration items are allowed here.
+ #
+ }
diff --git a/raddb/mods-available/README.rst b/raddb/mods-available/README.rst
new file mode 100644
index 0000000..79ed5c3
--- /dev/null
+++ b/raddb/mods-available/README.rst
@@ -0,0 +1,116 @@
+Modules in Version 3
+====================
+
+As of Version 3, all of the modules have been placed in the
+"mods-available/" directory. This practice follows that used by other
+servers such as Nginx, Apache, etc. The "modules" directory should
+not be used.
+
+Modules are enabled by creating a file in the mods-enabled/ directory.
+You can also create a soft-link from one directory to another::
+
+ $ cd raddb/mods-enabled
+ $ ln -s ../mods-available/foo
+
+This will enable module "foo". Be sure that you have configured the
+module correctly before enabling it, otherwise the server will not
+start. You can verify the server configuration by running
+"radiusd -XC".
+
+A large number of modules are enabled by default. This allows the
+server to work with the largest number of authentication protocols.
+Please be careful when disabling modules. You will likely need to
+edit the "sites-enabled/" files to remove references to any disabled
+modules.
+
+Conditional Modules
+-------------------
+
+Version 3 allows modules to be conditionally loaded. This is useful
+when you want to have a virtual server which references a module, but
+does not require it. Instead of editing the virtual server file, you
+can just conditionally enable the module.
+
+Modules are conditionally enabled by adding a "-" before their name in
+a virtual server. For example, you can do::
+
+ server {
+ authorize {
+ ...
+ ldap
+ -sql
+ ...
+ }
+ }
+
+This says "require the LDAP module, but use the SQL module only if it
+is configured."
+
+This feature is not very useful for production configurations. It is,
+however, very useful for the default examples that ship with the
+server.
+
+Ignoring module
+---------------
+
+If you see this message::
+
+ Ignoring module (see raddb/mods-available/README.rst)
+
+Then you are in the right place. Most of the time this message can be
+ignored. The message can be fixed by finding the references to "-module"
+in the virtual server, and deleting them.
+
+Another way to fix it is to configure the module, as described above.
+
+Simplification
+--------------
+
+Allowing conditional modules simplifies the default virtual servers
+that are shipped with FreeRADIUS. This means that if you want to
+enable LDAP (for example), you no longer need to edit the files in
+raddb/sites-available/ in order to enable it.
+
+Instead, you should edit the raddb/mods-available/ldap file to point
+to your local LDAP server. Then, enable the module via the soft-link
+method described above.
+
+Once the module is enabled, it will automatically be used in the
+default configuration.
+
+Multiple Instances
+------------------
+
+It is sometimes necessary to have the same module do two different
+things. The server supports this functionality via "instances" of
+modules.
+
+Normally, a module configuration looks like this:
+
+ sql {
+ ... sql stuff ...
+ }
+
+This module is then refereed to as the "sql" module.
+
+
+But what happens if you want to connect to two different SQL
+databases? The solution is simple; copy the "sql" module
+configuration, and add an instance name after the "sql" string:
+
+ sql mysql1 {
+ ... configuration for connecting to mysql11 ...
+ }
+
+ sql mysql2 {
+ ... configuration for connecting to mysql12 ...
+ }
+
+This configuration says "load the SQL module, but create two copies of
+it, with different configurations". The different configurations can
+be referred to by name, as "mysql1" and "mysql2". That is, anywhere
+you would normally use "sql", you could use either "mysql1" or
+"mysql2".
+
+For further examples of using module instances, see the "attr_filter"
+module configuration in this directory.
diff --git a/raddb/mods-available/abfab_psk_sql b/raddb/mods-available/abfab_psk_sql
new file mode 100644
index 0000000..d75130d
--- /dev/null
+++ b/raddb/mods-available/abfab_psk_sql
@@ -0,0 +1,15 @@
+# -*- text -*-
+##
+## Module for PSK authorizations from ABFAB trust router
+##
+## $Id$
+
+sql psksql {
+
+ driver = "rlm_sql_sqlite"
+
+ sqlite {
+ filename = "/var/lib/trust_router/keys"
+ }
+
+}
diff --git a/raddb/mods-available/always b/raddb/mods-available/always
new file mode 100644
index 0000000..b77d00c
--- /dev/null
+++ b/raddb/mods-available/always
@@ -0,0 +1,81 @@
+# -*- text -*-
+#
+# $Id$
+
+#
+# The "always" module is here for debugging purposes, or
+# for use in complex policies.
+# Instance simply returns the same result, always, without
+# doing anything.
+#
+# rcode may be one of the following values:
+# - reject - Reject the user.
+# - fail - Simulate or indicate a failure.
+# - ok - Simulate or indicate a success.
+# - handled - Indicate that the request has been handled,
+# stop processing, and send response if set.
+# - invalid - Indicate that the request is invalid.
+# - userlock - Indicate that the user account has been
+# locked out.
+# - notfound - Indicate that a user account can't be found.
+# - noop - Simulate a no-op.
+# - updated - Indicate that the request has been updated.
+#
+# If an instance is listed in a session {} section,
+# this simulates a user having <integer> sessions.
+#
+# simulcount = <integer>
+#
+# If an instance is listed in a session {} section,
+# this simulates the user having multilink
+# sessions.
+#
+# mpp = <integer>
+#
+# An xlat based on the instance name can be called to change the status
+# returned by the instance, in this example "always db_status { ... }"
+#
+# Force the module status to be alive or dead:
+#
+# %{db_status:alive}
+# %{db_status:dead}
+#
+# Update the rcode returned by an alive module (a dead module returns fail):
+#
+# %{db_status:ok}
+# %{db_status:fail}
+# %{db_status:notfound}
+# ...
+#
+# The above xlats expand to the current status of the module. To fetch the
+# current status without affecting it call the xlat with an empty argument:
+#
+# %{db_status:}
+#
+always reject {
+ rcode = reject
+}
+always fail {
+ rcode = fail
+}
+always ok {
+ rcode = ok
+}
+always handled {
+ rcode = handled
+}
+always invalid {
+ rcode = invalid
+}
+always userlock {
+ rcode = userlock
+}
+always notfound {
+ rcode = notfound
+}
+always noop {
+ rcode = noop
+}
+always updated {
+ rcode = updated
+}
diff --git a/raddb/mods-available/attr_filter b/raddb/mods-available/attr_filter
new file mode 100644
index 0000000..a23d3c0
--- /dev/null
+++ b/raddb/mods-available/attr_filter
@@ -0,0 +1,61 @@
+# -*- text -*-
+#
+# $Id$
+
+#
+# This file defines a number of instances of the "attr_filter" module.
+#
+
+# 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 attr_filter.post-proxy {
+ key = "%{Realm}"
+ filename = ${modconfdir}/${.:name}/post-proxy
+}
+
+# attr_filter - filters the attributes in the packets we send to
+# the RADIUS home servers.
+attr_filter attr_filter.pre-proxy {
+ key = "%{Realm}"
+ filename = ${modconfdir}/${.:name}/pre-proxy
+}
+
+# Enforce RFC requirements on the contents of Access-Reject
+# packets. See the comments at the top of the file for
+# more details.
+#
+attr_filter attr_filter.access_reject {
+ key = "%{User-Name}"
+ filename = ${modconfdir}/${.:name}/access_reject
+}
+
+# Enforce RFC requirements on the contents of Access-Challenge
+# packets. See the comments at the top of the file for
+# more details.
+#
+attr_filter attr_filter.access_challenge {
+ key = "%{User-Name}"
+ filename = ${modconfdir}/${.:name}/access_challenge
+}
+
+
+# Enforce RFC requirements on the contents of the
+# Accounting-Response packets. See the comments at the
+# top of the file for more details.
+#
+attr_filter attr_filter.accounting_response {
+ key = "%{User-Name}"
+ filename = ${modconfdir}/${.:name}/accounting_response
+}
+
+#
+# Enforce CoA or Disconnect packets.
+#
+# Note that you MUST edit the "coa" file below for your
+# local configuration. Add in any attributes needed by the NAS.
+#
+attr_filter attr_filter.coa {
+ key = "%{User-Name}"
+ filename = ${modconfdir}/${.:name}/coa
+}
diff --git a/raddb/mods-available/cache b/raddb/mods-available/cache
new file mode 100644
index 0000000..cf0054f
--- /dev/null
+++ b/raddb/mods-available/cache
@@ -0,0 +1,150 @@
+# -*- text -*-
+#
+# $Id$
+
+#
+# A module to cache attributes. The idea is that you can look
+# up information in a database, and then cache it. Repeated
+# requests for the same information will then have the cached
+# values added to the request.
+#
+# The module can cache a fixed set of attributes per key.
+# It can be listed in "authorize", "post-auth", "pre-proxy"
+# and "post-proxy".
+#
+# If you want different things cached for authorize and post-auth,
+# you will need to define two instances of the "cache" module.
+#
+# The module returns "ok" if it found or created a cache entry.
+# The module returns "updated" if it merged a cached entry.
+# The module returns "noop" if it did nothing.
+# The module returns "fail" on error.
+#
+cache {
+ # The backend datastore used to store the cache entries.
+ # Current datastores are
+ # rlm_cache_rbtree - An in memory, non persistent rbtree based datastore.
+ # Useful for caching data locally.
+ # rlm_cache_memcached - A non persistent "webscale" distributed datastore.
+ # Useful if the cached data need to be shared between
+ # a cluster of RADIUS servers.
+ # rlm_cache_redis - uses Redis.
+# driver = "rlm_cache_rbtree"
+
+ #
+ # Some drivers accept specific options, to set them a
+ # config section with the the name as the driver should be added
+ # to the cache instance.
+ #
+ # Driver specific options are:
+ #
+# memcached {
+# # Memcached configuration options, as documented here:
+# # http://docs.libmemcached.org/libmemcached_configuration.html#memcached
+# options = "--SERVER=localhost"
+#
+# pool {
+# start = ${thread[pool].start_servers}
+# min = ${thread[pool].min_spare_servers}
+# max = ${thread[pool].max_servers}
+# spare = ${thread[pool].max_spare_servers}
+# uses = 0
+# lifetime = 0
+# idle_timeout = 60
+# }
+# }
+
+ #
+ # See mods-available/redis for documentation on the following
+ # configuration items. They are identical here.
+ #
+ # Note that the "pool" section can re-use the normal Redis
+ # connections. This is done by setting the "pool" configuration
+ # item to the name of the Redis module. The other configuration
+ # items should then be the same as for the original "redis" module.
+ #
+# redis {
+# server = ...
+# port =
+# database =
+# query_timeout = ...
+# pool = redis
+# }
+
+ # The key used to index the cache. It is dynamically expanded
+ # at run time.
+ key = "%{User-Name}"
+
+ # The TTL of cache entries, in seconds. Entries older than this
+ # will be expired.
+ #
+ # This value should be between 10 and 86400.
+ ttl = 10
+
+ # If yes the following attributes will be added to the request:
+ # * &request:Cache-Entry-Hits - The number of times this entry
+ # has been retrieved.
+ #
+ # Note: Not supported by the rlm_cache_memcached module.
+ add_stats = no
+
+ #
+ # The list of attributes to cache for a particular key.
+ #
+ # Each key gets the same set of cached attributes. The attributes
+ # are dynamically expanded at run time.
+ #
+ # The semantics of this construct are identical to an unlang
+ # update block, except the left hand side of the expression
+ # represents the cache entry. see man unlang for more information
+ # on update blocks.
+ #
+ # Note: Only request, reply, control and session-state lists
+ # are available in cache entries. Attempting to store attributes
+ # in other lists will raise an error during config validation.
+ #
+ update {
+ # <list>:<attribute> <op> <value>
+
+ # Cache all instances of Reply-Message in the reply list
+ &reply:Reply-Message += &reply:Reply-Message[*]
+
+ # Add our own to show when the cache was last updated
+ &reply:Reply-Message += "Cache last updated at %t"
+
+ &reply:Class := "%{randstr:ssssssssssssssssssssssssssssssss}"
+ }
+
+ # This module supports a number of runtime configuration parameters
+ # represented by attributes in the &control: list.
+ #
+ # &control:Cache-TTL - Sets the TTL of an entry to be created, or
+ # modifies the TTL of an existing entry.
+ # - Setting a Cache-TTL of > 0 means set the TTL of the entry to
+ # the new value (and reset the expiry timer).
+ # - Setting a Cache-TTL of < 0 means expire the existing entry
+ # (without merging) and create a new one with TTL set to
+ # value * -1.
+ # - Setting a Cache-TTL of 0 means expire the existing entry
+ # (without merging) and don't create a new one.
+ #
+ # &control:Cache-Status-Only - If present and set to 'yes' will
+ # prevent a new entry from being created, and existing entries from
+ # being merged. It will also alter the module's return codes.
+ # - The module will return "ok" if a cache entry was found.
+ # - The module will return "notfound" if no cache entry was found.
+ #
+ # &control:Cache-Read-Only - If present and set to 'yes' will
+ # prevent a new entry from being created, but will allow existing
+ # entries to be merged. It will also alter the module's return codes.
+ # - The module will return "updated" if a cache entry was found.
+ # - The module will return "notfound" if no cache was found.
+ #
+ # &control:Cache-Merge - If present and set to 'yes' will merge new
+ # cache entries into the current request. Useful if results
+ # of execs or expansions are stored directly in the cache.
+ #
+ # All runtime configuration attributes will be removed from the
+ # &control: list after the cache module is called.
+
+}
diff --git a/raddb/mods-available/cache_auth b/raddb/mods-available/cache_auth
new file mode 100644
index 0000000..7485f36
--- /dev/null
+++ b/raddb/mods-available/cache_auth
@@ -0,0 +1,116 @@
+# -*- text -*-
+#
+# $Id$
+
+# This file contains a collection of cache module configurations
+# which have been designed to be used to cache accepts, rejects, and
+# LDAP User DNs. The main use of these modules is Google Secure
+# LDAP.
+#
+# In scenarios where there is repeated authentication requests for the same
+# user within a short time frame (e.g. 802.1x wifi), these modules can help to
+# compensate for slow responses from poor LDAP servers (i.e. Google).
+#
+# See also mods-available/ldap_google, and sites-available/google-ldap-auth.
+#
+# The configurations in this file can be used for non-Google LDAP
+# servers, too.
+#
+
+
+#
+# This instance of the cache module caches successful
+# authentications.
+#
+# The TTL controls how often the authentication will be cached.
+#
+# In addition, if group membership is used as part of the policy, the
+# &control:LDAP-Group attribute should be added to the "update: section here.
+#
+# If a user's authentication is found in the cache, then any data
+# which is normally retrieved from LDAP for local policies must also
+# be stored in the cache via the "update" section.
+#
+cache cache_auth_accept {
+ driver = "rlm_cache_rbtree"
+ key = "%{md5:%{%{Stripped-User-Name}:-%{User-Name}}%{User-Password}}"
+ ttl = 7200
+ update {
+ #
+ # We need to cache something, so we just cache
+ # a random attribute. This attribute is not used
+ # for anything else, just as a "place-holder" to
+ # contain a cache entry.
+ #
+ # If you add other attributes to this update section, then
+ # this attribute can be deleted.
+ #
+ &control:User-Category = "success"
+ }
+}
+
+
+#
+# This instance of the cache module caches failed authentications.
+#
+# In many cases, rejected users will repeatedly try to authenticate.
+# These repeated authentication attempts can cause significant load
+# on the system. By caching the reject, we can avoid hitting the database.
+#
+# We index the cache by a hash of the client's MAC and the user name
+# and password. If a user corrects their user name or password, then
+# that authentication attempt won't hit the cache, and their
+# credentials will be immediately checked against the database.
+#
+# The TTL controls how long a combination of device / user and
+# password wil be rejected without looking at the database. Once the
+# cache entry expires, the server will delete the cache entry, and
+# contact the database.
+#
+cache cache_auth_reject {
+ driver = "rlm_cache_rbtree"
+ key = "%{md5:%{Calling-Station-Id}%{Stripped-User-Name}%{User-Password}}"
+ ttl = 3600
+ update {
+ #
+ # We need to cache something, so we just cache
+ # a random attribute. This attribute is not used
+ # for anything else, just as a "place-holder" to
+ # contain a cache entry.
+ #
+ &control:User-Category = "failure"
+ }
+}
+
+
+#
+# An instance of the cache module which caches the LDAP user DN.
+#
+# If LDAP authentication is being used for a simple auth / reject without
+# any need to retrieve other attributes (e.g. group membership), each LDAP
+# bind authentication is three steps
+#
+# - bind as admin user
+# - lookup user's DN
+# - bind as user using retrieved DN
+#
+# By caching the DN after the first LDAP querry, the first two steps
+# are skipped on subsequent authentications.
+#
+# If an alternative attribute name is being used for the user DN, you
+# should change the update section here appropriately. But that is
+# likely rare.
+#
+# In scenarios where DNs may change, consideration should be given as
+# to whether use of this cache may create issues. i.e. if the cache
+# doesn't help, then don't use it.
+#
+cache cache_ldap_user_dn {
+ driver = "rlm_cache_rbtree"
+ key = "%{Stripped-User-Name}"
+ ttl = 86400
+ update {
+ &control:LDAP-UserDN = &control:LDAP-UserDN
+ }
+}
+
diff --git a/raddb/mods-available/chap b/raddb/mods-available/chap
new file mode 100644
index 0000000..e2a3cd3
--- /dev/null
+++ b/raddb/mods-available/chap
@@ -0,0 +1,11 @@
+# -*- text -*-
+#
+# $Id$
+
+# CHAP module
+#
+# To authenticate requests containing a CHAP-Password attribute.
+#
+chap {
+ # no configuration
+}
diff --git a/raddb/mods-available/couchbase b/raddb/mods-available/couchbase
new file mode 100644
index 0000000..da1a39d
--- /dev/null
+++ b/raddb/mods-available/couchbase
@@ -0,0 +1,204 @@
+couchbase {
+ #
+ # List of Couchbase hosts (hosts may be space, tab, comma or semi-colon separated).
+ # Ports are optional if servers are listening on the standard port.
+ # Complete pool urls are preferred.
+ #
+ server = "http://cb01.blargs.com:8091/pools/ http://cb04.blargs.com:8091/pools/"
+
+ # Couchbase bucket name
+ bucket = "radius"
+
+ # Couchbase bucket password (optional)
+ #password = "password"
+
+ # Couchbase accounting document key (unlang supported)
+ acct_key = "radacct_%{%{Acct-Unique-Session-Id}:-%{Acct-Session-Id}}"
+
+ # Value for the 'docType' element in the json body for accounting documents
+ doctype = "radacct"
+
+ ## Accounting document expire time in seconds (0 = never)
+ expire = 2592000
+
+ #
+ # Map attribute names to json element names for accounting.
+ #
+ # Configuration items are in the format:
+ # <radius attribute> = '<element name>'
+ #
+ # Element names should be single quoted.
+ #
+ # Note: Attributes not in this map will not be recorded.
+ #
+ update {
+ Acct-Session-Id = 'sessionId'
+ Acct-Unique-Session-Id = 'uniqueId'
+ Acct-Status-Type = 'lastStatus'
+ Acct-Authentic = 'authentic'
+ User-Name = 'userName'
+ Stripped-User-Name = 'strippedUserName'
+ Stripped-User-Domain = 'strippedUserDomain'
+ Realm = 'realm'
+ NAS-IP-Address = 'nasIpAddress'
+ NAS-Identifier = 'nasIdentifier'
+ NAS-Port = 'nasPort'
+ Called-Station-Id = 'calledStationId'
+ Called-Station-SSID = 'calledStationSSID'
+ Calling-Station-Id = 'callingStationId'
+ Framed-Protocol = 'framedProtocol'
+ Framed-IP-Address = 'framedIpAddress'
+ NAS-Port-Type = 'nasPortType'
+ Connect-Info = 'connectInfo'
+ Acct-Session-Time = 'sessionTime'
+ Acct-Input-Packets = 'inputPackets'
+ Acct-Output-Packets = 'outputPackets'
+ Acct-Input-Octets = 'inputOctets'
+ Acct-Output-Octets = 'outputOctets'
+ Acct-Input-Gigawords = 'inputGigawords'
+ Acct-Output-Gigawords = 'outputGigawords'
+ Event-Timestamp = 'lastUpdated'
+ }
+
+ # Couchbase document key for user documents (unlang supported)
+ user_key = "raduser_%{md5:%{tolower:%{%{Stripped-User-Name}:-%{User-Name}}}}"
+
+ # Set to 'yes' to read radius clients from the Couchbase view specified below.
+ # NOTE: Clients will ONLY be read on server startup.
+ #read_clients = no
+
+ #
+ # Map attribute names to json element names when loading clients.
+ #
+ # Configuration follows the same rules as the accounting map above.
+ #
+ client {
+ # Couchbase view that should return all available client documents.
+ view = "_design/client/_view/by_id"
+
+ #
+ # Sets default values (not obtained from couchbase) 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 mappings are in the format:
+ # <client attribute> = '<element name>'
+ #
+ # Element names should be single quoted.
+ #
+ # The following attributes are required:
+ # * ipaddr | ipv4addr | ipv6addr - Client IP Address.
+ # * secret - RADIUS shared secret.
+ #
+ # All attributes usually supported in a client
+ # definition are also supported here.
+ #
+ attribute {
+ ipaddr = 'clientIdentifier'
+ secret = 'clientSecret'
+ shortname = 'clientShortname'
+ nas_type = 'nasType'
+ virtual_server = 'virtualServer'
+ require_message_authenticator = 'requireMessageAuthenticator'
+ limit {
+ max_connections = 'maxConnections'
+ lifetime = 'clientLifetime'
+ idle_timeout = 'idleTimeout'
+ }
+ }
+ }
+
+ # Set to 'yes' to enable simultaneous use checking (multiple logins).
+ # NOTE: This will cause the execution of a view request on every check
+ # and may be a performance penalty.
+# check_simul = no
+
+ # Couchbase view that should return all account documents keyed by username.
+# simul_view = "_design/acct/_view/by_user"
+
+ # The key to the above view.
+ # NOTE: This will need to match EXACTLY what you emit from your view.
+# simul_vkey = "%{tolower:%{%{Stripped-User-Name}:-%{User-Name}}}"
+
+ # Set to 'yes' to enable verification of the results returned from the above view.
+ # NOTE: This may be an additional performance penalty to the actual check and
+ # should be avoided unless absolutely neccessary.
+# verify_simul = no
+
+ # Remove stale session if checkrad does not see a double login.
+ # NOTE: This will only be executed if both check_simul and verify_simul
+ # are set to 'yes' above.
+# delete_stale_sessions = yes
+
+ #
+ # The connection pool is used to pool outgoing connections.
+ #
+ pool {
+ # Connections to create during module instantiation.
+ # If the server cannot create specified number of
+ # connections during instantiation it will exit.
+ # Set to 0 to allow the server to start without the
+ # couchbase being available.
+ start = ${thread[pool].start_servers}
+
+ # Minimum number of connections to keep open
+ min = ${thread[pool].min_spare_servers}
+
+ # Maximum number of connections
+ #
+ # If these connections are all in use and a new one
+ # is requested, the request will NOT get a connection.
+ #
+ # Setting 'max' to LESS than the number of threads means
+ # that some threads may starve, and you will see errors
+ # like 'No connections available and at max connection limit'
+ #
+ # Setting 'max' to MORE than the number of threads means
+ # that there are more connections than necessary.
+ max = ${thread[pool].max_servers}
+
+ # Spare connections to be left idle
+ #
+ # NOTE: Idle connections WILL be closed if "idle_timeout"
+ # is set. This should be less than or equal to "max" above.
+ spare = ${thread[pool].max_spare_servers}
+
+ # Number of uses before the connection is closed
+ #
+ # 0 means "infinite"
+ uses = 0
+
+ # The lifetime (in seconds) of the connection
+ #
+ # NOTE: A setting of 0 means infinite (no limit).
+ lifetime = 0
+
+ # The idle timeout (in seconds). A connection which is
+ # unused for this length of time will be closed.
+ #
+ # NOTE: A setting of 0 means infinite (no timeout).
+ idle_timeout = 1200
+
+ # NOTE: All configuration settings are enforced. If a
+ # connection is closed because of "idle_timeout",
+ # "uses", or "lifetime", then the total number of
+ # connections MAY fall below "min". When that
+ # happens, it will open a new connection. It will
+ # also log a WARNING message.
+ #
+ # The solution is to either lower the "min" connections,
+ # or increase lifetime/idle_timeout.
+ }
+}
diff --git a/raddb/mods-available/counter b/raddb/mods-available/counter
new file mode 100644
index 0000000..a5ac1e6
--- /dev/null
+++ b/raddb/mods-available/counter
@@ -0,0 +1,82 @@
+# -*- text -*-
+#
+# $Id$
+
+# 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 omitted 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 ELSE and if the reply_name is
+# set, we send back that attribute. The reply_name attribute
+# MUST be of an integer type.
+#
+# 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_service_type 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 = ${db_dir}/db.daily
+ key = User-Name
+ count_attribute = Acct-Session-Time
+ reset = daily
+ counter_name = Daily-Session-Time
+ check_name = Max-Daily-Session
+ reply_name = Session-Timeout
+ allowed_service_type = Framed-User
+ cache_size = 5000
+}
+
diff --git a/raddb/mods-available/cui b/raddb/mods-available/cui
new file mode 100644
index 0000000..54842d4
--- /dev/null
+++ b/raddb/mods-available/cui
@@ -0,0 +1,53 @@
+# -*- text -*-
+#
+# $Id$
+
+#
+# Write Chargeable-User-Identity to the database.
+#
+# Schema raddb/mods-config/sql/cui/<DB>/schema.sql
+# Queries raddb/mods-config/sql/cui/<DB>/queries.conf
+#
+sql cuisql {
+
+ # The dialect of SQL you want to use, this should usually match
+ # the driver below.
+ #
+ # If you're using rlm_sql_null, then it should be the type of
+ # database the logged queries are going to be executed against.
+ dialect = "sqlite"
+
+ # The sub-module to use to execute queries. This should match
+ # the database you're attempting to connect to.
+ #
+ # There are CUI queries available for:
+ # * rlm_sql_mysql
+ # * rlm_sql_postgresql
+ # * rlm_sql_sqlite
+ # * rlm_sql_null (log queries to disk)
+ #
+ driver = "rlm_sql_${dialect}"
+
+ sqlite {
+ filename = ${radacctdir}/cui.sqlite
+ bootstrap = ${modconfdir}/${..:name}/cui/sqlite/schema.sql
+ }
+
+ # Write CUI queries to a logfile. Useful for debugging.
+# logfile = ${logdir}/cuilog.sql
+
+ pool {
+ start = 5
+ min = 4
+ max = 10
+ spare = 3
+ uses = 0
+ lifetime = 0
+ idle_timeout = 60
+ }
+
+ cui_table = "cui"
+ sql_user_name = "%{User-Name}"
+
+ $INCLUDE ${modconfdir}/${.:name}/cui/${dialect}/queries.conf
+}
diff --git a/raddb/mods-available/date b/raddb/mods-available/date
new file mode 100644
index 0000000..25a64da
--- /dev/null
+++ b/raddb/mods-available/date
@@ -0,0 +1,35 @@
+#
+# Registers xlat to convert between time formats.
+#
+# xlat input string is an attribute name. If this attribute is of date
+# or integer type, the date xlat will convert it to a time string in
+# the format of the format config item.
+#
+# If the attribute is a string type, date will attempt to parse it in
+# the format specified by the format config item, and will expand
+# to a Unix timestamp.
+#
+date {
+ format = "%b %e %Y %H:%M:%S %Z"
+
+ # Use UTC instead of local time.
+ #
+ # default = no
+# utc = yes
+}
+
+#
+# The WISPr-Session-Terminate-Time attribute is of type "string",
+# and not "date". Use this expansion to create an attribute
+# that holds an actual date:
+#
+# Tmp-Date-0 := "%{wispr2date:&reply:WISPr-Session-Terminate-Time}"
+#
+date wispr2date {
+ format = "%Y-%m-%dT%H:%M:%S"
+
+ # Use UTC instead of local time.
+ #
+ # default = no
+# utc = yes
+}
diff --git a/raddb/mods-available/detail b/raddb/mods-available/detail
new file mode 100644
index 0000000..ccf65f9
--- /dev/null
+++ b/raddb/mods-available/detail
@@ -0,0 +1,109 @@
+# -*- text -*-
+#
+# $Id$
+
+# 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 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.
+ #
+ # If you are reading detail files via the "listen" section
+ # (e.g. as in raddb/sites-available/robust-proxy-accounting),
+ # you MUST use a unique directory for each combination of a
+ # detail file writer, and reader. That is, there can only
+ # be ONE "listen" section reading detail files from a
+ # particular directory.
+ #
+ # The configuration below puts the detail files into separate
+ # directories for each client. If you are reading the detail
+ # files via the "listen" section, just use one directory.
+ #
+ # e.g. filename = ${radacctdir}/reader1/detail-%Y%m%d
+ #
+ # AND use a separate directory (reader2, reader3, etc.) for each
+ # reader.
+ #
+ filename = ${radacctdir}/%{%{Packet-Src-IP-Address}:-%{Packet-Src-IPv6-Address}}/detail-%Y%m%d
+
+ #
+ # If you are using radrelay, delete the above line for "file",
+ # and use this one instead:
+ #
+# filename = ${radacctdir}/detail
+
+ #
+ # Most file systems can handly nearly the full range of UTF-8
+ # characters. Ones that can deal with a limited range should
+ # set this to "yes".
+ #
+ escape_filenames = no
+
+ #
+ # 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.
+ permissions = 0600
+
+ # The Unix group of the log file.
+ #
+ # The user that the server runs as must be in the specified
+ # system group otherwise this will fail to work.
+ #
+# group = ${security.group}
+
+ #
+ # Every entry in the detail file has a header which
+ # is a timestamp. By default, we use the ctime
+ # format (see "man ctime" for details).
+ #
+ # The header can be customised by editing this
+ # string. See "doc/configuration/variables.rst" for a
+ # description of what can be put here.
+ #
+ header = "%t"
+
+ #
+ # Uncomment this line if the detail file reader will be
+ # reading this detail file.
+ #
+# locking = yes
+
+ #
+ # Log the Packet src/dst IP/port. This is disabled by
+ # default, as that information isn't used by many people.
+ #
+# log_packet_header = yes
+
+ #
+ # Certain attributes such as User-Password may be
+ # "sensitive", so they should not be printed in the
+ # detail file. This section lists the attributes
+ # that should be suppressed.
+ #
+ # The attributes should be listed one to a line.
+ #
+ #suppress {
+ # User-Password
+ #}
+
+}
diff --git a/raddb/mods-available/detail.example.com b/raddb/mods-available/detail.example.com
new file mode 100644
index 0000000..827cdf5
--- /dev/null
+++ b/raddb/mods-available/detail.example.com
@@ -0,0 +1,27 @@
+# -*- text -*-
+#
+# Detail file writer, used in the following examples:
+#
+# raddb/sites-available/robust-proxy-accounting
+# raddb/sites-available/decoupled-accounting
+#
+# Note that this module can write detail files that are read by
+# only ONE "listen" section. If you use BOTH of the examples
+# above, you will need to define TWO "detail" modules.
+#
+# e.g. detail1.example.com && detail2.example.com
+#
+#
+# We write *multiple* detail files here. They will be processed by
+# the detail "listen" section in the order that they were created.
+# The directory containing these files should NOT be used for any
+# other purposes. i.e. It should have NO other files in it.
+#
+# Writing multiple detail enables the server to process the pieces
+# in smaller chunks. This helps in certain catastrophic corner cases.
+#
+# $Id$
+#
+detail detail.example.com {
+ filename = ${radacctdir}/detail.example.com/detail-%Y%m%d:%H:%G
+}
diff --git a/raddb/mods-available/detail.log b/raddb/mods-available/detail.log
new file mode 100644
index 0000000..b91cf7c
--- /dev/null
+++ b/raddb/mods-available/detail.log
@@ -0,0 +1,75 @@
+# -*- text -*-
+#
+# $Id$
+
+#
+# More examples of doing detail logs.
+
+#
+# Many people want to log authentication requests.
+# Rather than modifying the server core to print out more
+# messages, we can use a different instance of the 'detail'
+# module, to log the authentication requests to a file.
+#
+# You will also need to un-comment the 'auth_log' line
+# in the 'authorize' section, below.
+#
+detail auth_log {
+ filename = ${radacctdir}/%{%{Packet-Src-IP-Address}:-%{Packet-Src-IPv6-Address}}/auth-detail-%Y%m%d
+
+ #
+ # This MUST be 0600, otherwise anyone can read
+ # the users passwords!
+ permissions = 0600
+
+ # You may also strip out passwords completely
+ suppress {
+ User-Password
+ }
+}
+
+#
+# This module logs authentication reply packets sent
+# to a NAS. Both Access-Accept and Access-Reject packets
+# are logged.
+#
+# You will also need to un-comment the 'reply_log' line
+# in the 'post-auth' section, below.
+#
+detail reply_log {
+ filename = ${radacctdir}/%{%{Packet-Src-IP-Address}:-%{Packet-Src-IPv6-Address}}/reply-detail-%Y%m%d
+
+ permissions = 0600
+}
+
+#
+# This module logs packets proxied to a home server.
+#
+# You will also need to un-comment the 'pre_proxy_log' line
+# in the 'pre-proxy' section, below.
+#
+detail pre_proxy_log {
+ filename = ${radacctdir}/%{%{Packet-Src-IP-Address}:-%{Packet-Src-IPv6-Address}}/pre-proxy-detail-%Y%m%d
+
+ #
+ # This MUST be 0600, otherwise anyone can read
+ # the users passwords!
+ permissions = 0600
+
+ # You may also strip out passwords completely
+ #suppress {
+ # User-Password
+ #}
+}
+
+#
+# This module logs response packets from a home server.
+#
+# You will also need to un-comment the 'post_proxy_log' line
+# in the 'post-proxy' section, below.
+#
+detail post_proxy_log {
+ filename = ${radacctdir}/%{%{Packet-Src-IP-Address}:-%{Packet-Src-IPv6-Address}}/post-proxy-detail-%Y%m%d
+
+ permissions = 0600
+}
diff --git a/raddb/mods-available/dhcp b/raddb/mods-available/dhcp
new file mode 100644
index 0000000..a431633
--- /dev/null
+++ b/raddb/mods-available/dhcp
@@ -0,0 +1,19 @@
+# -*- text -*-
+#
+# $Id$
+
+#
+# This module is useful only for 'xlat'. To use it,
+# put 'dhcp' into the 'instantiate' section.
+#
+# %{dhcp_options:<Attribute-ref>} may be used to decode
+# DHCP options data included in RADIUS packets by vendors
+# of DHCP to RADIUS gateways.
+#
+# This is known to work with the following VSAs:
+# * Juniper - ERX-Dhcp-Options
+# * Alcatel lucent SR - Alc-ToServer-Dhcp-Options
+# - Alc-ToClient-Dhcp-Options
+#
+dhcp {
+}
diff --git a/raddb/mods-available/dhcp_files b/raddb/mods-available/dhcp_files
new file mode 100644
index 0000000..243a241
--- /dev/null
+++ b/raddb/mods-available/dhcp_files
@@ -0,0 +1,56 @@
+# -*- text -*-
+#
+# $Id$
+
+# Instances of the "files" module for managing DHCP options
+#
+files dhcp_network {
+ # The file containing network-specific DHCP options mapping
+ filename = ${modconfdir}/files/dhcp
+
+ # For network lookups we use a fixed key. Matching
+ # actual networks is done by additional filtering within
+ # the file
+ key = "network"
+}
+
+files dhcp_subnet {
+ # The file containing subnet-specific DHCP options mapping
+ filename = ${modconfdir}/files/dhcp
+
+ # For subnet lookups we use a fixed key. Matching
+ # actual subnets is done by additional filtering within
+ # the file
+ key = "subnet"
+}
+
+files dhcp_set_group_options {
+ # An example of looking up DHCP group options. This
+ # is designed to be called from a policy configured in
+ # policy.d/dhcp.
+ #
+ # If clients are never members of more than one group,
+ # then this could be simplified such that DHCP-Group-Name
+ # is used here in place of Foreach-Variable-0 and this
+ # module instance called directly rather than the policy
+
+ # Use the same file as for subnets - could be split
+ # for large, complex installations
+ filename = ${modconfdir}/files/dhcp
+
+ # The key is a temporary string populated by the calling policy
+ # which uses a foreach loop.
+ key = "%{Foreach-Variable-0}"
+}
+
+files dhcp_hosts {
+ # An example of a DHCP host mapping for option setting
+
+ # Use the same file as for subnets - could be split
+ # for large, complex installations
+ filename = ${modconfdir}/files/dhcp
+
+ # If a different identifier is needed for looking up
+ # host specific entries then amend this key.
+ key = "host-%{DHCP-Client-Hardware-Address}"
+}
diff --git a/raddb/mods-available/dhcp_passwd b/raddb/mods-available/dhcp_passwd
new file mode 100644
index 0000000..7884a00
--- /dev/null
+++ b/raddb/mods-available/dhcp_passwd
@@ -0,0 +1,20 @@
+# -*- text -*-
+#
+# $Id$
+
+# An instance of the passwd module designed for looking up
+# DHCP client membership. This example is based on hardware
+# address.
+# The "groups" file should be of the format:
+# <group name>|<hardware address>,<hardware address>,<hardware address>
+# <group name>|<hardware address>,<hardware address>,<hardware address>
+#
+# See the passwd module for more details.
+
+passwd dhcp_group_membership {
+ filename = "${modconfdir}/files/dhcp_groups"
+ format = "~DHCP-Group-Name:*,DHCP-Client-Hardware-Address"
+ hash_size = 100
+ allow_multiple_keys = yes
+ delimiter = "|"
+}
diff --git a/raddb/mods-available/dhcp_sql b/raddb/mods-available/dhcp_sql
new file mode 100644
index 0000000..20dbe3a
--- /dev/null
+++ b/raddb/mods-available/dhcp_sql
@@ -0,0 +1,92 @@
+# -*- text -*-
+##
+## mods-available/sql -- SQL modules
+##
+## $Id$
+
+######################################################################
+#
+# Configuration for the DHCP-specific instance of the SQL module
+#
+# The database schemas and queries are located in subdirectories:
+#
+# sql/dhcp/<DB>/schema.sql Schema
+# sql/dhcp/<DB>/queries.conf Reply options lookup queries
+#
+# Where "DB" is mysql, mssql, oracle, or postgresql.
+#
+
+#
+# See raddb/mods-available/sql for a description of the configuration items
+# for the sql module.
+#
+sql dhcp_sql {
+ dialect = "sqlite"
+ driver = "rlm_sql_null"
+# driver = "rlm_sql_${dialect}"
+
+ sqlite {
+ filename = "/tmp/freeradius.db"
+ busy_timeout = 200
+ bootstrap = "${modconfdir}/${..:name}/dhcp/sqlite/schema.sql"
+ }
+
+ mysql {
+ tls {
+ ca_file = "/etc/ssl/certs/my_ca.crt"
+ ca_path = "/etc/ssl/certs/"
+ certificate_file = "/etc/ssl/certs/private/client.crt"
+ private_key_file = "/etc/ssl/certs/private/client.key"
+ cipher = "DHE-RSA-AES256-SHA:AES128-SHA"
+
+ tls_required = yes
+ tls_check_cert = no
+ tls_check_cert_cn = no
+ }
+ warnings = auto
+ }
+
+ postgresql {
+ send_application_name = yes
+ }
+
+ mongo {
+ appname = "freeradius"
+ tls {
+ certificate_file = /path/to/file
+ certificate_password = "password"
+ ca_file = /path/to/file
+ ca_dir = /path/to/directory
+ crl_file = /path/to/file
+ weak_cert_validation = false
+ allow_invalid_hostname = false
+ }
+ }
+
+# server = "localhost"
+# port = 3306
+# login = "radius"
+# password = "radpass"
+
+ radius_db = "radius"
+
+ dhcpreply_table = "dhcpreply"
+ groupreply_table = "dhcpgroupreply"
+ dhcpgroup_table = "dhcpgroup"
+ read_groups = no
+
+ pool {
+ start = ${thread[pool].start_servers}
+ min = ${thread[pool].min_spare_servers}
+ max = ${thread[pool].max_servers}
+ spare = ${thread[pool].max_spare_servers}
+ uses = 0
+ retry_delay = 30
+ lifetime = 0
+ idle_timeout = 60
+ }
+
+ group_attribute = "${.:instance}-SQL-Group"
+
+ $INCLUDE ${modconfdir}/${.:name}/dhcp/${dialect}/queries.conf
+}
diff --git a/raddb/mods-available/dhcp_sqlippool b/raddb/mods-available/dhcp_sqlippool
new file mode 100644
index 0000000..909b93c
--- /dev/null
+++ b/raddb/mods-available/dhcp_sqlippool
@@ -0,0 +1,101 @@
+# Configuration for DHCP for the SQL based IP Pools module (rlm_sqlippool).
+#
+# See raddb/mods-available/sqlippool for common configuration explanation
+#
+# See raddb/policy.d/dhcp_sqlippool for the "glue" code that allows
+# the RADIUS based "sqlippool" module to be used for DHCP.
+#
+# See raddb/sites-available/dhcp for instructions on how to configure
+# the DHCP server.
+#
+# The database schemas are available at:
+#
+# raddb/mods-config/sql/ippool-dhcp/<DB>/schema.sql
+#
+# $Id$
+
+sqlippool dhcp_sqlippool {
+ # SQL instance to use (from mods-available/sql)
+ #
+ # If you have multiple sql instances, such as "sql sql1 {...}",
+ # use the *instance* name here: sql1.
+ sql_module_instance = "dhcp_sql"
+
+ # This is duplicative of info available in the SQL module, but
+ # we have to list it here as we do not yet support nested
+ # reference expansions.
+ dialect = "mysql"
+
+ # Name of the check item attribute to be used as a key in the SQL queries
+ pool_name = "Pool-Name"
+
+ # SQL table to use for ippool range and lease info
+ ippool_table = "dhcpippool"
+
+ # The duration for which a lease is reserved whilst under offer
+ offer_duration = 10
+
+ # IP lease duration. (Leases expire even if no DHCP-Release packet is received)
+ # Either use the value to be sent to the client or a hard coded one.
+ lease_duration = "%{reply:DHCP-IP-Address-Lease-Time}"
+ #lease_duration = 7200
+
+ # The attribute in which the IP address is returned in the reply
+ attribute_name = "DHCP-Your-IP-Address"
+
+ # Assign the IP address, even if the above attribute already exists in
+ # the reply.
+ #
+# allow_duplicates = no
+
+ # The attribute in which an IP address hint may be supplied
+ req_attribute_name = "DHCP-Requested-IP-Address"
+
+ #
+ # RFC 2132 allows the DHCP client to supply a unique
+ # identifier ("uid") using Option 61 (DHCP-Client-Identifier)
+ # in which case it must be used as the lookup key for
+ # configuration data.
+ #
+ pool_key = "%{%{DHCP-Client-Identifier}:-%{DHCP-Client-Hardware-Address}}"
+ #
+ # The "uid" is generated by the OS which means that clients
+ # whose BMC piggybacks on the main interface (sharing its MAC,
+ # but generating a distinct uid) and dual-booting clients can
+ # be allocated multiple IPs, consuming more pool entries. To
+ # avoid this you can ignore the RFCs and key the configuration
+ # data based only on the client MAC address.
+ #
+ # pool_key = "%{DHCP-Client-Hardware-Address}"
+
+ ################################################################
+ #
+ # WARNING: MySQL (MyISAM) has certain limitations that means it can
+ # hand out the same IP address to 2 different users.
+ #
+ # We suggest using an SQL DB with proper transaction
+ # support, such as PostgreSQL, or using MySQL
+ # with InnoDB.
+ #
+ ################################################################
+
+ # These messages are added to the "control" items, as
+ # Module-Success-Message. They are not logged anywhere else,
+ # unlike previous versions. If you want to have them logged
+ # to a file, see the "linelog" module, and create an entry
+ # which writes Module-Success-Message message.
+ #
+ messages {
+ exists = "DHCP: Existing IP: %{reply:${..attribute_name}} (cid %{DHCP-Client-Identifier} chaddr %{DHCP-Client-Hardware-Address} giaddr %{DHCP-Gateway-IP-Address})"
+
+ success = "DHCP: Allocated IP: %{reply:${..attribute_name}} from %{control:${..pool_name}} (cid %{DHCP-Client-Identifier} chaddr %{DHCP-Client-Hardware-Address} giaddr %{DHCP-Gateway-IP-Address})"
+
+ clear = "DHCP: Released IP %{DHCP-Client-IP-Address} (cid %{DHCP-Client-Identifier} chaddr %{DHCP-Client-Hardware-Address} giaddr %{DHCP-Gateway-IP-Address})"
+
+ failed = "DHCP: IP Allocation FAILED from %{control:${..pool_name}} (cid %{DHCP-Client-Identifier} chaddr %{DHCP-Client-Hardware-Address} giaddr %{DHCP-Gateway-IP-Address})"
+
+ nopool = "DHCP: No ${..pool_name} defined (cid %{DHCP-Client-Identifier} chaddr %{DHCP-Client-Hardware-Address} giaddr %{DHCP-Gateway-IP-Address})"
+ }
+
+ $INCLUDE ${modconfdir}/sql/ippool-dhcp/${dialect}/queries.conf
+}
diff --git a/raddb/mods-available/digest b/raddb/mods-available/digest
new file mode 100644
index 0000000..f0aa9ed
--- /dev/null
+++ b/raddb/mods-available/digest
@@ -0,0 +1,13 @@
+# -*- text -*-
+#
+# $Id$
+
+#
+# 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 {
+}
diff --git a/raddb/mods-available/dynamic_clients b/raddb/mods-available/dynamic_clients
new file mode 100644
index 0000000..cc2bd5f
--- /dev/null
+++ b/raddb/mods-available/dynamic_clients
@@ -0,0 +1,32 @@
+# -*- text -*-
+#
+# $Id$
+
+# This module loads RADIUS clients as needed, rather than when the server
+# starts.
+#
+# There are no configuration entries for this module. Instead, it
+# relies on the "client" configuration. You must:
+#
+# 1) link raddb/sites-enabled/dynamic_clients to
+# raddb/sites-available/dynamic_clients
+#
+# 2) Define a client network/mask (see top of the above file)
+#
+# 3) uncomment the "directory" entry in that client definition
+#
+# 4) list "dynamic_clients" in the "authorize" section of the
+# "dynamic_clients' virtual server. The default example already
+# does this.
+#
+# 5) put files into the above directory, one per IP.
+# e.g. file "192.0.2.1" should contain a normal client definition
+# for a client with IP address 192.0.2.1.
+#
+# For more documentation, see the file:
+#
+# raddb/sites-available/dynamic-clients
+#
+dynamic_clients {
+
+}
diff --git a/raddb/mods-available/eap b/raddb/mods-available/eap
new file mode 100644
index 0000000..ee9e539
--- /dev/null
+++ b/raddb/mods-available/eap
@@ -0,0 +1,1115 @@
+# -*- text -*-
+##
+## eap.conf -- Configuration for EAP types (PEAP, TTLS, etc.)
+##
+## $Id$
+
+#######################################################################
+#
+# Whatever you do, do NOT set 'Auth-Type := EAP'. The server
+# is smart enough to figure this out on its own. The most
+# common side effect of setting 'Auth-Type := EAP' is that the
+# users then cannot use ANY other authentication method.
+#
+eap {
+ # Invoke the default supported EAP type when
+ # EAP-Identity response is received.
+ #
+ # The incoming EAP messages DO 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.
+ #
+ # If the EAP-Type attribute is set by another module,
+ # then that EAP type takes precedence over the
+ # default type configured here.
+ #
+ default_eap_type = md5
+
+ # A list is maintained to correlate EAP-Response
+ # packets with EAP-Request packets. After a
+ # configurable length of time, entries in the list
+ # expire, and are deleted.
+ #
+ timer_expire = 60
+
+ # There are many EAP types, but the server has support
+ # for only a limited subset. If the server receives
+ # a request for an EAP type it does not support, then
+ # it normally rejects the request. By setting this
+ # configuration to "yes", you can tell the server to
+ # instead keep processing the request. Another module
+ # MUST then be configured to proxy the request to
+ # another RADIUS server which supports that EAP type.
+ #
+ # If another module is NOT configured to handle the
+ # request, then the request will still end up being
+ # rejected.
+ #
+ ignore_unknown_eap_types = no
+
+ # Cisco AP1230B firmware 12.2(13)JA1 has a bug. When given
+ # a User-Name attribute in an Access-Accept, it copies one
+ # more byte than it should.
+ #
+ # We can work around it by configurably adding an extra
+ # zero byte.
+ #
+ cisco_accounting_username_bug = no
+
+ # Help prevent DoS attacks by limiting the number of
+ # sessions that the server is tracking. For simplicity,
+ # this is taken from the "max_requests" directive in
+ # radiusd.conf.
+ #
+ max_sessions = ${max_requests}
+
+
+ ############################################################
+ #
+ # Supported EAP-types
+ #
+
+
+ # EAP-MD5
+ #
+ # We do NOT recommend using EAP-MD5 authentication
+ # for wireless connections. It is insecure, and does
+ # not provide for dynamic WEP keys.
+ #
+ md5 {
+ }
+
+
+ # EAP-pwd -- secure password-based authentication
+ #
+ #pwd {
+ # group = 19
+
+ # server_id = theserver@example.com
+
+ # This has the same meaning as for TLS.
+ #
+ # fragment_size = 1020
+
+ # The virtual server which determines the
+ # "known good" password for the user.
+ # Note that unlike TLS, only the "authorize"
+ # section is processed. EAP-PWD requests can be
+ # distinguished by having a User-Name, but
+ # no User-Password, CHAP-Password, EAP-Message, etc.
+ #
+ # virtual_server = "inner-tunnel"
+ #}
+
+
+ # Cisco LEAP
+ #
+ # We do not recommend using LEAP in new deployments. See:
+ # http://www.securiteam.com/tools/5TP012ACKE.html
+ #
+ # LEAP is not supported.
+ # It is insecure, and no one should be using it.
+ #
+
+
+ # EAP-GTC -- Generic Token Card
+ #
+ # Currently, this is only permitted inside of EAP-TTLS,
+ # or EAP-PEAP. The module "challenges" the user with
+ # text, and the response from the user is taken to be
+ # the User-Password.
+ #
+ # Proxying the tunneled EAP-GTC session is a bad idea,
+ # the users password will go over the wire in plain-text,
+ # for anyone to see.
+ #
+ gtc {
+ # The default challenge, which many clients
+ # ignore..
+ #
+ # challenge = "Password: "
+
+ # The plain-text response which comes back
+ # is put into a User-Password attribute,
+ # and passed to another module for
+ # authentication. This allows the EAP-GTC
+ # response to be checked against plain-text,
+ # or crypt'd passwords.
+ #
+ # If you say "Local" instead of "PAP", then
+ # the module will look for a User-Password
+ # configured for the request, and do the
+ # authentication itself.
+ #
+ auth_type = PAP
+ }
+
+
+ # Common TLS configuration for TLS-based EAP types
+ # ------------------------------------------------
+ #
+ # See raddb/certs/README.md for additional comments
+ # on certificates.
+ #
+ # If OpenSSL was not found at the time the server was
+ # built, the "tls", "ttls", and "peap" sections will
+ # be ignored.
+ #
+ # If you do not currently have certificates signed by
+ # a trusted CA you may use the 'snakeoil' certificates.
+ # Included with the server in raddb/certs.
+ #
+ # If these certificates have not been auto-generated:
+ # cd raddb/certs
+ # make
+ #
+ # These test certificates SHOULD NOT be used in a normal
+ # deployment. They are created only to make it easier
+ # to install the server, and to perform some simple
+ # tests with EAP-TLS, TTLS, or PEAP.
+ #
+ # Note that you should NOT use a globally known CA here!
+ # e.g. using a Verisign cert as a "known CA" means that
+ # ANYONE who has a certificate signed by them can
+ # authenticate via EAP-TLS! This is likely not what you want.
+ #
+ tls-config tls-common {
+ private_key_password = whatever
+ private_key_file = ${certdir}/server.pem
+
+ # If Private key & Certificate are located in
+ # the same file, then private_key_file &
+ # certificate_file must contain the same file
+ # name.
+ #
+ # If ca_file (below) is not used, then the
+ # certificate_file below SHOULD also include all of
+ # the intermediate CA certificates used to sign the
+ # server certificate, but NOT the root CA.
+ #
+ # Including the ROOT CA certificate is not useful and
+ # merely inflates the exchanged data volume during
+ # the TLS negotiation.
+ #
+ # This file should contain the server certificate,
+ # followed by intermediate certificates, in order.
+ # i.e. If we have a server certificate signed by CA1,
+ # which is signed by CA2, which is signed by a root
+ # CA, then the "certificate_file" should contain
+ # server.pem, followed by CA1.pem, followed by
+ # CA2.pem.
+ #
+ # When using "ca_file" or "ca_path", the
+ # "certificate_file" should contain only
+ # "server.pem". And then you may (or may not) need
+ # to set "auto_chain", depending on your version of
+ # OpenSSL.
+ #
+ # In short, SSL / TLS certificates are complex.
+ # There are many versions of software, each of which
+ # behave slightly differently. It is impossible to
+ # give advice which will work everywhere. Instead,
+ # we give general guidelines.
+ #
+ certificate_file = ${certdir}/server.pem
+
+ # Trusted Root CA list
+ #
+ # This file can contain multiple CA certificates.
+ # ALL of the CA's in this list will be trusted to
+ # issue client certificates for authentication.
+ #
+ # In general, you should use self-signed
+ # certificates for 802.1x (EAP) authentication.
+ # In that case, this CA file should contain
+ # *one* CA certificate.
+ #
+ ca_file = ${cadir}/ca.pem
+
+ #
+ # Directory where multiple CAs are stored. Both
+ # "ca_file" and "ca_path" can be used at the same time.
+ #
+ ca_path = ${cadir}
+
+ # OpenSSL does not reload contents of ca_path dir over time.
+ # That means that if check_crl is enabled and CRLs are loaded
+ # from ca_path dir, at some point CRLs will expire and
+ # the server will stop authenticating users.
+ #
+ # If ca_path_reload_interval is non-zero, it will force OpenSSL
+ # to reload all data from ca_path periodically
+ #
+ # Flush ca_path each hour
+ # ca_path_reload_interval = 3600
+
+ # OpenSSL will automatically create certificate chains,
+ # unless we tell it to not do that. The problem is that
+ # it sometimes gets the chains right from a certificate
+ # signature view, but wrong from the clients view.
+ #
+ # When setting "auto_chain = no", the server certificate
+ # file MUST include the full certificate chain.
+ #
+ # auto_chain = yes
+
+ # If OpenSSL supports TLS-PSK, then we can use a
+ # fixed PSK identity and (hex) password. These can
+ # be used at the same time as the certificate
+ # configuration, but only for TLS 1.0 through 1.2.
+ #
+ # If PSK and certificates are configured at the same
+ # time for TLS 1.3, then the server will warn you,
+ # and will disable TLS 1.3, as it will not work.
+ #
+ # The work around is to have two modules (or for
+ # RadSec, two listen sections). One will have PSK
+ # configured, and the other will have certificates
+ # configured.
+ #
+ # psk_identity = "test"
+ # psk_hexphrase = "036363823"
+
+ # Dynamic queries for the PSK. If TLS-PSK is used,
+ # and psk_query is set, then you MUST NOT use
+ # psk_identity or psk_hexphrase.
+ #
+ # Instead, use a dynamic expansion similar to the one
+ # below. It keys off of TLS-PSK-Identity. It should
+ # return a of string no more than 512 hex characters.
+ # That string will be converted to binary, and will
+ # be used as the dynamic PSK hexphrase.
+ #
+ # Note that this query is just an example. You will
+ # need to customize it for your installation.
+ #
+ # psk_query = "%{sql:select hex(key) from psk_keys where keyid = '%{TLS-PSK-Identity}'}"
+
+ # For DH cipher suites to work in OpenSSL < 1.1.0,
+ # you have to run OpenSSL to create the DH file
+ # first:
+ #
+ # openssl dhparam -out certs/dh 2048
+ #
+ # For OpenSSL >= 1.1.0, just leave this commented
+ # out, and OpenSSL will do the right thing.
+ #
+ # dh_file = ${certdir}/dh
+
+ # If your system doesn't have /dev/urandom,
+ # you will need to create this file, and
+ # periodically change its contents.
+ #
+ # For security reasons, FreeRADIUS doesn't
+ # write to files in its configuration
+ # directory.
+ #
+ # random_file = /dev/urandom
+
+ # This can never exceed the size of a RADIUS
+ # packet (4096 bytes), and is preferably half
+ # that, to accommodate 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 or less.
+ #
+ # 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
+
+
+ # Check the Certificate Revocation List
+ #
+ # 1) Copy CA certificates and CRLs to same directory.
+ # 2) Execute 'c_rehash <CA certs&CRLs Directory>'.
+ # 'c_rehash' is OpenSSL's command.
+ # 3) uncomment the lines below.
+ # 5) Restart radiusd
+ # check_crl = yes
+
+ # Check if intermediate CAs have been revoked.
+ # check_all_crl = yes
+
+ # Accept an expired Certificate Revocation List
+ #
+ # allow_expired_crl = no
+
+ # If check_cert_issuer is set, the value will
+ # be checked against the DN of the issuer in
+ # the client certificate. If the values do not
+ # match, the certificate verification will fail,
+ # rejecting the user.
+ #
+ # This check can be done more generally by checking
+ # the value of the TLS-Client-Cert-Issuer attribute.
+ # This check can be done via any mechanism you
+ # choose.
+ #
+ # check_cert_issuer = "/C=GB/ST=Berkshire/L=Newbury/O=My Company Ltd"
+
+ # If check_cert_cn is set, the value will
+ # be xlat'ed and checked against the CN
+ # in the client certificate. If the values
+ # do not match, the certificate verification
+ # will fail rejecting the user.
+ #
+ # This check is done only if the previous
+ # "check_cert_issuer" is not set, or if
+ # the check succeeds.
+ #
+ # This check can be done more generally by writing
+ # "unlang" statements to examine the value of the
+ # TLS-Client-Cert-Common-Name attribute.
+ #
+ # check_cert_cn = %{User-Name}
+
+ #
+ # This configuration item only applies when there is
+ # an intermediate CA between the "root" CA, and the
+ # client certificate. If we trust the root CA, then
+ # by definition we also trust ANY intermediate CA
+ # which is signed by that root. This means ANOTHER
+ # intermediate CA can issue client certificates, and
+ # have them accepted by the EAP module.
+ #
+ # The solution is to list ONLY the trusted CAs in the
+ # FreeRADIUS configuration, and then set this
+ # configuration item to "yes".
+ #
+ # Then, when the server receives a client certificate
+ # from an untrusted CA, that authentication request
+ # can be rejected.
+ #
+ # It is possible to do these checks in "unlang", by
+ # checking for unknown names in the
+ # TLS-Cert-Common-Name attribute, but that is
+ # more complex. So we add a configuration option
+ # which can be set once, and which works for all
+ # possible intermediate CAs, no matter what their
+ # value.
+ #
+ # reject_unknown_intermediate_ca = no
+
+ # Set this option to specify the allowed
+ # TLS cipher suites. The format is listed
+ # in "man 1 ciphers".
+ #
+ cipher_list = "DEFAULT"
+
+ # Set this option to specify the allowed
+ # TLS signature algorithms for OpenSSL 1.1.1 and above.
+ # The format and available signature algorithms are listed
+ # in "man 3 SSL_CTX_set1_sigalgs_list".
+ #
+ # sigalgs_list = ""
+
+ # If enabled, OpenSSL will use server cipher list
+ # (possibly defined by cipher_list option above)
+ # for choosing right cipher suite rather than
+ # using client-specified list which is OpenSSl default
+ # behavior. Setting this to "yes" means that OpenSSL
+ # will choose the servers ciphers, even if they do not
+ # best match what the client sends.
+ #
+ # TLS negotiation is usually good, but can be imperfect.
+ # This setting allows administrators to "fine tune" it
+ # if necessary.
+ #
+ cipher_server_preference = no
+
+ # You can selectively disable TLS versions for
+ # compatability with old client devices.
+ #
+ # If your system has OpenSSL 1.1.0 or greater, do NOT
+ # use these. Instead, set tls_min_version and
+ # tls_max_version.
+ #
+# disable_tlsv1_2 = yes
+# disable_tlsv1_1 = yes
+# disable_tlsv1 = yes
+
+
+ # Set min / max TLS version.
+ #
+ # Generally speaking you should NOT use TLS 1.0 or
+ # TLS 1.1. They are old, possibly insecure, and
+ # deprecated. However, it is sometimes necessary to
+ # enable it for compatibility with legact systems.
+ # We recommend replacing those legacy systems, and
+ # using at least TLS 1.2.
+ #
+ # Some Debian versions disable older versions of TLS,
+ # and requires the application to manually enable
+ # them.
+ #
+ # If you are running such a distribution, you should
+ # set these options, otherwise older clients will not
+ # be able to connect.
+ #
+ # Allowed values are "1.0", "1.1", "1.2", and "1.3".
+ #
+ # As of 2021, it is STRONGLY RECOMMENDED to set
+ #
+ # tls_min_version = "1.2"
+ #
+ # Older TLS versions are insecure and deprecated.
+ #
+ # In order to enable TLS 1.0 and TLS 1.1, you may
+ # also need to update cipher_list below to:
+ #
+ # * OpenSSL >= 3.x
+ #
+ # cipher_list = "DEFAULT@SECLEVEL=0"
+ #
+ # * OpenSSL < 3.x
+ #
+ # cipher_list = "DEFAULT@SECLEVEL=1"
+ #
+ # The values must be in quotes.
+ #
+ # We also STRONGLY RECOMMEND to set
+ #
+ # tls_max_version = "1.2"
+ #
+ # While the server will accept "1.3" as a value,
+ # most EAP supplicants WILL NOT DO TLS 1.3 PROPERLY.
+ #
+ # i.e. they WILL NOT WORK, SO DO NOT ASK QUESTIONS ON
+ # THE LIST ABOUT WHY IT DOES NOT WORK.
+ #
+ # The TLS 1.3 support is here for future
+ # compatibility, as clients get upgraded, and people
+ # don't upgrade their copies of FreeRADIUS.
+ #
+ # Also note that we only support TLS 1.3 for EAP-TLS,
+ # TTLS, and PEAP. It is not supported for EAP-FAST.
+ #
+ tls_min_version = "1.2"
+ tls_max_version = "1.2"
+
+ # Elliptical cryptography configuration
+ #
+ # This configuration should be one of the following:
+ #
+ # * a name of the curve to use, e.g. "prime256v1".
+ #
+ # * a colon separated list of curve NIDs or names.
+ #
+ # * an empty string, in which case OpenSSL will choose
+ # the "best" curve for the situation.
+ #
+ # For supported curve names, please run
+ #
+ # openssl ecparam -list_curves
+ #
+ ecdh_curve = ""
+
+ # Session resumption / fast reauthentication
+ # cache.
+ #
+ # The cache contains the following information:
+ #
+ # session Id - unique identifier, managed by SSL
+ # User-Name - from the Access-Accept
+ # Stripped-User-Name - from the Access-Request
+ # Cached-Session-Policy - from the Access-Accept
+ #
+ # See also the "store" subsection below for
+ # additional attributes which can be cached.
+ #
+ # The "Cached-Session-Policy" is the name of a
+ # policy which should be applied to the cached
+ # session. This policy can be used to assign
+ # VLANs, IP addresses, etc. It serves as a useful
+ # way to re-apply the policy from the original
+ # Access-Accept to the subsequent Access-Accept
+ # for the cached session.
+ #
+ # On session resumption, these attributes are
+ # copied from the cache, and placed into the
+ # reply list.
+ #
+ # You probably also want "use_tunneled_reply = yes"
+ # when using fast session resumption.
+ #
+ # You can check if a session has been resumed by
+ # looking for the existence of the EAP-Session-Resumed
+ # attribute. Note that this attribute will *only*
+ # exist in the "post-auth" section.
+ #
+ # CAVEATS: The cache is stored and reloaded BEFORE
+ # the "post-auth" section is run. This limitation
+ # makes caching more difficult than it should be. In
+ # practice, it means that the first authentication
+ # session must set the reply attributes before the
+ # post-auth section is run.
+ #
+ # When the session is resumed, the attributes are
+ # restored and placed into the session-state list.
+ #
+ cache {
+ # Enable it. The default is "no". Deleting the entire "cache"
+ # subsection also disables caching.
+ #
+ # The session cache requires the use of the
+ # "name" and "persist_dir" configuration
+ # items, below.
+ #
+ # The internal OpenSSL session cache has been permanently
+ # disabled.
+ #
+ # You can disallow resumption for a particular user by adding the
+ # following attribute to the control item list:
+ #
+ # Allow-Session-Resumption = No
+ #
+ # If "enable = no" below, you CANNOT enable resumption for just one
+ # user by setting the above attribute to "yes".
+ #
+ enable = no
+
+ # Lifetime of the cached entries, in hours. The sessions will be
+ # deleted/invalidated after this time.
+ #
+ lifetime = 24 # hours
+
+ # Internal "name" of the session cache. Used to
+ # distinguish which TLS context sessions belong to.
+ #
+ # The server will generate a random value if unset.
+ # This will change across server restart so you MUST
+ # set the "name" if you want to persist sessions (see
+ # below).
+ #
+ # name = "EAP module"
+
+ # Simple directory-based storage of sessions.
+ # Two files per session will be written, the SSL
+ # state and the cached VPs. This will persist session
+ # across server restarts.
+ #
+ # The default directory is ${logdir}, for historical
+ # reasons. You should ${db_dir} instead. And check
+ # the value of db_dir in the main radiusd.conf file.
+ # It should not point to ${raddb}
+ #
+ # The server will need write perms, and the directory
+ # should be secured from anyone else. You might want
+ # a script to remove old files from here periodically:
+ #
+ # find ${logdir}/tlscache -mtime +2 -exec rm -f {} \;
+ #
+ # This feature REQUIRES "name" option be set above.
+ #
+ # persist_dir = "${logdir}/tlscache"
+
+ #
+ # It is possible to partially
+ # control which attributes exist in the
+ # session cache. This subsection lists
+ # attributes which are taken from the reply,
+ # and saved to the on-disk cache. When the
+ # session is resumed, these attributes are
+ # added to the "session-state" list. The
+ # default configuration will then take care
+ # of copying them to the reply.
+ #
+ store {
+ Tunnel-Private-Group-Id
+ }
+ }
+
+ # Client certificates can be validated via an
+ # external command. This allows dynamic CRLs or OCSP
+ # to be used.
+ #
+ # This configuration is commented out in the
+ # default configuration. Uncomment it, and configure
+ # the correct paths below to enable it.
+ #
+ # If OCSP checking is enabled, and the OCSP checks fail,
+ # the verify section is not run.
+ #
+ # If OCSP checking is disabled, the verify section is
+ # run on successful certificate validation.
+ #
+ verify {
+ # If the OCSP checks succeed, the verify section
+ # is run to allow additional checks.
+ #
+ # If you want to skip verify on OCSP success,
+ # uncomment this configuration item, and set it
+ # to "yes".
+ #
+ # skip_if_ocsp_ok = no
+
+ # A temporary directory where the client
+ # certificates are stored. This directory
+ # MUST be owned by the UID of the server,
+ # and MUST not be accessible by any other
+ # users. When the server starts, it will do
+ # "chmod go-rwx" on the directory, for
+ # security reasons. The directory MUST
+ # exist when the server starts.
+ #
+ # You should also delete all of the files
+ # in the directory when the server starts.
+ #
+ # tmpdir = /tmp/radiusd
+
+ # The command used to verify the client cert.
+ # We recommend using the OpenSSL command-line
+ # tool.
+ #
+ # The ${..ca_path} text is a reference to
+ # the ca_path variable defined above.
+ #
+ # The %{TLS-Client-Cert-Filename} is the name
+ # of the temporary file containing the cert
+ # in PEM format. This file is automatically
+ # deleted by the server when the command
+ # returns.
+ #
+ # client = "/path/to/openssl verify -CApath ${..ca_path} %{TLS-Client-Cert-Filename}"
+ }
+
+ # OCSP Configuration
+ #
+ # Certificates can be verified against an OCSP
+ # Responder. This makes it possible to immediately
+ # revoke certificates without the distribution of
+ # new Certificate Revocation Lists (CRLs).
+ #
+ ocsp {
+ # Enable it. The default is "no".
+ # Deleting the entire "ocsp" subsection
+ # also disables ocsp checking
+ #
+ enable = no
+
+ # The OCSP Responder URL can be automatically
+ # extracted from the certificate in question.
+ # To override the OCSP Responder URL set
+ # "override_cert_url = yes".
+ #
+ override_cert_url = yes
+
+ # If the OCSP Responder address is not extracted from
+ # the certificate, the URL can be defined here.
+ #
+ url = "http://127.0.0.1/ocsp/"
+
+ # If the OCSP Responder can not cope with nonce
+ # in the request, then it can be disabled here.
+ #
+ # For security reasons, disabling this option
+ # is not recommended as nonce protects against
+ # replay attacks.
+ #
+ # Note that Microsoft AD Certificate Services OCSP
+ # Responder does not enable nonce by default. It is
+ # more secure to enable nonce on the responder than
+ # to disable it in the query here.
+ # See http://technet.microsoft.com/en-us/library/cc770413%28WS.10%29.aspx
+ #
+ # use_nonce = yes
+
+ # Number of seconds before giving up waiting
+ # for OCSP response. 0 uses system default.
+ #
+ # timeout = 0
+
+ # Normally an error in querying the OCSP
+ # responder (no response from server, server did
+ # not understand the request, etc) will result in
+ # a validation failure.
+ #
+ # To treat these errors as 'soft' failures and
+ # still accept the certificate, enable this
+ # option.
+ #
+ # Warning: this may enable clients with revoked
+ # certificates to connect if the OCSP responder
+ # is not available. Use with caution.
+ #
+ # softfail = no
+ }
+
+ #
+ # The server can present different certificates based
+ # on the realm presented in EAP. See
+ # raddb/certs/realms/README.md for examples of how to
+ # configure this.
+ #
+ # Note that the default is to use the same set of
+ # realm certificates for both EAP and RadSec! If
+ # this is not what you want, you should use different
+ # subdirectories or each, e.g. ${certdir}/realms/radsec/,
+ # and ${certdir}/realms/eap/
+ #
+ # realm_dir = ${certdir}/realms/
+ }
+
+
+ # EAP-TLS
+ #
+ # The TLS configuration for TLS-based EAP types is held in
+ # the "tls-config" section, above.
+ #
+ tls {
+ # Point to the common TLS configuration
+ #
+ tls = tls-common
+
+ # As part of checking a client certificate, the EAP-TLS
+ # sets some attributes such as TLS-Client-Cert-Common-Name. This
+ # virtual server has access to these attributes, and can
+ # be used to accept or reject the request.
+ #
+ # virtual_server = check-eap-tls
+
+ # You can control whether or not EAP-TLS requires a
+ # client certificate by setting
+ #
+ # configurable_client_cert = yes
+ #
+ # Once that setting has been changed, you can then set
+ #
+ # EAP-TLS-Require-Client-Cert = No
+ #
+ # in the control items for a request, and the EAP-TLS
+ # module will not require a client certificate from
+ # the supplicant.
+ #
+ # WARNING: This configuration should only be used
+ # when the users are placed into a "captive portal"
+ # or "walled garden", where they have limited network
+ # access. Otherwise the configuraton will allow
+ # anyone on the network, without authenticating them!
+ #
+# configurable_client_cert = no
+ }
+
+
+ # EAP-TTLS -- Tunneled TLS
+ #
+ # The TTLS module implements the EAP-TTLS protocol,
+ # which can be described as EAP inside of Diameter,
+ # inside of TLS, inside of EAP, inside of RADIUS...
+ #
+ # Surprisingly, it works quite well.
+ #
+ ttls {
+ # Which tls-config section the TLS negotiation parameters
+ # are in - see EAP-TLS above for an explanation.
+ #
+ # In the case that an old configuration from FreeRADIUS
+ # v2.x is being used, all the options of the tls-config
+ # section may also appear instead in the 'tls' section
+ # above. If that is done, the tls= option here (and in
+ # tls above) MUST be commented out.
+ #
+ tls = tls-common
+
+ # The tunneled EAP session needs a default EAP type
+ # which is separate from the one for the non-tunneled
+ # EAP module. Inside of the TTLS tunnel, we recommend
+ # using EAP-MD5. If the request does not contain an
+ # EAP conversation, then this configuration entry is
+ # ignored.
+ #
+ default_eap_type = md5
+
+ # The tunneled authentication request does not usually
+ # contain useful attributes like 'Calling-Station-Id',
+ # etc. These attributes are outside of the tunnel,
+ # and normally unavailable to the tunneled
+ # authentication request.
+ #
+ # By setting this configuration entry to 'yes',
+ # any attribute which is NOT in the tunneled
+ # authentication request, but which IS available
+ # outside of the tunnel, is copied to the tunneled
+ # request.
+ #
+ # allowed values: {no, yes}
+ #
+ copy_request_to_tunnel = no
+
+ # This configuration item is deprecated. Instead,
+ # you should use:
+ #
+ # update outer.session-state {
+ # ...
+ # }
+ #
+ # This will cache attributes for the final Access-Accept.
+ #
+ # See "update outer.session-state" in the "post-auth"
+ # sections of sites-available/default, and of
+ # sites-available/inner-tunnel
+ #
+ # The reply attributes sent to the NAS are usually
+ # based on the name of the user 'outside' of the
+ # tunnel (usually 'anonymous'). If you want to send
+ # the reply attributes based on the user name inside
+ # of the tunnel, then set this configuration entry to
+ # 'yes', and the reply to the NAS will be taken from
+ # the reply to the tunneled request.
+ #
+ # allowed values: {no, yes}
+ #
+ use_tunneled_reply = no
+
+ # The inner tunneled request can be sent
+ # through a virtual server constructed
+ # specifically for this purpose.
+ #
+ # A virtual server MUST be specified.
+ #
+ virtual_server = "inner-tunnel"
+
+ # This has the same meaning, and overwrites, the
+ # same field in the "tls" configuration, above.
+ # The default value here is "yes".
+ #
+ # include_length = yes
+
+ # Unlike EAP-TLS, EAP-TTLS does not require a client
+ # certificate. However, you can require one by setting the
+ # following option. You can also override this option by
+ # setting
+ #
+ # EAP-TLS-Require-Client-Cert = Yes
+ #
+ # in the control items for a request.
+ #
+ # Note that the majority of supplicants do not support using a
+ # client certificate with EAP-TTLS, so this option is unlikely
+ # to be usable for most people.
+ #
+ # require_client_cert = yes
+ }
+
+
+ # EAP-PEAP
+ #
+
+ ##################################################
+ #
+ # !!!!! WARNINGS for Windows compatibility !!!!!
+ #
+ ##################################################
+ #
+ # If you see the server send an Access-Challenge,
+ # and the client never sends another Access-Request,
+ # then
+ #
+ # STOP!
+ #
+ # The server certificate has to have special OID's
+ # in it, or else the Microsoft clients will silently
+ # fail. See the "scripts/xpextensions" file for
+ # details, and the following page:
+ #
+ # https://support.microsoft.com/en-us/help/814394/
+ #
+ # If is still doesn't work, and you're using Samba,
+ # you may be encountering a Samba bug. See:
+ #
+ # https://bugzilla.samba.org/show_bug.cgi?id=6563
+ #
+ # Note that we do not necessarily agree with their
+ # explanation... but the fix does appear to work.
+ #
+ ##################################################
+
+ # The tunneled EAP session needs a default EAP type
+ # which is separate from the one for the non-tunneled
+ # EAP module. Inside of the TLS/PEAP tunnel, we
+ # recommend using EAP-MS-CHAPv2.
+ #
+ peap {
+ # Which tls-config section the TLS negotiation parameters
+ # are in - see EAP-TLS above for an explanation.
+ #
+ # In the case that an old configuration from FreeRADIUS
+ # v2.x is being used, all the options of the tls-config
+ # section may also appear instead in the 'tls' section
+ # above. If that is done, the tls= option here (and in
+ # tls above) MUST be commented out.
+ #
+ tls = tls-common
+
+ # The tunneled EAP session needs a default
+ # EAP type which is separate from the one for
+ # the non-tunneled EAP module. Inside of the
+ # PEAP tunnel, we recommend using MS-CHAPv2,
+ # as that is the default type supported by
+ # Windows clients.
+ #
+ default_eap_type = mschapv2
+
+ # The PEAP module also has these configuration
+ # items, which are the same as for TTLS.
+ #
+ copy_request_to_tunnel = no
+
+ # This configuration item is deprecated. Instead,
+ # you should use:
+ #
+ # update outer.session-state {
+ # ...
+ # }
+ #
+ # This will cache attributes for the final Access-Accept.
+ #
+ # See "update outer.session-state" in the "post-auth"
+ # sections of sites-available/default, and of
+ # sites-available/inner-tunnel
+ #
+ use_tunneled_reply = no
+
+ # When the tunneled session is proxied, the
+ # home server may not understand EAP-MSCHAP-V2.
+ # Set this entry to "no" to proxy the tunneled
+ # EAP-MSCHAP-V2 as normal MSCHAPv2.
+ #
+ # This setting can be over-ridden on a packet by
+ # packet basis by setting
+ #
+ # &control:Proxy-Tunneled-Request-As-EAP = yes
+ #
+ # proxy_tunneled_request_as_eap = yes
+
+ # The inner tunneled request can be sent
+ # through a virtual server constructed
+ # specifically for this purpose.
+ #
+ # A virtual server MUST be specified.
+ #
+ virtual_server = "inner-tunnel"
+
+ # This option enables support for MS-SoH
+ # see doc/SoH.txt for more info.
+ # It is disabled by default.
+ #
+ # soh = yes
+
+ # The SoH reply will be turned into a request which
+ # can be sent to a specific virtual server:
+ #
+ # soh_virtual_server = "soh-server"
+
+ # Unlike EAP-TLS, PEAP does not require a client certificate.
+ # However, you can require one by setting the following
+ # option. You can also override this option by setting
+ #
+ # EAP-TLS-Require-Client-Cert = Yes
+ #
+ # in the control items for a request.
+ #
+ # Note that the majority of supplicants do not support using a
+ # client certificate with PEAP, so this option is unlikely to
+ # be usable for most people.
+ #
+ # require_client_cert = yes
+ }
+
+
+ # EAP-MSCHAPv2
+ #
+ # Note that it is the EAP MS-CHAPv2 sub-module, not
+ # the main 'mschap' module.
+ #
+ # Note also that in order for this sub-module to work,
+ # the main 'mschap' module MUST ALSO be configured.
+ #
+ # This module is the *Microsoft* implementation of MS-CHAPv2
+ # in EAP. There is another (incompatible) implementation
+ # of MS-CHAPv2 in EAP by Cisco, which FreeRADIUS does not
+ # currently support.
+ #
+ mschapv2 {
+ # In earlier versions of the server, this module
+ # never sent the MS-CHAP-Error message to the client.
+ # This worked, but it had issues when the cached
+ # password was wrong. The server *should* send
+ # "E=691 R=0" to the client, which tells it to prompt
+ # the user for a new password.
+ #
+ # The default is to use that functionality. which is
+ # known to work. If you set "send_error = yes", then
+ # the error message will be sent back to the client.
+ # This *may* help some clients work better, but *may*
+ # also cause other clients to stop working.
+ #
+ # send_error = no
+
+ # Server identifier to send back in the challenge.
+ # This should generally be the host name of the
+ # RADIUS server. Or, some information to uniquely
+ # identify it.
+ #
+ # identity = "FreeRADIUS"
+ }
+
+
+ # EAP-FAST
+ #
+ # The FAST module implements the EAP-FAST protocol
+ #
+ #fast {
+ # Point to the common TLS configuration
+ #
+ # tls = tls-common
+
+ # If 'cipher_list' is set here, it will over-ride the
+ # 'cipher_list' configuration from the 'tls-common'
+ # configuration. The EAP-FAST module has it's own
+ # over-ride for 'cipher_list' because the
+ # specifications mandata a different set of ciphers
+ # than are used by the other EAP methods.
+ #
+ # cipher_list though must include "ADH" for anonymous provisioning.
+ # This is not as straight forward as appending "ADH" alongside
+ # "DEFAULT" as "DEFAULT" contains "!aNULL" so instead it is
+ # recommended "ALL:!EXPORT:!eNULL:!SSLv2" is used
+ #
+ # cipher_list = "ALL:!EXPORT:!eNULL:!SSLv2"
+
+ # PAC lifetime in seconds (default: seven days)
+ #
+ # pac_lifetime = 604800
+
+ # Authority ID of the server
+ #
+ # If you are running a cluster of RADIUS servers, you should make
+ # the value chosen here (and for "pac_opaque_key") the same on all
+ # your RADIUS servers. This value should be unique to your
+ # installation. We suggest using a domain name.
+ #
+ # authority_identity = "1234"
+
+ # PAC Opaque encryption key (must be exactly 32 bytes in size)
+ #
+ # This value MUST be secret, and MUST be generated using
+ # a secure method, such as via 'openssl rand -hex 32'
+ #
+ # pac_opaque_key = "0123456789abcdef0123456789ABCDEF"
+
+ # Same as for TTLS, PEAP, etc.
+ #
+ # virtual_server = inner-tunnel
+ #}
+}
diff --git a/raddb/mods-available/echo b/raddb/mods-available/echo
new file mode 100644
index 0000000..ad3e159
--- /dev/null
+++ b/raddb/mods-available/echo
@@ -0,0 +1,123 @@
+# -*- text -*-
+#
+# $Id$
+
+#
+# This is a more general example of the execute module.
+#
+# This one is called "echo".
+#
+# Attribute-Name = `%{echo:/path/to/program args}`
+#
+# 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.
+#
+# The return value of the program run determines the result
+# of the exec instance call as follows:
+# (See doc/configurable_failover for details)
+#
+# < 0 : fail the module failed
+# = 0 : ok the module succeeded
+# = 1 : reject the module rejected the user
+# = 2 : fail the module failed
+# = 3 : ok the module succeeded
+# = 4 : handled the module has done everything to handle the request
+# = 5 : invalid the user's configuration entry was invalid
+# = 6 : userlock the user was locked out
+# = 7 : notfound the user was not found
+# = 8 : noop the module did nothing
+# = 9 : updated the module updated information in the request
+# > 9 : fail the module failed
+#
+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
+ # config attributes from the configuration items list
+ # 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
+
+ #
+ # Should we escape the environment variables?
+ #
+ # If this is set, all the RADIUS attributes
+ # are capitalised and dashes replaced with
+ # underscores. Also, RADIUS values are surrounded
+ # with double-quotes.
+ #
+ # That is to say: User-Name=BobUser => USER_NAME="BobUser"
+ shell_escape = yes
+
+ #
+ # How long should we wait for the program to finish?
+ #
+ # Default is 10 seconds, which should be plenty for nearly
+ # anything. Range is 1 to 30 seconds. You are strongly
+ # encouraged to NOT increase this value. Decreasing can
+ # be used to cause authentication to fail sooner when you
+ # know it's going to fail anyway due to the time taken,
+ # thereby saving resources.
+ #
+ #timeout = 10
+
+}
diff --git a/raddb/mods-available/etc_group b/raddb/mods-available/etc_group
new file mode 100644
index 0000000..114f24a
--- /dev/null
+++ b/raddb/mods-available/etc_group
@@ -0,0 +1,32 @@
+# -*- text -*-
+#
+# $Id$
+
+# "passwd" configuration, for the /etc/group file. Adds a Etc-Group-Name
+# attribute for every group that the user is member of.
+#
+# You will have to define the Etc-Group-Name in the 'dictionary' file
+# as a 'string' type.
+#
+# The module name "etc_group" should also be listed in the "authorize"
+# section. Make sure it's listed before any other part of the server
+# tries to use the Etc-Group-Name attribute.
+#
+# The Group and Group-Name attributes are automatically created by
+# the Unix module, and do checking against /etc/group automatically.
+# This means that you CANNOT use Group or Group-Name to do any other
+# kind of grouping in the server. You MUST define a new group
+# attribute.
+#
+# i.e. this module should NOT be used as-is, but should be edited to
+# point to a different group file.
+#
+passwd etc_group {
+ filename = /etc/group
+ format = "=Etc-Group-Name:::*,User-Name"
+ hash_size = 50
+ ignore_nislike = yes
+ allow_multiple_keys = yes
+ delimiter = ":"
+}
+
diff --git a/raddb/mods-available/exec b/raddb/mods-available/exec
new file mode 100644
index 0000000..bb1d437
--- /dev/null
+++ b/raddb/mods-available/exec
@@ -0,0 +1,29 @@
+# -*- text -*-
+#
+# $Id$
+
+#
+# Execute external programs
+#
+# This module 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 "man unlang" and in doc/configuration/variables.rst
+#
+# See also "echo" for more sample configuration.
+#
+exec {
+ wait = no
+ input_pairs = request
+ shell_escape = yes
+ timeout = 10
+}
diff --git a/raddb/mods-available/expiration b/raddb/mods-available/expiration
new file mode 100644
index 0000000..5d06454
--- /dev/null
+++ b/raddb/mods-available/expiration
@@ -0,0 +1,13 @@
+# -*- text -*-
+#
+# $Id$
+
+#
+# The expiration module. This handles the Expiration attribute
+# It should be included in the *end* of the authorize section
+# in order to handle user Expiration. It should also be included
+# in the instantiate section in order to register the Expiration
+# compare function
+#
+expiration {
+}
diff --git a/raddb/mods-available/expr b/raddb/mods-available/expr
new file mode 100644
index 0000000..ca0b3bf
--- /dev/null
+++ b/raddb/mods-available/expr
@@ -0,0 +1,148 @@
+# -*- text -*-
+#
+# $Id$
+
+#
+# This module performs mathematical calculations:
+#
+# Attribute-Name = "%{expr:2 + 3 + &NAS-Port}"
+#
+# It supports the following operators (in order of precedence)
+#
+# & binary AND
+# | binary OR
+# << left shift
+# >> right shift
+# + addition
+# - subtraction
+# * multiply
+# / divide
+# %% remainder
+# ^ exponentiation
+# (...) sub-expression
+#
+# Operator precedence follows the normal rules.
+# Division by zero means that the entire expression is invalid.
+#
+# It also allows unary negation: -1
+# And twos complement: ~1
+#
+# All calculations are done on signed 63-bit integers.
+# e.g. int64_t. This should be sufficient for all normal
+# purposes.
+#
+# Hex numbers are supported: 0xabcdef
+#
+# As with all string expansions, you can nest the expansions:
+#
+# %{expr: %{NAS-Port} + 1}
+# %{expr: %{sql:SELECT ... } + 1}
+#
+# Attribute references are supported for integer attributes.
+# e.g. &NAS-Port. The benefit of using attribute references
+# is that the expression is calculated directly on the
+# attribute. It skips the step of "print to string, and then
+# parse to number". This means it's a little faster.
+#
+# Otherwise, all numbers are decimal.
+#
+
+#
+# The module also registers a few paircompare functions, and
+# many string manipulation functions, including:
+#
+# rand get random number from 0 to n-1
+# "%{rand:10}" == "9"
+#
+# randstr get random string built from character classes:
+# c lowercase letters
+# C uppercase letters
+# n numbers
+# a alphanumeric
+# ! punctuation
+# . alphanumeric + punctuation
+# s alphanumeric + "./"
+# o characters suitable for OTP (easily confused removed)
+# h binary data as lowercase hex
+# H binary data as uppercase hex
+#
+# "%{randstr:CCCC!!cccnnn}" == "IPFL>{saf874"
+# "%{randstr:oooooooo}" == "rfVzyA4y"
+# "%{randstr:hhhh}" == "68d60de3"
+#
+# urlquote quote special characters in URI
+# "%{urlquote:http://example.org/}" == "http%3A%47%47example.org%47"
+#
+# urlunquote unquote URL special characters
+# "%{urlunquote:http%%3A%%47%%47example.org%%47}" == "http://example.org/"
+#
+# escape escape string similar to rlm_sql safe_characters
+# "%{escape:<img>foo.jpg</img>}" == "=60img=62foo.jpg=60/img=62"
+#
+# unescape reverse of escape
+# "%{unescape:=60img=62foo.jpg=60/img=62}" == "<img>foo.jpg</img>"
+#
+# tolower convert to lowercase
+# "%{tolower:Bar}" == "bar"
+#
+# toupper convert to uppercase
+# "%{toupper:Foo}" == "FOO"
+#
+# md5 get md5sum hash
+# "%{md5:foo}" == "acbd18db4cc2f85cedef654fccc4a4d8"
+#
+# sha1 get sha1 hash
+# "%{sha1:foo}" == "0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"
+#
+# sha256 get sha256 hash
+# "%{sha256:foo}" == "2c26b46b68ffc68ff99b453c1d30413413422d706..."
+#
+# sha512 get sha512 hash
+# "%{sha512:foo}" == "f7fbba6e0636f890e56fbbf3283e524c6fa3204ae29838..."
+#
+# hmacmd5 generate HMAC-MD5 of string
+# "%{hmacmd5:foo bar}" == "31b6db9e5eb4addb42f1a6ca07367adc"
+#
+# hmacsha1 generate HMAC-SHA1 of string
+# "%{hmacsha1:foo bar}" == "85d155c55ed286a300bd1cf124de08d87e914f3a"
+#
+# crypt encrypt with a salt: %{crypt:salt:password}
+# "%{crypt:aa:foo}" == "aaKNIEDOaueR6"
+# "%{crypt:$1$abcdefgh:foo}" == "$1$abcdefgh$XxzGe9Muun7wTYbZO4sdr0"
+# "%{crypt:$5$%{randstr:aaaaaaaaaaaaaaaa}:foo}" == "$1$fu4P2fcAdo9gM..."
+#
+# pairs serialize attributes as comma-delimited string
+# "%{pairs:request:}" == "User-Name = 'foo', User-Password = 'bar', ..."
+#
+# base64 encode string as base64
+# "%{base64:foo}" == "Zm9v"
+#
+# base64tohex convert base64 to hex
+# "%{base64tohex:Zm9v}" == "666f6f"
+#
+# explode split an attribute into multiple new attributes based on a delimiter
+# "%{explode:&ref <delim>}"
+#
+# nexttime calculate number of seconds until next n hour(s), day(s), week(s), year(s)
+# if it were 16:18, %{nexttime:1h} would expand to 2520
+#
+# lasttime calculate number of seconds until last n hour(s), day(s), week(s), year(s)
+# if it were 16:18, %{lasttime:1h} would expand to 4680
+#
+# lpad left-pad a string
+# if User-Name is "foo": "%{lpad:&User-Name 6 x}" == "xxxfoo"
+#
+# rpad right-pad a string
+# if User-Name is "foo": "%{rpad:&User-Name 5 -}" == "foo--"
+#
+# concat concatenate a set of attributes, separated by a character.
+# "%{concat:foo[*] ;}"
+#
+
+expr {
+ #
+ # Characters that will not be encoded by the %{escape}
+ # xlat function.
+ #
+ safe_characters = "@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_: /äéöüàâæçèéêëîïôœùûüaÿÄÉÖÜßÀÂÆÇÈÉÊËÎÃÔŒÙÛÜŸ"
+}
diff --git a/raddb/mods-available/files b/raddb/mods-available/files
new file mode 100644
index 0000000..e3f3bf5
--- /dev/null
+++ b/raddb/mods-available/files
@@ -0,0 +1,30 @@
+# -*- text -*-
+#
+# $Id$
+
+# Livingston-style 'users' file
+#
+# See "man users" for more information.
+#
+files {
+ # Search for files in a subdirectory of mods-config which
+ # matches this instance of the files module.
+ moddir = ${modconfdir}/${.:instance}
+
+ # 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 = ${moddir}/authorize
+
+ # This is accepted for backwards compatibility
+ # It will be removed in a future release.
+# usersfile = ${moddir}/authorize
+
+ # These are accepted for backwards compatibility.
+ # They will be renamed in a future release.
+ acctusersfile = ${moddir}/accounting
+ preproxy_usersfile = ${moddir}/pre-proxy
+}
diff --git a/raddb/mods-available/idn b/raddb/mods-available/idn
new file mode 100644
index 0000000..5340540
--- /dev/null
+++ b/raddb/mods-available/idn
@@ -0,0 +1,28 @@
+# -*- text -*-
+#
+# $Id$
+
+#
+# Internationalised domain names.
+#
+
+# The expansion string: %{idn: example.com} results in an ASCII
+# punycode version of the domain name. That version can then be used
+# for name comparisons. Using an i18n version of the name is NOT
+# RECOMMENDED, as that version is not canonical.
+#
+# i.e. the "same" domain name can be represented in many, many,
+# different ways. Only the idn version has *one* representation.
+#
+idn {
+ #
+ # Allow use of unassigned Unicode code points.
+ #
+ allow_unassigned = no
+
+ #
+ # Prohibit underscores and other invalid characters in domain
+ # names.
+ use_std3_ascii_rules = yes
+
+} \ No newline at end of file
diff --git a/raddb/mods-available/inner-eap b/raddb/mods-available/inner-eap
new file mode 100644
index 0000000..576eb77
--- /dev/null
+++ b/raddb/mods-available/inner-eap
@@ -0,0 +1,107 @@
+# -*- text -*-
+#
+# $Id$
+
+#
+# Sample configuration for an EAP module that occurs *inside*
+# of a tunneled method. It is used to limit the EAP types that
+# can occur inside of the inner tunnel.
+#
+# See also raddb/sites-available/inner-tunnel
+#
+# See raddb/mods-available/eap for full documentation on the meaning of these
+# configuration entries.
+#
+eap inner-eap {
+ # This is the best choice for PEAP.
+ default_eap_type = mschapv2
+
+ timer_expire = 60
+
+ # This should be the same as the outer eap "max sessions"
+ max_sessions = 2048
+
+ # Supported EAP-types
+ md5 {
+ }
+
+ gtc {
+ # The default challenge, which many clients
+ # ignore..
+ #challenge = "Password: "
+
+ auth_type = PAP
+ }
+
+ mschapv2 {
+ # See eap for documentation
+# send_error = no
+ }
+
+ # No TTLS or PEAP configuration should be listed here.
+
+ ## EAP-TLS
+ #
+ # You SHOULD use different certificates than are used
+ # for the outer EAP configuration!
+ #
+ # You can create the "inner-server.pem" file by doing:
+ #
+ # cd raddb/certs
+ # vi inner-server.cnf
+ # make inner-server
+ #
+ # The certificate MUST be different from the "server.cnf"
+ # file.
+ #
+ # Support for PEAP/TLS and RFC 5176 TLS/TLS is experimental.
+ # It might work, or it might not.
+ #
+ tls {
+ private_key_password = whatever
+ private_key_file = ${certdir}/inner-server.pem
+
+ # If Private key & Certificate are located in
+ # the same file, then private_key_file &
+ # certificate_file must contain the same file
+ # name.
+ #
+ # If ca_file (below) is not used, then the
+ # certificate_file below MUST include not
+ # only the server certificate, but ALSO all
+ # of the CA certificates used to sign the
+ # server certificate.
+ certificate_file = ${certdir}/inner-server.pem
+
+ # You may want different CAs for inner and outer
+ # certificates. If so, edit this file.
+ ca_file = ${cadir}/ca.pem
+
+ cipher_list = "DEFAULT"
+
+ # You may want to set a very small fragment size.
+ # The TLS data here needs to go inside of the
+ # outer EAP-TLS protocol.
+ #
+ # Try values and see if they work...
+ # fragment_size = 1024
+
+ # Other needful things
+ dh_file = ${certdir}/dh
+ random_file = /dev/urandom
+
+ # CRL and OCSP things go here. See the main "eap"
+ # file for details.
+ # check_crl = yes
+ # ca_path = /path/to/directory/with/ca_certs/and/crls/
+
+ # Accept an expired Certificate Revocation List
+ #
+# allow_expired_crl = no
+
+ #
+ # The session resumption / fast re-authentication
+ # cache CANNOT be used for inner sessions.
+ #
+ }
+}
diff --git a/raddb/mods-available/ippool b/raddb/mods-available/ippool
new file mode 100644
index 0000000..1d3305b
--- /dev/null
+++ b/raddb/mods-available/ippool
@@ -0,0 +1,66 @@
+# -*- text -*-
+#
+# $Id$
+
+# 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.
+#
+# The Pool-Name should be set to the ippool module instance
+# name or to DEFAULT to match any module.
+
+#
+# Example:
+# radiusd.conf: ippool students { [...] }
+# ippool teachers { [...] }
+# users file : DEFAULT Group == students, Pool-Name := "students"
+# DEFAULT Group == teachers, Pool-Name := "teachers"
+# DEFAULT Group == other, Pool-Name := "DEFAULT"
+#
+# Note: If you change the range parameters you must then erase the
+# db files.
+#
+ippool main_pool {
+ # The main db file used to allocate addresses.
+ filename = ${db_dir}/db.ippool
+
+ # The start and end ip addresses for this pool.
+ range_start = 192.0.2.1
+ range_stop = 192.0.2.254
+
+ # The network mask used for this pool.
+ netmask = 255.255.255.0
+
+ # 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
+
+ # Helper db index file used in multilink
+ ip_index = ${db_dir}/db.ipindex
+
+ # If set, the Framed-IP-Address already in the
+ # reply (if any) will be discarded, and replaced
+ # ith a Framed-IP-Address assigned here.
+ override = no
+
+ # Specifies the maximum time in seconds that an
+ # entry may be active. If set to zero, means
+ # "no timeout". The default value is 0
+ maximum_timeout = 0
+
+ # The key to use for the session database (which
+ # holds the allocated ip's) normally it should
+ # just be the nas ip/port (which is the default).
+ #
+ # If your NAS sends the same value of NAS-Port
+ # all requests, the key should be based on some
+ # other attribute that is in ALL requests, AND
+ # is unique to each machine needing an IP address.
+# key = "%{NAS-IP-Address} %{NAS-Port}"
+}
diff --git a/raddb/mods-available/json b/raddb/mods-available/json
new file mode 100644
index 0000000..02a62ae
--- /dev/null
+++ b/raddb/mods-available/json
@@ -0,0 +1,271 @@
+# -*- text -*-
+#
+#
+# $Id$
+
+#######################################################################
+#
+# = JSON Module
+#
+# The `json` module provides the `json_encode` XLAT, which may be
+# used to encode a given list of attributes into different
+# formats of JSON object.
+#
+
+#
+# ## Configuration Settings
+#
+json {
+
+ #
+ # The only options for the JSON module are to control the output
+ # format of the `json_encode` xlat.
+ #
+ encode {
+
+ #
+ # output_mode:: set the format of JSON documenta
+ # that should be created. This may be one of:
+ #
+ # - object
+ # - object_simple
+ # - array
+ # - array_of_names
+ # - array_of_values
+ #
+ # Examples of each format are given below.
+ #
+# output_mode = object
+
+ #
+ # ### Formatting options for attribute names
+ #
+ attribute {
+ #
+ # prefix:: Add a colon-delimited prefix to all
+ # attribute names in the output document. For example,
+ # with a prefix of "foo", `User-Name` will be output as
+ # `foo:User-Name`.
+ #
+# prefix =
+ }
+
+ #
+ # ### Formatting options for attribute values
+ #
+ value {
+
+ #
+ # single_value_as_array:: always put values in an array
+ #
+ # Output formats will by default put single values as a
+ # JSON object (string, integer, etc). More than one
+ # value will, depending on the output format, be added
+ # as an array.
+ #
+ # When this option is enabled, values will always be
+ # added as an array.
+ #
+# single_value_as_array = no
+
+ #
+ # enum_as_integer:: output the integer value of
+ # enumerated attributes
+ #
+ # Where an attribute has enum values, the textual
+ # representation of the value will normally be output.
+ # Enable this option to force the numeric value
+ # instead.
+ #
+# enum_as_integer = no
+
+ #
+ # always_string:: force all values to be strings
+ #
+ # Integer values are normally written to the JSON
+ # document as numbers (i.e. without quotes). Enable
+ # this option to force all values to be as quoted
+ # strings.
+ #
+# always_string = no
+ }
+
+ }
+
+}
+
+
+#
+# ## Expansions
+#
+# rlm_json provides the below xlat function.
+#
+# ### %{json_encode:...}
+#
+# Generates a JSON document from a given list of attribute templates. The
+# format of document generated can be controlled with the 'encode' section in
+# the module configuration. Attribute values will automatically be escaped so
+# they are JSON-safe.
+#
+# NOTE: The name of the xlat is based on the instance name of this module. If
+# the module was defined as `json jdoc {...}`, then the xlat name will be
+# `jdoc_encode`.
+#
+# The xlat should be passed a list of attributes to encode. Each attribute
+# (after template expansion) will be added to a list of attributes to include
+# in the JSON document. If any of the attributes given are preceeded with a `!`
+# then they are removed from the list. Once all attributes have been processed,
+# the JSON document will be created using this list.
+#
+# For example, the following will produce a JSON document with two attributes in
+# it, `User-Name` and `Calling-Station-Id`, from the RADIUS request:
+#
+# .Example
+#
+# ```
+# %{json_encode:&User-Name &Calling-Station-Id}
+# ```
+#
+# The following will include all attributes in the RADIUS request, except for
+# `User-Password`:
+#
+# .Example
+#
+# ```
+# %{json_encode:&request[*] !&User-Password}
+# ```
+#
+# In another (contrived) example, all the attributes in the RADIUS request will
+# be included in the document, _except_ any attributes in the RADIUS reply.
+# `&User-Name` will be included from the control list, too, if it exists:
+#
+# .Example
+#
+# ```
+# %{json_encode:&request[*] !&reply[*] &control.User-Name}
+# ```
+#
+# #### Output format modes
+#
+# There are a number of output modes, each generating a different format of
+# JSON document.
+#
+# NOTE: In the JSON document, "type" is the type of the _attribute_, which is
+# not necessarily the same as the type of the "value" in the document. See e.g.
+# `Login-Service` above, an enumerated value.
+#
+# The following examples assume the three attributes are being added to the
+# JSON document:
+#
+# ```
+# User-Name = bob
+# Filter-Id = ab
+# Filter-Id += cd
+# ```
+#
+# #### Object output mode examples
+#
+# These modes output a JSON object.
+#
+# .Output mode "object"
+#
+# [source,json]
+# ----
+# {
+# "User-Name": {
+# "type": "string",
+# "value": "bob"
+# },
+# "Filter-Id": {
+# "type": "string",
+# "value": ["ab","cd"]
+# }
+# }
+# ----
+#
+# .Output mode "object_simple"
+#
+# [source,json]
+# ----
+# {
+# "User-Name": "bob",
+# "Filter-Id": ["ab","cd"]
+# }
+# ----
+#
+# #### Array output mode examples
+#
+# The "array" mode is a list of objects, each containing an attribute. If the
+# "single_value_as_array" value option is set then each attribute will only
+# appear once in the array, and "value" will be a list of all the values from
+# the same attribute.
+#
+# .Output mode "array"
+#
+# [source,json]
+# ----
+# [
+# {
+# "name": "User-Name",
+# "type": "string",
+# "value": "bob"
+# },
+# {
+# "name": "Filter-Id",
+# "type": "string",
+# "value": "ab"
+# },
+# {
+# "name": "Filter-Id",
+# "type": "string",
+# "value": "cd"
+# }
+# ]
+# ----
+#
+# .Output mode "array" when "single_value_as_array" is also set
+#
+# [source,json]
+# ----
+# [
+# {
+# "name": "User-Name",
+# "type": "string",
+# "value": ["bob"]
+# },
+# {
+# "name": "Filter-Id",
+# "type": "string",
+# "value": ["ab","cd"]
+# }
+# ]
+# ----
+#
+# The following output modes either do not include the attribute names or
+# values. They are likely to be useful only when the attributes are
+# individually specified and _guaranteed to exist_. In this case the attribute
+# names in `array_of_names` will have corresponding indexes to the values in
+# `array_of_values`.
+#
+# .Output mode "array_of_names"
+#
+# [source,json]
+# ----
+# [
+# "User-Name",
+# "Filter-Id",
+# "Filter-Id"
+# ]
+# ----
+#
+# .Output mode "array_of_values"
+#
+# [source,json]
+# ----
+# [
+# "bob",
+# "ab",
+# "cd"
+# ]
+# ----
+#
diff --git a/raddb/mods-available/krb5 b/raddb/mods-available/krb5
new file mode 100644
index 0000000..c88b5fb
--- /dev/null
+++ b/raddb/mods-available/krb5
@@ -0,0 +1,82 @@
+# -*- text -*-
+#
+# $Id$
+
+#
+# Kerberos. See doc/modules/rlm_krb5 for minimal docs.
+#
+krb5 {
+ #
+ # The keytab file MUST be owned by the UID/GID used by the server.
+ # The keytab file MUST be writable by the server.
+ # The keytab file MUST NOT be readable by other users on the system.
+ # The keytab file MUST exist before the server is started.
+ #
+ keytab = ${localstatedir}/lib/radiusd/keytab
+ service_principal = name_of_principle
+
+ # Pool of krb5 contexts, this allows us to make the module multithreaded
+ # and to avoid expensive operations like resolving and opening keytabs
+ # on every request. It may also allow TCP connections to the KDC to be
+ # cached if that is supported by the version of libkrb5 used.
+ #
+ # The context pool is only used if the underlying libkrb5 reported
+ # that it was thread safe at compile time.
+ #
+ pool {
+ # Connections to create during module instantiation.
+ # If the server cannot create specified number of
+ # connections during instantiation it will exit.
+ # Set to 0 to allow the server to start without the
+ # KDC being available.
+ start = ${thread[pool].start_servers}
+
+ # Minimum number of connections to keep open
+ min = ${thread[pool].min_spare_servers}
+
+ # Maximum number of connections
+ #
+ # If these connections are all in use and a new one
+ # is requested, the request will NOT get a connection.
+ #
+ # Setting 'max' to LESS than the number of threads means
+ # that some threads may starve, and you will see errors
+ # like 'No connections available and at max connection limit'
+ #
+ # Setting 'max' to MORE than the number of threads means
+ # that there are more connections than necessary.
+ max = ${thread[pool].max_servers}
+
+ # Spare connections to be left idle
+ #
+ # NOTE: Idle connections WILL be closed if "idle_timeout"
+ # is set. This should be less than or equal to "max" above.
+ spare = ${thread[pool].max_spare_servers}
+
+ # Number of uses before the connection is closed
+ #
+ # 0 means "infinite"
+ uses = 0
+
+ # The lifetime (in seconds) of the connection
+ #
+ # NOTE: A setting of 0 means infinite (no limit).
+ lifetime = 0
+
+ # The idle timeout (in seconds). A connection which is
+ # unused for this length of time will be closed.
+ #
+ # NOTE: A setting of 0 means infinite (no timeout).
+ idle_timeout = 0
+
+ # NOTE: All configuration settings are enforced. If a
+ # connection is closed because of "idle_timeout",
+ # "uses", or "lifetime", then the total number of
+ # connections MAY fall below "min". When that
+ # happens, it will open a new connection. It will
+ # also log a WARNING message.
+ #
+ # The solution is to either lower the "min" connections,
+ # or increase lifetime/idle_timeout.
+ }
+}
diff --git a/raddb/mods-available/ldap b/raddb/mods-available/ldap
new file mode 100644
index 0000000..997d41e
--- /dev/null
+++ b/raddb/mods-available/ldap
@@ -0,0 +1,712 @@
+# -*- 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 = 'localhost'
+# server = 'ldap.rrdns.example.org'
+# server = 'ldap.rrdns.example.org'
+
+ # Port to connect on, defaults to 389, will be ignored for LDAP URIs.
+# port = 389
+
+ # Administrator account for searching and possibly modifying.
+ # If using SASL + KRB5 these should be commented out.
+# identity = 'cn=admin,dc=example,dc=org'
+# password = mypass
+
+ # Unless overridden in another section, the dn from which all
+ # searches will start from.
+ base_dn = 'dc=example,dc=org'
+
+ #
+ # You can run the 'ldapsearch' command line tool using the
+ # parameters from this module's configuration.
+ #
+ # ldapsearch -D ${identity} -w ${password} -h ${server} -b 'CN=user,${base_dn}'
+ #
+ # That will give you the LDAP information for 'user'.
+ #
+ # Group membership can be queried by using the above "ldapsearch" string,
+ # and adding "memberof" qualifiers. For ActiveDirectory, use:
+ #
+ # ldapsearch ... '(&(objectClass=user)(sAMAccountName=user)(memberof=CN=group,${base_dn}))'
+ #
+ # Where 'user' is the user as above, and 'group' is the group you are querying for.
+ #
+
+ #
+ # SASL parameters to use for admin binds
+ #
+ # When we're prompted by the SASL library, these control
+ # the responses given, as well as the identity and password
+ # directives above.
+ #
+ # If any directive is commented out, a NULL response will be
+ # provided to cyrus-sasl.
+ #
+ # Unfortunately the only way to control Keberos here is through
+ # environmental variables, as cyrus-sasl provides no API to
+ # set the krb5 config directly.
+ #
+ # Full documentation for MIT krb5 can be found here:
+ #
+ # http://web.mit.edu/kerberos/krb5-devel/doc/admin/env_variables.html
+ #
+ # At a minimum you probably want to set KRB5_CLIENT_KTNAME.
+ #
+ 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'
+# 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
+
+ # LDAP "bind as user" configuration to check PAP passwords.
+ #
+ # Active Directory needs "bind as user", which can be done by
+ # adding the following "if" statement to the authorize {} section
+ # of the virtual server, after the "ldap" module. For
+ # example:
+ #
+ # ...
+ # ldap
+ # if ((ok || updated) && User-Password && !control:Auth-Type) {
+ # update {
+ # control:Auth-Type := ldap
+ # }
+ # }
+ # ...
+ #
+ # You will also need to uncomment the "Auth-Type LDAP" block in the
+ # "authenticate" section.
+ #
+ # This configuration is required because AD will not return the users
+ # "known good" password to FreeRADIUS. Instead, FreeRADIUS has to run
+ # "Auth-Type LDAP" in order to do an LDAP "bind as user", which will hand
+ # the user name / password to AD for verification.
+ #
+
+ #
+ # Name of the attribute that contains the user DN.
+ # The default name is LDAP-UserDn.
+ #
+ # If you have multiple LDAP instances, you should
+ # change this configuration item to:
+ #
+ # ${.:instance}-LDAP-UserDn
+ #
+ # That change allows the modules to set their own
+ # User DN, and to not conflict with each other.
+ #
+ user_dn = "LDAP-UserDn"
+
+ #
+ # User object identification.
+ #
+ user {
+ # Where to start searching in the tree for users
+ base_dn = "${..base_dn}"
+
+ # Filter for user objects, should be specific enough
+ # to identify a single user object.
+ #
+ # For Active Directory, you should use
+ # "samaccountname=" instead of "uid="
+ #
+ filter = "(uid=%{%{Stripped-User-Name}:-%{User-Name}})"
+
+ # For Active Directory nested group, you should comment out the previous 'filter = ...'
+ # and use the below. Where 'group' is the group you are querying for.
+ #
+ # NOTE: The string '1.2.840.113556.1.4.1941' specifies LDAP_MATCHING_RULE_IN_CHAIN.
+ # This applies only to DN attributes. This is an extended match operator that walks
+ # the chain of ancestry in objects all the way to the root until it finds a match.
+ # This reveals group nesting. It is available only on domain controllers with
+ # Windows Server 2003 SP2 or Windows Server 2008 (or above).
+ #
+ # See: https://social.technet.microsoft.com/wiki/contents/articles/5392.active-directory-ldap-syntax-filters.aspx
+ #
+# filter = "(&(objectClass=user)(sAMAccountName=%{%{Stripped-User-Name}:-%{User-Name}})(memberOf:1.2.840.113556.1.4.1941:=cn=group,${..base_dn}))"
+
+ # 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'
+
+ # Server side result sorting
+ #
+ # A list of space delimited attributes to order the result
+ # set by, if the filter matches multiple objects.
+ # Only the first result in the set will be processed.
+ #
+ # If the attribute name is prefixed with a hyphen '-' the
+ # sorting order will be reversed for that attribute.
+ #
+ # If sort_by is set, and the server does not support sorting
+ # the search will fail.
+# sort_by = '-uid'
+
+ # 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 = "${..base_dn}"
+
+ # Filter for group objects, should match all available
+ # group objects a user might be a member of.
+ #
+ # If using Active Directory you are likely to need "group"
+ # instead of "posixGroup".
+ filter = '(objectClass=posixGroup)'
+
+ # 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 all group objects a user is a member of.
+ # That is, group objects with attributes that
+ # identify members (the inverse of membership_attribute).
+ #
+ # Note that this configuration references the "user_dn"
+ # configuration defined above.
+ #
+# membership_filter = "(|(member=%{control:${..user_dn}})(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.
+ #
+ # If the LDAP server does not support the "memberOf"
+ # attribute (or equivalent), then you will need to use the
+ # membership_filter option above instead. If you can't see
+ # the memberOf attribute then it is also possible that the
+ # LDAP bind user does not have the correct permissions to
+ # view it.
+ 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 = 'no'
+# cacheable_dn = 'no'
+
+ # Override the normal cache attribute (<inst>-LDAP-Group or
+ # LDAP-Group if using the default instance) and create a
+ # custom attribute. This can help if multiple module instances
+ # are used in fail-over.
+# cache_attribute = 'LDAP-Cached-Membership'
+
+ # If the group being checked is specified as a name, but
+ # the user's groups are referenced by DN, and one of those
+ # group DNs is invalid, the whole group check is treated as
+ # invalid, and a negative result will be returned.
+ # When set to 'yes', this option ignores invalid DN
+ # references.
+# allow_dangling_group_ref = 'no'
+ }
+
+ #
+ # 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 (the update section above).
+ #
+ profile {
+ # Filter for RADIUS profile objects
+# filter = '(objectclass=radiusprofile)'
+
+ # The default profile. This may be a DN or an attribute
+ # reference.
+ # To get old v2.2.x style behaviour, or to use the
+ # &User-Profile attribute to specify the default profile,
+ # set this to &control:User-Profile.
+# default = 'cn=radprofile,dc=example,dc=org'
+
+ # The LDAP attribute containing profile DNs to apply
+ # in addition to the default profile above. These are
+ # retrieved from the user object, at the same time as the
+ # attributes from the update section, are are applied
+ # if authorization is successful.
+# attribute = 'radiusProfileDn'
+ }
+
+ #
+ # Bulk load clients from the directory
+ #
+ client {
+ # Where to start searching in the tree for clients
+ base_dn = "${..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 := "Online at %S"
+ }
+ }
+
+ 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 := "Authenticated at %S"
+ }
+ }
+
+ #
+ # 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.
+ #
+ # 'rebind' causes any connections being established to follow
+ # referrals to be bound using the admin credentials defined
+ # for this module. If it is set to 'no' libldap will bind
+ # to those connections anonymously.
+ #
+ chase_referrals = yes
+ rebind = yes
+
+ # SASL Security Properties (see SASL_SECPROPS in ldap.conf man page).
+ # Note - uncomment when using GSS-API sasl mechanism along with TLS
+ # encryption against Active-Directory LDAP servers (this disables
+ # sealing and signing at the GSS level as required by AD).
+ #sasl_secprops = 'noanonymous,noplain,maxssf=0'
+
+ # Seconds to wait for LDAP query to finish. default: 20
+ res_timeout = 10
+
+ # Seconds LDAP server has to process the query (server-side
+ # time limit). default: 20
+ #
+ # LDAP_OPT_TIMELIMIT is set to this value.
+ srv_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 = 0x0028
+ }
+
+ #
+ # 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.
+ #
+ # Note that some distributions use NSS for libldap instead
+ # of OpenSSL.
+ #
+ # If you see something like this in the debug output:
+ #
+ # TLSMC: MozNSS compatibility interception begins.
+ #
+ # Then there is a problem.
+ #
+ # THIS LDAP INSTALLATION WILL NOT WORK WITH FREERADIUS.
+ #
+ # You MUST install fixed LDAP libraries which use OpenSSL.
+ #
+ # For more details, see:
+ #
+ # http://packages.networkradius.com
+ #
+ 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 = /dev/urandom
+
+ # Certificate Verification requirements. Can be:
+ # 'never' (do not even bother trying)
+ # 'allow' (try, but don't fail if the certificate
+ # cannot be verified)
+ # 'demand' (fail if the certificate does not verify)
+ # 'hard' (similar to 'demand' but fails if TLS
+ # cannot negotiate)
+ #
+ # The default is libldap's default, which varies based
+ # on the contents of ldap.conf.
+
+# require_cert = 'demand'
+
+ #
+ # Check the CRL, as with the EAP module.
+ #
+ # The default is "no".
+ #
+# check_crl = yes
+
+ #
+ # Minimum TLS version to accept. We STRONGLY recommend
+ # setting this to "1.2"
+ #
+# tls_min_version = "1.2"
+
+ # Set this option to specify the allowed
+ # TLS cipher suites. The format is listed
+ # in "man 1 ciphers".
+ #
+ cipher_list = "DEFAULT"
+ }
+
+ # As of v3, the 'pool' section has replaced the
+ # following v2 configuration items:
+ #
+ # ldap_connections_number
+
+ #
+ # The connection pool is used to pool outgoing connections.
+ #
+ # When the server is not threaded, the connection pool
+ # limits are ignored, and only one connection is used.
+ pool {
+ # Connections to create during module instantiation.
+ # If the server cannot create specified number of
+ # connections during instantiation it will exit.
+ # Set to 0 to allow the server to start without the
+ # directory being available.
+ start = ${thread[pool].start_servers}
+
+ # Minimum number of connections to keep open
+ min = ${thread[pool].min_spare_servers}
+
+ # Maximum number of connections
+ #
+ # If these connections are all in use and a new one
+ # is requested, the request will NOT get a connection.
+ #
+ # Setting 'max' to LESS than the number of threads means
+ # that some threads may starve, and you will see errors
+ # like 'No connections available and at max connection limit'
+ #
+ # Setting 'max' to MORE than the number of threads means
+ # that there are more connections than necessary.
+ max = ${thread[pool].max_servers}
+
+ # Spare connections to be left idle
+ #
+ # NOTE: Idle connections WILL be closed if "idle_timeout"
+ # is set. This should be less than or equal to "max" above.
+ spare = ${thread[pool].max_spare_servers}
+
+ # Number of uses before the connection is closed
+ #
+ # 0 means "infinite"
+ uses = 0
+
+ # 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 = 30
+
+ # 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
+
+ # 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.
+
+ # Maximum number of times an operation can be retried
+ # if it returns an error which indicates the connection
+ # needs to be restarted. This includes timeouts.
+ max_retries = 5
+ }
+}
diff --git a/raddb/mods-available/ldap_google b/raddb/mods-available/ldap_google
new file mode 100644
index 0000000..03c98d3
--- /dev/null
+++ b/raddb/mods-available/ldap_google
@@ -0,0 +1,262 @@
+# -*- text -*-
+#
+# $Id$
+
+#
+# This file contains an instance of the ldap module which has been
+# configured for the G Suite / Google Workspace Secure LDAP server.
+# There are a few steps which still need to be taken, but they are
+# documented clearly below.
+#
+# In order to use the Google LDAP server, a client must first be
+# created. See Google's documentation for doing this:
+#
+# https://support.google.com/a/answer/9048434?hl=en&ref_topic=9173976
+#
+# Google LDAP requires that any system connecting to it use a client
+# certificate. However, FreeRADIUS also requires a username and
+# password in the "ldap" module configuration. Therere before
+# downloading the client certificate from Google, you should choose
+# the option to generate access credentials in order to obtain a
+# username and password. That username and password should be used
+# below.
+#
+# Ensure the Goolge client configuration which is used for FreeRADIUS
+# has sufficient permissions to read user information, and, if group
+# membership is part of the FreeRADIUS policy, ensure that the client
+# can read group information. This configuration is done on Google's
+# systems. Please see the Google documentation for more information.
+#
+# NOTE: The Google LDAP database does NOT return user passwords in
+# the search results!
+#
+# Therefore, if Google LDAP is being used for authentication, it will
+# ONLY work when using "LDAP bind as user". The authentication
+# method used there MUST also provide the user password in plain
+# text. This limits the use of Google LDAP to PAP, and TTLS+PAP.
+# Anything else simply will not work, and nothing you do will ever
+# make it work.
+#
+# The Google LDAP service has been observed to have poor
+# performance compared to a dedicated / local LDAP server like
+# OpenLDAP. In order to improve performance, we simply bypass it
+# completely by caching things associated with accept and reject.
+# See mods-available/cache_auth for the cache configuration, and
+# sites-available/google-ldap-auth for a sample virtual server which
+# uses this module, and the cache.
+#
+# In addition, if you are using Google LDAP service as part of WiFi
+# authentication (remember, only TTLS+PAP will work!), then we also
+# recommend enabling the "cache" configuration in mods-available/eap.
+# That cache is a separate one from mods-available/cache_auth, and
+# both caches can be used at the same time.
+#
+#
+# The comments in this file are specific to using the Google Secure
+# LDAP service. For more general LDAP module configuration, see the
+# mods-available/ldap.
+#
+ldap ldap_google {
+ # The standard Google LDAP server URL
+ server = 'ldaps://ldap.google.com:636/'
+
+ # Google LDAP client username and password as generated during
+ # client creation.
+# identity = 'myuser'
+# password = 'mypass'
+
+ # Base dn for your organisation.
+ base_dn = 'dc=example,dc=org'
+
+ #
+ # The default Google LDAP schema can be seen here
+ #
+ # https://support.google.com/a/answer/9188164
+ #
+ # Custom attributes can be added to user profiles, and those
+ # custom attributes can then be accessed in the LDAP
+ # directory:
+ #
+ # https://support.google.com/a/answer/6208725
+ #
+ # You can run the 'ldapsearch' command line tool using the
+ # parameters from this module's configuration.
+ #
+ # LDAPTLS_REQCERT=ALLOW \
+ # LDAPTLS_CERT="<Google certificate file>" \
+ # LDAPTLS_KEY="<Google key file>" \
+ # ldapsearch -H ${server} -b '${base_dn}' '(uid=user)'
+ #
+ # That command will return the LDAP information for 'user'.
+ #
+ # Group membership can be queried by using the above "ldapsearch" string,
+ # and adding "memberof" qualifiers.
+ #
+
+# valuepair_attribute = 'radiusAttribute'
+
+ update {
+# reply:Reply-Message := 'radiusReplyMessage'
+# reply:Tunnel-Type := 'radiusTunnelType'
+# reply:Tunnel-Medium-Type := 'radiusTunnelMediumType'
+# reply:Tunnel-Private-Group-ID := 'radiusTunnelPrivategroupId'
+
+ control: += 'radiusControlAttribute'
+ request: += 'radiusRequestAttribute'
+ reply: += 'radiusReplyAttribute'
+ }
+
+ #
+ # In order to use LDAP "bind as user" authentication, you
+ # should add following "if" statement to the authorize {}
+ # section of the virtual server, after the "ldap" module.
+ # For example:
+ #
+ # ...
+ # ldap_google
+ # if ((ok || updated) && User-Password && !control:Auth-Type) {
+ # update {
+ # &control:Auth-Type := ldap
+ # }
+ # }
+ # ...
+ #
+ # You will also need to uncomment the "Auth-Type LDAP" block in the
+ # "authenticate" section.
+ #
+ # Note that these configuration steps have already been done
+ # in the sample virtual server, in
+ # sites-available/google-ldap-auth.
+ #
+
+ #
+ # If you change this, you will also need to update the
+ # "cache_ldap_user_dn" module in mods-available/cache_auth.
+ #
+ user_dn = "LDAP-UserDn"
+
+ #
+ # User object identification.
+ #
+ user {
+ # The typical Google LDAP configuration has users under "ou=Users..."
+ base_dn = "ou=Users,${..base_dn}"
+
+ filter = "(uid=%{%{Stripped-User-Name}:-%{User-Name}})"
+
+ scope = 'sub'
+
+# sort_by = '-uid'
+
+# access_attribute = 'dialupAccess'
+
+# access_positive = yes
+ }
+
+ #
+ # User membership checking.
+ #
+ group {
+ # The typical Google LDAP configuration has groups under "ou=Groups..."
+ base_dn = "ou=Groups,${..base_dn}"
+
+ filter = '(objectClass=posixGroup)'
+
+ scope = 'sub'
+
+ name_attribute = cn
+
+ #
+ # Google Secure LDAP supports the "memberOf"
+ # attribute, which is more efficient than using this
+ # filter.
+ #
+ # You should also check the permissions of the client
+ # in Google's systems to ensure that it is allowed to
+ # read group information.
+ #
+# membership_filter = "(|(member=%{control:${..user_dn}})(memberUid=%{%{Stripped-User-Name}:-%{User-Name}}))"
+
+ membership_attribute = 'memberOf'
+
+ #
+ # If the "memberOf" attribute is used for retrieving group membership,
+ # then you should also use "cacheable_dn", in orser to cache the group details.
+ # "memberOf" is a list of fully quallified group DNs which the user belongs to,
+ # so using the DN for the cache avoids further lookups to retrieve group names.
+ #
+# cacheable_name = 'no'
+# cacheable_dn = 'no'
+
+# cache_attribute = 'LDAP-Cached-Membership'
+
+# allow_dangling_group_ref = 'no'
+ }
+
+ options {
+# dereference = 'always'
+
+ # Google Secure LDAP does not appear to do referrals, so we might as well
+ # turn this off.
+ chase_referrals = no
+# rebind = yes
+
+ # Some reasonable defaults for use with Google Secure LDAP
+ #
+ # See mods-available/ldap for a complete description
+ # of what these configuration options mean.
+ #
+ res_timeout = 10
+ srv_timelimit = 3
+ net_timeout = 3
+ idle = 60
+ probes = 3
+ interval = 3
+
+ ldap_debug = 0x0000
+ }
+
+ tls {
+
+ #
+ # The certificate and key which were downloaded from the Google
+ # client tools are configured here.
+ #
+ # By default ${certdir} is raddb/certs/. You can
+ # please these files anywhere you want. The only
+ # requirement is that they are readable by
+ # FreeRADIUS, and NOT readable by anyone else on the
+ # system!
+ #
+# certificate_file = ${certdir}/google/certificate.crt
+# private_key_file = ${certdir}/google/key.key
+# random_file = /dev/urandom
+
+ #
+ # Google Secure LDAP uses a self signed certificate
+ # so this configuration needs to be set to 'allow'
+ #
+ require_cert = 'allow'
+
+ #
+ # We recommend not using TLS 1.0 or 1.1.
+ #
+# tls_min_version = "1.2"
+ }
+
+ #
+ # See mods-available/ldap for documentation on the "pool"
+ # section and its configuration items.
+ #
+ pool {
+ start = ${thread[pool].start_servers}
+ min = ${thread[pool].min_spare_servers}
+ max = ${thread[pool].max_servers}
+ spare = ${thread[pool].max_spare_servers}
+
+ uses = 0
+ retry_delay = 30
+ lifetime = 0
+ idle_timeout = 60
+ }
+}
diff --git a/raddb/mods-available/linelog b/raddb/mods-available/linelog
new file mode 100644
index 0000000..66d2682
--- /dev/null
+++ b/raddb/mods-available/linelog
@@ -0,0 +1,170 @@
+# -*- text -*-
+#
+# $Id$
+
+#
+# The "linelog" module will log one line of text to a file.
+# Both the filename and the line of text are dynamically expanded.
+#
+# We STRONGLY suggest that you do not use data from the
+# packet as part of the filename.
+#
+linelog {
+ #
+ # The file where the logs will go.
+ #
+ # If the filename is "syslog", then the log messages will
+ # go to syslog.
+ #
+ # The output can be directed to stdout by using /dev/stdout
+ #
+ filename = ${logdir}/linelog
+
+ #
+ # Most file systems can handly nearly the full range of UTF-8
+ # characters. Ones that can deal with a limited range should
+ # set this to "yes".
+ #
+ escape_filenames = no
+
+ #
+ # The Unix-style permissions on the log file.
+ #
+ # Depending on format string, the log file may contain secret or
+ # private information about users. Keep the file permissions as
+ # restrictive as possible.
+ permissions = 0600
+
+ # The Unix group which owns the log file.
+ #
+ # The user that freeradius runs as must be in the specified
+ # group, otherwise it will not be possible to set the group.
+# group = ${security.group}
+
+ # Syslog facility (if logging via syslog).
+ # Defaults to the syslog_facility config item in radiusd.conf.
+ # Standard facilities are:
+ # - kern Messages generated by the kernel. These cannot
+ # be generated by any user processes.
+ # - user Messages generated by random user processes.
+ # This is the default facility identifier if
+ # none is specified.
+ # - mail The mail system.
+ # - daemon System daemons, such as routed(8), that are not
+ # provided for explicitly by other facilities.
+ # - auth The authorization system: login(1), su(1),
+ # getty(8), etc.
+ # - lpr The line printer spooling system: cups-lpd(8),
+ # cupsd(8), etc.
+ # - news The network news system.
+ # - uucp The uucp system.
+ # - cron The cron daemon: cron(8).
+ # - authpriv The same as LOG_AUTH, but logged to a file
+ # readable only by selected individuals.
+ # - ftp The file transfer protocol daemons: ftpd(8),
+ # tftpd(8).
+ # - local[0-7] Reserved for local use.
+# syslog_facility = daemon
+
+ # Syslog severity (if logging via syslog). Defaults to info.
+ # Possible values are:
+ # - emergency A panic condition. This is normally broadcast
+ # to all users.
+ # - alert A condition that should be corrected immediately,
+ # such as a corrupted system database.
+ # - critical Critical conditions, e.g., hard device errors.
+ # - error Errors.
+ # - warning Warning messages.
+ # - notice Conditions that are not error conditions, but
+ # should possibly be handled specially.
+ # - info Informational messages.
+ # - debug Messages that contain information normally of use
+ # only when debugging a program.
+# syslog_severity = info
+
+ # If logging via syslog, the severity can be set here.
+ # Defaults to info.
+
+ #
+ # Optional header format string.
+ # Written to the first line of any newly created log file
+# header = "This is a header line"
+
+ #
+ # The default format string.
+ format = "This is a log message for %{User-Name}"
+
+ #
+ # This next line can be omitted. If it is omitted, then
+ # the log message is static, and is always given by "format",
+ # above.
+ #
+ # If it is defined, then the string is dynamically expanded,
+ # and the result is used to find another configuration entry
+ # here, with the given name. That name is then used as the
+ # format string.
+ #
+ # If the configuration entry cannot be found, then no log
+ # message is printed.
+ #
+ # i.e. You can have many log messages in one "linelog" module.
+ # If this two-step expansion did not exist, you would have
+ # needed to configure one "linelog" module for each log message.
+
+ #
+ # Reference the Packet-Type (Access-Accept, etc.) If it doesn't
+ # exist, reference the "default" entry.
+ #
+ # This is for "linelog" being used in the post-auth section
+ # If you want to use it in "authorize", you need to change
+ # the reference to "messages.%{%{Packet-Type}:-default}",
+ # and then add the appropriate messages.
+ #
+ reference = "messages.%{%{reply:Packet-Type}:-default}"
+
+ #
+ # The messages defined here are taken from the "reference"
+ # expansion, above.
+ #
+ messages {
+ default = "Unknown packet type %{Packet-Type}"
+
+ Access-Accept = "Accepted user: %{User-Name}"
+ Access-Reject = "Rejected user: %{User-Name}"
+ Access-Challenge = "Sent challenge: %{User-Name}"
+ }
+}
+
+#
+# Another example, for accounting packets.
+#
+linelog log_accounting {
+ #
+ # Used if the expansion of "reference" fails.
+ #
+ format = ""
+
+ filename = ${logdir}/linelog-accounting
+
+ permissions = 0600
+
+ reference = "Accounting-Request.%{%{Acct-Status-Type}:-unknown}"
+
+ #
+ # Another example:
+ #
+ #
+ Accounting-Request {
+ Start = "Connect: [%{User-Name}] (did %{Called-Station-Id} cli %{Calling-Station-Id} port %{NAS-Port} ip %{Framed-IP-Address})"
+ Stop = "Disconnect: [%{User-Name}] (did %{Called-Station-Id} cli %{Calling-Station-Id} port %{NAS-Port} ip %{Framed-IP-Address}) %{Acct-Session-Time} seconds"
+
+ # Don't log anything for these packets.
+ Alive = ""
+
+ Accounting-On = "NAS %{%{Packet-Src-IP-Address}:-%{Packet-Src-IPv6-Address}} (%{%{NAS-IP-Address}:-%{NAS-IPv6-Address}}) just came online"
+ Accounting-Off = "NAS %{%{Packet-Src-IP-Address}:-%{Packet-Src-IPv6-Address}} (%{%{NAS-IP-Address}:-%{NAS-IPv6-Address}}) just went offline"
+
+ # don't log anything for other Acct-Status-Types.
+ unknown = "NAS %{%{Packet-Src-IP-Address}:-%{Packet-Src-IPv6-Address}} (%{%{NAS-IP-Address}:-%{NAS-IPv6-Address}}) sent unknown Acct-Status-Type %{Acct-Status-Type}"
+ }
+}
diff --git a/raddb/mods-available/logintime b/raddb/mods-available/logintime
new file mode 100644
index 0000000..2534452
--- /dev/null
+++ b/raddb/mods-available/logintime
@@ -0,0 +1,23 @@
+# -*- text -*-
+#
+# $Id$
+
+# The logintime module. This handles the Login-Time,
+# Current-Time, and Time-Of-Day attributes. It should be
+# included in the *end* of the authorize section in order to
+# handle Login-Time checks. It should also be included in the
+# instantiate section in order to register the Current-Time
+# and Time-Of-Day comparison functions.
+#
+# When the Login-Time attribute is set to some value, and the
+# user has been permitted to log in, a Session-Timeout is
+# calculated based on the remaining time. See "doc/README".
+#
+logintime {
+ # The minimum timeout (in seconds) a user is allowed
+ # to have. If the calculated timeout is lower we don't
+ # allow the login. Some NAS do not handle values
+ # lower than 60 seconds well.
+ minimum_timeout = 60
+}
+
diff --git a/raddb/mods-available/mac2ip b/raddb/mods-available/mac2ip
new file mode 100644
index 0000000..a4ead1d
--- /dev/null
+++ b/raddb/mods-available/mac2ip
@@ -0,0 +1,25 @@
+# -*- text -*-
+#
+# $Id$
+
+######################################################################
+#
+# This next section is a sample configuration for the "passwd"
+# module, that reads flat-text files.
+#
+# The file is in the format <mac>,<ip>
+#
+# 00:01:02:03:04:05,192.0.2.100
+# 01:01:02:03:04:05,192.0.2.101
+# 02:01:02:03:04:05,192.0.2.102
+#
+# This lets you perform simple static IP assignments from a flat-text
+# file. You will have to define lease times yourself.
+#
+######################################################################
+
+passwd mac2ip {
+ filename = ${modconfdir}/${.:name}/${.:instance}
+ format = "*DHCP-Client-Hardware-Address:=DHCP-Your-IP-Address"
+ delimiter = ","
+}
diff --git a/raddb/mods-available/mac2vlan b/raddb/mods-available/mac2vlan
new file mode 100644
index 0000000..a1db803
--- /dev/null
+++ b/raddb/mods-available/mac2vlan
@@ -0,0 +1,18 @@
+# -*- text -*-
+#
+# $Id$
+
+# A simple file to map a MAC address to a VLAN.
+#
+# The file should be in the format MAC,VLAN
+# the VLAN name cannot have spaces in it, for example:
+#
+# 00:01:02:03:04:05,VLAN1
+# 03:04:05:06:07:08,VLAN2
+# ...
+#
+passwd mac2vlan {
+ filename = ${modconfdir}/${.:name}/${.:instance}
+ format = "*VMPS-Mac:=VMPS-VLAN-Name"
+ delimiter = ","
+}
diff --git a/raddb/mods-available/moonshot-targeted-ids b/raddb/mods-available/moonshot-targeted-ids
new file mode 100644
index 0000000..1b27b44
--- /dev/null
+++ b/raddb/mods-available/moonshot-targeted-ids
@@ -0,0 +1,57 @@
+# -*- text -*-
+#
+# $Id$
+
+#
+# Write Moonshot-*-TargetedId (MSTID) to the database.
+#
+# Schema raddb/mods-config/sql/moonshot-targeted-ids/<DB>/schema.sql
+# Queries raddb/mods-config/sql/moonshot-targeted-ids/<DB>/queries.conf
+#
+sql moonshot_tid_sql {
+
+ # The dialect of SQL you want to use, this should usually match
+ # the driver below.
+ #
+ # If you're using rlm_sql_null, then it should be the type of
+ # database the logged queries are going to be executed against.
+ dialect = "sqlite"
+
+ # The sub-module to use to execute queries. This should match
+ # the database you're attempting to connect to.
+ #
+ # There are MSTID queries available for:
+ # * rlm_sql_mysql
+ # * rlm_sql_postgresql
+ # * rlm_sql_sqlite
+ # * rlm_sql_null (log queries to disk)
+ #
+ driver = "rlm_sql_${dialect}"
+
+ sqlite {
+ filename = ${radacctdir}/moonshot-targeted-ids.sqlite
+ bootstrap = ${modconfdir}/${..:name}/moonshot-targeted-ids/sqlite/schema.sql
+ }
+
+ # Write MSTID queries to a logfile. Useful for debugging.
+# logfile = ${logdir}/moonshot-targeted-id-log.sql
+
+ pool {
+ start = 5
+ min = 4
+ max = 10
+ spare = 3
+ uses = 0
+ lifetime = 0
+ idle_timeout = 60
+ }
+
+ # If you adjust the table name here, you must also modify the table name in
+ # the moonshot_get_targeted_id.post-auth policy in policy.d/moonshot-targeted-ids
+ # and the schema.sql files in the mods-config/sql/moonshot-targeted-ids tree.
+ #
+ moonshot_tid_table = "moonshot_targeted_ids"
+ sql_user_name = "%{User-Name}"
+
+ $INCLUDE ${modconfdir}/${.:name}/moonshot-targeted-ids/${dialect}/queries.conf
+}
diff --git a/raddb/mods-available/mschap b/raddb/mods-available/mschap
new file mode 100644
index 0000000..1748d57
--- /dev/null
+++ b/raddb/mods-available/mschap
@@ -0,0 +1,253 @@
+# -*- text -*-
+#
+# $Id$
+
+#
+# Microsoft CHAP authentication
+#
+# This module supports MS-CHAP and MS-CHAPv2 authentication.
+# It also enforces the SMB-Account-Ctrl attribute.
+#
+mschap {
+ #
+ # If you are using /etc/smbpasswd, see the 'passwd'
+ # module for an example of how to use /etc/smbpasswd
+ #
+
+ #
+ # 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
+
+ #
+ # This module can perform authentication itself, OR
+ # use a Windows Domain Controller. This configuration
+ # directive tells the module to call the ntlm_auth
+ # program, which will do the authentication, and return
+ # the NT-Key. Note that you MUST have "winbindd" and
+ # "nmbd" running on the local machine for ntlm_auth
+ # to work. See the ntlm_auth program documentation
+ # for details.
+ #
+ # If ntlm_auth is configured below, then the mschap
+ # module will call ntlm_auth for every MS-CHAP
+ # authentication request. If there is a cleartext
+ # or NT hashed password available, you can set
+ # "MS-CHAP-Use-NTLM-Auth := No" in the control items,
+ # and the mschap module will do the authentication itself,
+ # without calling ntlm_auth.
+ #
+ # Be VERY careful when editing the following line!
+ #
+ # You can also try setting the user name as:
+ #
+ # ... --username=%{mschap:User-Name} ...
+ #
+ # In that case, the mschap module will look at the User-Name
+ # attribute, and do prefix/suffix checks in order to obtain
+ # the "best" user name for the request.
+ #
+ # For Samba 4, you should also set the "ntlm auth" parameter
+ # in the Samba configuration:
+ #
+ # ntlm auth = yes
+ #
+ # or
+ #
+ # ntlm auth = mschapv2-and-ntlmv2-only
+ #
+ # This will let Samba 4 accept the MS-CHAP authentication
+ # method that is needed by FreeRADIUS.
+ #
+ # Depending on the Samba version, you may also need to add:
+ #
+ # --allow-mschapv2
+ #
+ # to the command-line parameters.
+ #
+# ntlm_auth = "/path/to/ntlm_auth --request-nt-key --allow-mschapv2 --username=%{%{Stripped-User-Name}:-%{%{User-Name}:-None}} --challenge=%{%{mschap:Challenge}:-00} --nt-response=%{%{mschap:NT-Response}:-00}"
+
+ #
+ # The default is to wait 10 seconds for ntlm_auth to
+ # complete. This is a long time, and if it's taking that
+ # long then you likely have other problems in your domain.
+ # The length of time can be decreased with the following
+ # option, which can save clients waiting if your ntlm_auth
+ # usually finishes quicker. Range 1 to 10 seconds.
+ #
+# ntlm_auth_timeout = 10
+
+ #
+ # An alternative to using ntlm_auth is to connect to the
+ # winbind daemon directly for authentication. This option
+ # is likely to be faster and may be useful on busy systems,
+ # but is less well tested.
+ #
+ # Using this option requires libwbclient from Samba 4.2.1
+ # or later to be installed. Make sure that ntlm_auth above is
+ # commented out.
+ #
+# winbind_username = "%{mschap:User-Name}"
+# winbind_domain = "%{mschap:NT-Domain}"
+
+ #
+ # When using single sign-on with a winbind connection and the
+ # client uses a different casing for the username than the
+ # casing is according to the backend, reauth may fail because
+ # of some Windows internals. This switch tries to find the
+ # user in the correct casing in the backend, and retry
+ # authentication with that username.
+ #
+# winbind_retry_with_normalised_username = no
+
+ #
+ # Information for the winbind connection pool. The configuration
+ # items below are the same for all modules which use the new
+ # connection pool.
+ #
+ pool {
+ #
+ # Connections to create during module instantiation.
+ # If the server cannot create specified number of
+ # connections during instantiation it will exit.
+ # Set to 0 to allow the server to start without the
+ # winbind daemon being available.
+ #
+ start = ${thread[pool].start_servers}
+
+ #
+ # Minimum number of connections to keep open
+ #
+ min = ${thread[pool].min_spare_servers}
+
+ #
+ # Maximum number of connections
+ #
+ # If these connections are all in use and a new one
+ # is requested, the request will NOT get a connection.
+ #
+ # Setting 'max' to LESS than the number of threads means
+ # that some threads may starve, and you will see errors
+ # like 'No connections available and at max connection limit'
+ #
+ # Setting 'max' to MORE than the number of threads means
+ # that there are more connections than necessary.
+ #
+ max = ${thread[pool].max_servers}
+
+ #
+ # Spare connections to be left idle
+ #
+ # NOTE: Idle connections WILL be closed if "idle_timeout"
+ # is set. This should be less than or equal to "max" above.
+ #
+ spare = ${thread[pool].max_spare_servers}
+
+ #
+ # Number of uses before the connection is closed
+ #
+ # 0 means "infinite"
+ #
+ uses = 0
+
+ #
+ # 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 = 30
+
+ #
+ # The lifetime (in seconds) of the connection
+ #
+ # NOTE: A setting of 0 means infinite (no limit).
+ #
+ lifetime = 86400
+
+ #
+ # The pool is checked for free connections every
+ # "cleanup_interval". If there are free connections,
+ # then one of them is closed.
+ #
+ cleanup_interval = 300
+
+ #
+ # The idle timeout (in seconds). A connection which is
+ # unused for this length of time will be closed.
+ #
+ # NOTE: A setting of 0 means infinite (no timeout).
+ #
+ idle_timeout = 600
+
+ #
+ # 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.
+ #
+ }
+
+ passchange {
+ #
+ # This support MS-CHAPv2 (not v1) password change
+ # requests. See doc/mschap.rst for more IMPORTANT
+ # information.
+ #
+ # Samba/ntlm_auth - if you are using ntlm_auth to
+ # validate passwords, you will need to use ntlm_auth
+ # to change passwords. Uncomment the three lines
+ # below, and change the path to ntlm_auth.
+ #
+# ntlm_auth = "/usr/bin/ntlm_auth --helper-protocol=ntlm-change-password-1"
+# ntlm_auth_username = "username: %{mschap:User-Name}"
+# ntlm_auth_domain = "nt-domain: %{mschap:NT-Domain}"
+
+ #
+ # To implement a local password change, you need to
+ # supply a string which is then expanded, so that the
+ # password can be placed somewhere. e.g. passed to a
+ # script (exec), or written to SQL (UPDATE/INSERT).
+ # We give both examples here, but only one will be
+ # used.
+ #
+# local_cpw = "%{exec:/path/to/script %{mschap:User-Name} %{MS-CHAP-New-Cleartext-Password}}"
+ #
+# local_cpw = "%{sql:UPDATE radcheck set value='%{MS-CHAP-New-NT-Password}' where username='%{SQL-User-Name}' and attribute='NT-Password'}"
+ }
+
+ #
+ # For Apple Server, when running on the same machine as
+ # Open Directory. It has no effect on other systems.
+ #
+# use_open_directory = yes
+
+ #
+ # On failure, set (or not) the MS-CHAP error code saying
+ # "retries allowed".
+ #
+# allow_retry = yes
+
+ #
+ # An optional retry message.
+ #
+# retry_msg = "Re-enter (or reset) the password"
+}
diff --git a/raddb/mods-available/ntlm_auth b/raddb/mods-available/ntlm_auth
new file mode 100644
index 0000000..ab0017c
--- /dev/null
+++ b/raddb/mods-available/ntlm_auth
@@ -0,0 +1,18 @@
+#
+# For testing ntlm_auth authentication with PAP.
+#
+# If you have problems with authentication failing, even when the
+# password is good, it may be a bug in Samba:
+#
+# https://bugzilla.samba.org/show_bug.cgi?id=6563
+#
+# Depending on the AD / Samba configuration, you may also need to add:
+#
+# --allow-mschapv2
+#
+# to the list of command-line options.
+#
+exec ntlm_auth {
+ wait = yes
+ program = "/path/to/ntlm_auth --request-nt-key --domain=MYDOMAIN --username=%{mschap:User-Name} --password=%{User-Password}"
+}
diff --git a/raddb/mods-available/opendirectory b/raddb/mods-available/opendirectory
new file mode 100644
index 0000000..443d74d
--- /dev/null
+++ b/raddb/mods-available/opendirectory
@@ -0,0 +1,26 @@
+# -*- text -*-
+#
+# $Id$
+
+# This module is only used when the server is running on the same
+# system as OpenDirectory. The configuration of the module is hard-coded
+# by Apple, and cannot be changed here.
+#
+# There are no configuration entries for this module.
+#
+# The MS-CHAP module will automatically talk to OpenDirectory, if the
+# server is built on an OSX machine. However, you must also set
+# dsAttrTypeNative:apple-enabled-auth-mech attribute in the
+# /config/dirserv OpenDirectory record. You will probably also need
+# to change the user passwords in order to re-generate the
+# appropriate hashes.
+#
+# Complete OSX configuration information is available on Apple's web site:
+#
+# https://developer.apple.com/support/macos-server/macOS-Server-Service-Migration-Guide.pdf
+#
+# See also https://discussions.apple.com/thread/6053980?tstart=0
+#
+opendirectory {
+
+}
diff --git a/raddb/mods-available/pam b/raddb/mods-available/pam
new file mode 100644
index 0000000..f4a91a9
--- /dev/null
+++ b/raddb/mods-available/pam
@@ -0,0 +1,26 @@
+# -*- text -*-
+#
+# $Id$
+
+
+# Pluggable Authentication Modules
+#
+# For Linux, see:
+# http://www.kernel.org/pub/linux/libs/pam/index.html
+#
+# WARNING: On many systems, the system PAM libraries have
+# memory leaks! We STRONGLY SUGGEST that you do not
+# use PAM for authentication, due to those memory leaks.
+#
+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
+}
diff --git a/raddb/mods-available/pap b/raddb/mods-available/pap
new file mode 100644
index 0000000..0038ecd
--- /dev/null
+++ b/raddb/mods-available/pap
@@ -0,0 +1,18 @@
+# -*- text -*-
+#
+# $Id$
+
+# PAP module to authenticate users based on their stored password
+#
+# Supports multiple encryption/hash schemes. See "man rlm_pap"
+# for details.
+#
+# For instructions on creating the various types of passwords, see:
+#
+# http://www.openldap.org/faq/data/cache/347.html
+pap {
+ # By default the server will use heuristics to try and automatically
+ # handle base64 or hex encoded passwords. This behaviour can be
+ # stopped by setting the following to "no".
+# normalise = yes
+}
diff --git a/raddb/mods-available/passwd b/raddb/mods-available/passwd
new file mode 100644
index 0000000..11bd224
--- /dev/null
+++ b/raddb/mods-available/passwd
@@ -0,0 +1,55 @@
+# -*- text -*-
+#
+# $Id$
+
+# passwd module allows to do authorization via any passwd-like
+# file and to extract any attributes from these files.
+#
+# See the "smbpasswd" and "etc_group" files for more examples.
+#
+# parameters are:
+# filename - path to file
+#
+# format - format for filename record. This parameters
+# correlates record in the passwd file and RADIUS
+# attributes.
+#
+# Field marked as '*' is a key field. That is, the parameter
+# with this name from the request is used to search for
+# the record from passwd file
+#
+# Attributes marked as '=' are added to reply_items instead
+# of default configure_items
+#
+# Attributes marked as '~' are added to request_items
+#
+# Field marked as ',' may contain a comma separated list
+# of attributes.
+#
+# hash_size - hashtable size. Setting it to 0 is no longer permitted
+# A future version of the server will have the module
+# automatically determine the hash size. Having it set
+# manually should not be necessary.
+#
+# allow_multiple_keys - if many records for a 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/passwd.
+#
+# This is an example which will NOT WORK if you have shadow passwords,
+# NIS, etc. The "unix" module is normally responsible for reading
+# system passwords. You should use it instead of this example.
+#
+passwd etc_passwd {
+ filename = /etc/passwd
+ format = "*User-Name:Crypt-Password:"
+ hash_size = 100
+ ignore_nislike = no
+ allow_multiple_keys = no
+}
diff --git a/raddb/mods-available/perl b/raddb/mods-available/perl
new file mode 100644
index 0000000..99215b8
--- /dev/null
+++ b/raddb/mods-available/perl
@@ -0,0 +1,94 @@
+# -*- text -*-
+#
+# $Id$
+
+# Persistent, embedded Perl interpreter.
+#
+perl {
+ #
+ # The Perl script to execute on authorize, authenticate,
+ # accounting, xlat, etc. This is very similar to using
+ # 'rlm_exec' module, but it is persistent, and therefore
+ # faster.
+ #
+ filename = ${modconfdir}/${.:instance}/example.pl
+
+ #
+ # Options which are passed to the Perl interpreter.
+ # These are (mostly) the same options as are passed
+ # to the "perl" command line.
+ #
+ # The most useful flag is "-T". This sets tainting on, which
+ # makes it impossible to leverage bad User-Names into local
+ # command execution.
+ #
+ perl_flags = "-T"
+
+ #
+ # The following hashes are given to the module and
+ # filled with value-pairs (Attribute names and values)
+ #
+ # %RAD_CHECK Check items
+ # %RAD_REQUEST Attributes from the request
+ # %RAD_REPLY Attributes for the reply
+ # %RAD_REQUEST_PROXY Attributes from the proxied request
+ # %RAD_REQUEST_PROXY_REPLY Attributes from the proxy reply
+ #
+ # The interface between FreeRADIUS and Perl is strings.
+ # That is, attributes of type "octets" are converted to
+ # printable strings, such as "0xabcdef". If you want to
+ # access the binary values of the attributes, you should
+ # call the Perl "pack" function. Then to send any binary
+ # data back to FreeRADIUS, call the Perl "unpack" function,
+ # so that the contents of the hashes are printable strings.
+ #
+ # IP addresses are sent as strings, e.g. "192.0.2.25", and
+ # not as a 4-byte binary value. The same applies to other
+ # attribute data types.
+ #
+ # Attributes of type "string" are copied to Perl as-is.
+ # They are not escaped or interpreted.
+ #
+ # The return codes from functions in the perl_script
+ # are passed directly back to the server. These
+ # codes are defined in mods-config/example.pl
+ #
+
+ # You can define configuration items (and nested sub-sections) in perl "config" section.
+ # These items will be accessible in the perl script through %RAD_PERLCONF hash.
+ # For instance: $RAD_PERLCONF{'name'} $RAD_PERLCONF{'sub-config'}->{'name'}
+ #
+ #config {
+ # name = "value"
+ # sub-config {
+ # name = "value of name from config.sub-config"
+ # }
+ #}
+
+ #
+ # List of functions in the module to call.
+ # Uncomment and change if you want to use function
+ # names other than the defaults.
+ #
+ #func_authenticate = authenticate
+ #func_authorize = authorize
+ #func_preacct = preacct
+ #func_accounting = accounting
+ #func_checksimul = checksimul
+ #func_pre_proxy = pre_proxy
+ #func_post_proxy = post_proxy
+ #func_post_auth = post_auth
+ #func_recv_coa = recv_coa
+ #func_send_coa = send_coa
+ #func_xlat = xlat
+ #func_detach = detach
+
+ #
+ # Uncomment the following lines if you wish
+ # to use separate functions for Start and Stop
+ # accounting packets. In that case, the
+ # func_accounting function is not called.
+ #
+ #func_start_accounting = accounting_start
+ #func_stop_accounting = accounting_stop
+}
diff --git a/raddb/mods-available/preprocess b/raddb/mods-available/preprocess
new file mode 100644
index 0000000..8baec79
--- /dev/null
+++ b/raddb/mods-available/preprocess
@@ -0,0 +1,62 @@
+# -*- text -*-
+#
+# $Id$
+
+# 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 NAS, and converts the attributes into a form which
+# is a little more standard.
+#
+preprocess {
+ # Search for files in a subdirectory of mods-config which
+ # matches this instance of the preprocess module.
+ moddir = ${modconfdir}/${.:instance}
+
+ huntgroups = ${moddir}/huntgroups
+ hints = ${moddir}/hints
+
+ # This hack changes Ascend's weird port numbering
+ # 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.
+ #
+ # This configuration entry SHOULD NOT be used.
+ # See the "realms" module for a better way to handle
+ # NT domains.
+ 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 (and Quintum in Cisco mode) 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 or Quintum NAS, you don't
+ # need this hack.
+ with_cisco_vsa_hack = no
+}
diff --git a/raddb/mods-available/python b/raddb/mods-available/python
new file mode 100644
index 0000000..371a56d
--- /dev/null
+++ b/raddb/mods-available/python
@@ -0,0 +1,65 @@
+#
+# Make sure the PYTHONPATH environmental variable contains the
+# directory(s) for the modules listed below.
+#
+# Uncomment any func_* which are included in your module. If
+# rlm_python is called for a section which does not have
+# a function defined, it will return NOOP.
+#
+python {
+ # Path to the python modules
+ #
+ # Note that due to limitations on Python, this configuration
+ # item is GLOBAL TO THE SERVER. That is, you cannot have two
+ # instances of the python module, each with a different path.
+ #
+# python_path="${modconfdir}/${.:name}:/path/to/python/files:/another_path/to/python_files/"
+
+ module = example
+
+ # Pass all VPS lists as a 6-tuple to the callbacks
+ # (request, reply, config, state, proxy_req, proxy_reply)
+# pass_all_vps = no
+
+ # Pass all VPS lists as a dictionary to the callbacks
+ # Keys: "request", "reply", "config", "session-state", "proxy-request",
+ # "proxy-reply"
+ # This option prevales over "pass_all_vps"
+# pass_all_vps_dict = no
+
+# mod_instantiate = ${.module}
+# func_instantiate = instantiate
+
+# mod_detach = ${.module}
+# func_detach = detach
+
+# mod_authorize = ${.module}
+# func_authorize = authorize
+
+# mod_authenticate = ${.module}
+# func_authenticate = authenticate
+
+# mod_preacct = ${.module}
+# func_preacct = preacct
+
+# mod_accounting = ${.module}
+# func_accounting = accounting
+
+# mod_checksimul = ${.module}
+# func_checksimul = checksimul
+
+# mod_pre_proxy = ${.module}
+# func_pre_proxy = pre_proxy
+
+# mod_post_proxy = ${.module}
+# func_post_proxy = post_proxy
+
+# mod_post_auth = ${.module}
+# func_post_auth = post_auth
+
+# mod_recv_coa = ${.module}
+# func_recv_coa = recv_coa
+
+# mod_send_coa = ${.module}
+# func_send_coa = send_coa
+}
diff --git a/raddb/mods-available/python3 b/raddb/mods-available/python3
new file mode 100644
index 0000000..f0e0424
--- /dev/null
+++ b/raddb/mods-available/python3
@@ -0,0 +1,65 @@
+#
+# Make sure the PYTHONPATH environmental variable contains the
+# directory(s) for the modules listed below.
+#
+# Uncomment any func_* which are included in your module. If
+# rlm_python is called for a section which does not have
+# a function defined, it will return NOOP.
+#
+python3 {
+ # Path to the python modules
+ #
+ # Note that due to limitations on Python, this configuration
+ # item is GLOBAL TO THE SERVER. That is, you cannot have two
+ # instances of the python module, each with a different path.
+ #
+# python_path="${modconfdir}/${.:name}:/another_path/to/python_files"
+
+ module = example
+
+ # Pass all VPS lists as a 6-tuple to the callbacks
+ # (request, reply, config, state, proxy_req, proxy_reply)
+# pass_all_vps = no
+
+ # Pass all VPS lists as a dictionary to the callbacks
+ # Keys: "request", "reply", "config", "session-state", "proxy-request",
+ # "proxy-reply"
+ # This option prevales over "pass_all_vps"
+# pass_all_vps_dict = no
+
+# mod_instantiate = ${.module}
+# func_instantiate = instantiate
+
+# mod_detach = ${.module}
+# func_detach = detach
+
+# mod_authorize = ${.module}
+# func_authorize = authorize
+
+# mod_authenticate = ${.module}
+# func_authenticate = authenticate
+
+# mod_preacct = ${.module}
+# func_preacct = preacct
+
+# mod_accounting = ${.module}
+# func_accounting = accounting
+
+# mod_checksimul = ${.module}
+# func_checksimul = checksimul
+
+# mod_pre_proxy = ${.module}
+# func_pre_proxy = pre_proxy
+
+# mod_post_proxy = ${.module}
+# func_post_proxy = post_proxy
+
+# mod_post_auth = ${.module}
+# func_post_auth = post_auth
+
+# mod_recv_coa = ${.module}
+# func_recv_coa = recv_coa
+
+# mod_send_coa = ${.module}
+# func_send_coa = send_coa
+}
diff --git a/raddb/mods-available/radutmp b/raddb/mods-available/radutmp
new file mode 100644
index 0000000..82319c0
--- /dev/null
+++ b/raddb/mods-available/radutmp
@@ -0,0 +1,53 @@
+# -*- text -*-
+#
+# $Id$
+
+# 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.
+ #
+ # You may want instead: %{%{Stripped-User-Name}:-%{User-Name}}
+ 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.
+ permissions = 0600
+
+ caller_id = "yes"
+}
diff --git a/raddb/mods-available/realm b/raddb/mods-available/realm
new file mode 100644
index 0000000..947a42d
--- /dev/null
+++ b/raddb/mods-available/realm
@@ -0,0 +1,80 @@
+# -*- text -*-
+#
+# $Id$
+
+# Realm module, for proxying.
+#
+# You can have multiple instances of the realm module to
+# support multiple realm syntaxes at the same time. The
+# search order is defined by the order that the modules are listed
+# in the authorize and preacct sections.
+#
+# Four config options:
+# format - must be "prefix" or "suffix"
+# The special cases of "DEFAULT"
+# and "NULL" are allowed, too.
+# delimiter - must be a single character
+
+#
+# For dynamic home servers, see doc/configuration/dynamic_home_servers.md,
+# and the script in mods-config/realm/freeradius-naptr-to-home-server.sh
+#
+
+# 'realm/username'
+#
+# Using this entry, IPASS users have their realm set to "IPASS".
+realm IPASS {
+ format = prefix
+ delimiter = "/"
+}
+
+# 'username@realm'
+#
+realm suffix {
+ format = suffix
+ delimiter = "@"
+
+ # The next configuration items are valid ONLY for a trust-router.
+ # For all other realms, they are ignored.
+# trust_router = "localhost"
+# tr_port = 12309
+# rp_realm = "realm.example.com"
+# default_community = "apc.communities.example.com"
+# # if rekey_enabled is enabled, dynamic realms are automatically rekeyed
+# # before they expire to avoid having to recreate them from scrach on
+# # demand (implying lengthy authentications)
+# rekey_enabled = no
+# # if realm_lifetime is > 0, the rekey is scheduled to happen the
+# # specified number of seconds after its creation or rekeying. Otherwise,
+# # the key material expiration timestamp is used
+# realm_lifetime = 0
+}
+
+# 'realm!username'
+#
+realm bangpath {
+ format = prefix
+ delimiter = "!"
+
+# trust_router = "localhost"
+# tr_port = 12309
+# rp_realm = "realm.example.com"
+# default_community = "apc.communities.example.com"
+# rekey_enabled = no
+# realm_lifetime = 0
+}
+
+# 'username%realm'
+#
+realm realmpercent {
+ format = suffix
+ delimiter = "%"
+}
+
+#
+# 'domain\user'
+#
+realm ntdomain {
+ format = prefix
+ delimiter = "\\"
+}
diff --git a/raddb/mods-available/redis b/raddb/mods-available/redis
new file mode 100644
index 0000000..64789f5
--- /dev/null
+++ b/raddb/mods-available/redis
@@ -0,0 +1,99 @@
+# -*- text -*-
+#
+# $Id$
+
+#
+# Configuration file for the "redis" module. This module does nothing
+# Other than provide connections to a redis database, and a %{redis: ...}
+# expansion.
+#
+redis {
+ # Host where the redis server is located.
+ # We recommend using ONLY 127.0.0.1 !
+ server = 127.0.0.1
+
+ # Select the Redis logical database having the specified zero-based numeric index.
+# database = 0
+
+ # The default port.
+ port = 6379
+
+ # The password used to authenticate to the server.
+ # We recommend using a strong password.
+# password = thisisreallysecretandhardtoguess
+
+ # Set connection and query timeout for rlm_redis
+ query_timeout = 5
+
+ #
+ # Information for the connection pool. The configuration items
+ # below are the same for all modules which use the new
+ # connection pool.
+ #
+ pool {
+ # Connections to create during module instantiation.
+ # If the server cannot create specified number of
+ # connections during instantiation it will exit.
+ # Set to 0 to allow the server to start without the
+ # web service being available.
+ start = ${thread[pool].start_servers}
+
+ # Minimum number of connections to keep open
+ min = ${thread[pool].min_spare_servers}
+
+ # Maximum number of connections
+ #
+ # If these connections are all in use and a new one
+ # is requested, the request will NOT get a connection.
+ #
+ # Setting 'max' to LESS than the number of threads means
+ # that some threads may starve, and you will see errors
+ # like 'No connections available and at max connection limit'
+ #
+ # Setting 'max' to MORE than the number of threads means
+ # that there are more connections than necessary.
+ max = ${thread[pool].max_servers}
+
+ # Spare connections to be left idle
+ #
+ # NOTE: Idle connections WILL be closed if "idle_timeout"
+ # is set. This should be less than or equal to "max" above.
+ spare = ${thread[pool].max_spare_servers}
+
+ # Number of uses before the connection is closed
+ #
+ # 0 means "infinite"
+ uses = 0
+
+ # 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 = 30
+
+ # The lifetime (in seconds) of the connection
+ #
+ # NOTE: A setting of 0 means infinite (no limit).
+ lifetime = 86400
+
+ # The pool is checked for free connections every
+ # "cleanup_interval". If there are free connections,
+ # then one of them is closed.
+ cleanup_interval = 300
+
+ # The idle timeout (in seconds). A connection which is
+ # unused for this length of time will be closed.
+ #
+ # NOTE: A setting of 0 means infinite (no timeout).
+ idle_timeout = 600
+
+ # 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/raddb/mods-available/rediswho b/raddb/mods-available/rediswho
new file mode 100644
index 0000000..d303550
--- /dev/null
+++ b/raddb/mods-available/rediswho
@@ -0,0 +1,52 @@
+# -*- text -*-
+#
+# $Id$
+
+#
+# Configuration file for the "rediswho" module.
+#
+# This module tracks the last set of login sessions for a user.
+#
+rediswho {
+ # REDIS instance to use (from mods-available/redis)
+ #
+ # If you have multiple redis instances, such as "redis redis1 {...}",
+ # use the *instance* name here: redis1.
+# redis_module_instance = redis
+
+ # How many sessions to keep track of per user.
+ # If there are more than this number, older sessions are deleted.
+ trim_count = 15
+
+ # Expiry time in seconds. Any sessions which have not received
+ # an update in this time will be automatically expired.
+ expire_time = 86400
+
+ #
+ # Each subsection contains insert / trim / expire queries.
+ # The subsections are named after the contents of the
+ # Acct-Status-Type attribute. See dictionary.rfc2866 for names
+ # of the various Acct-Status-Type values, or look at the output
+ # of debug mode.
+ #
+ # This module supports *any* Acct-Status-Type. Just add a subsection
+ # of the appropriate name, along with insert / trim / expire queries.
+ #
+ Start {
+ insert = "LPUSH %{User-Name} %l,%{Acct-Session-Id},%{NAS-IP-Address},%{Acct-Session-Time},%{Framed-IP-Address},%{%{Acct-Input-Gigawords}:-0},%{%{Acct-Output-Gigawords}:-0},%{%{Acct-Input-Octets}:-0},%{%{Acct-Output-Octets}:-0}"
+ trim = "LTRIM %{User-Name} 0 ${..trim_count}"
+ expire = "EXPIRE %{User-Name} ${..expire_time}"
+ }
+
+ Interim-Update {
+ insert = "LPUSH %{User-Name} %l,%{Acct-Session-Id},%{NAS-IP-Address},%{Acct-Session-Time},%{Framed-IP-Address},%{%{Acct-Input-Gigawords}:-0},%{%{Acct-Output-Gigawords}:-0},%{%{Acct-Input-Octets}:-0},%{%{Acct-Output-Octets}:-0}"
+ trim = "LTRIM %{User-Name} 0 ${..trim_count}"
+ expire = "EXPIRE %{User-Name} ${..expire_time}"
+ }
+
+ Stop {
+ insert = "LPUSH %{User-Name} %l,%{Acct-Session-Id},%{NAS-IP-Address},%{Acct-Session-Time},%{Framed-IP-Address},%{%{Acct-Input-Gigawords}:-0},%{%{Acct-Output-Gigawords}:-0},%{%{Acct-Input-Octets}:-0},%{%{Acct-Output-Octets}:-0}"
+ trim = "LTRIM %{User-Name} 0 ${..trim_count}"
+ expire = "EXPIRE %{User-Name} ${..expire_time}"
+ }
+}
diff --git a/raddb/mods-available/replicate b/raddb/mods-available/replicate
new file mode 100644
index 0000000..3ba88c1
--- /dev/null
+++ b/raddb/mods-available/replicate
@@ -0,0 +1,42 @@
+# Replicate packet(s) to a home server.
+#
+# This module will open a new socket for each packet, and "clone"
+# the incoming packet to the destination realm (i.e. home server).
+# These packets are only sent to UDP home servers. TCP and TLS
+# are not supported.
+#
+# Use it by setting "Replicate-To-Realm = name" in the control list,
+# just like Proxy-To-Realm. The configurations for the two attributes
+# are identical. The realm must exist, the home_server_pool must exist,
+# and the home_server must exist.
+#
+# The only difference is that the "replicate" module sends requests
+# and does not expect a reply. Any reply is ignored.
+#
+# Both Replicate-To-Realm and Proxy-To-Realm can be used at the same time.
+#
+# To use this module, list "replicate" in the "authorize" or
+# "accounting" section. Then, ensure that Replicate-To-Realm is set.
+# The contents of the "packet" attribute list will be sent to the
+# home server. The usual load-balancing, etc. features of the home
+# server will be used.
+#
+# "radmin" can be used to mark home servers alive/dead, in order to
+# enable/disable replication to specific servers.
+#
+# Packets can be replicated to multiple destinations. Just set
+# Replicate-To-Realm multiple times. One packet will be sent for
+# each of the Replicate-To-Realm attribute in the "control" list.
+#
+# If no packets are sent, the module returns "noop". If at least one
+# packet is sent, the module returns "ok". If an error occurs, the
+# module returns "fail"
+#
+# Note that replication does NOT change any of the packet statistics.
+# If you use "radmin" to look at the statistics for a home server,
+# the replicated packets will cause NO counters to increment. This
+# is not a bug, this is how replication works.
+#
+replicate {
+
+}
diff --git a/raddb/mods-available/rest b/raddb/mods-available/rest
new file mode 100644
index 0000000..2c33acb
--- /dev/null
+++ b/raddb/mods-available/rest
@@ -0,0 +1,301 @@
+rest {
+ #
+ # This subsection configures the tls related items
+ # that control how FreeRADIUS connects to a HTTPS
+ # server.
+ #
+ tls {
+ # Certificate Authorities:
+ # "ca_file" (libcurl option CURLOPT_ISSUERCERT).
+ # File containing a single CA, which is the issuer of the server
+ # certificate.
+ # "ca_info_file" (libcurl option CURLOPT_CAINFO).
+ # File containing a bundle of certificates, which allow to handle
+ # certificate chain validation.
+ # "ca_path" (libcurl option CURLOPT_CAPATH).
+ # Directory holding CA certificates to verify the peer with.
+# ca_file = ${certdir}/cacert.pem
+# ca_info_file = ${certdir}/cacert_bundle.pem
+# ca_path = ${certdir}
+
+# certificate_file = /path/to/radius.crt
+# private_key_file = /path/to/radius.key
+# private_key_password = "supersecret"
+# random_file = /dev/urandom
+
+ # Server certificate verification requirements. Can be:
+ # "no" (don't even bother trying)
+ # "yes" (verify the cert was issued by one of the
+ # trusted CAs)
+ #
+ # The default is "yes"
+# check_cert = yes
+
+ # Server certificate CN verification requirements. Can be:
+ # "no" (don't even bother trying)
+ # "yes" (verify the CN in the certificate matches the host
+ # in the URI)
+ #
+ # The default is "yes"
+# check_cert_cn = yes
+ }
+
+ # rlm_rest will open a connection to the server specified in connect_uri
+ # to populate the connection cache, ready for the first request.
+ # The server will not start if the server specified is unreachable.
+ #
+ # If you wish to disable this pre-caching and reachability check,
+ # comment out the configuration item below.
+ connect_uri = "http://127.0.0.1/"
+
+ #
+ # How long before new connection attempts timeout, defaults to 4.0 seconds.
+ #
+# connect_timeout = 4.0
+
+ #
+ # Specify HTTP protocol version to use. one of '1.0', '1.1', '2.0', '2.0+auto',
+ # '2.0+tls' or 'default'. (libcurl option CURLOPT_HTTP_VERSION)
+ #
+# http_negotiation = 1.1
+
+ #
+ # The following config items can be used in each of the sections.
+ # The sections themselves reflect the sections in the server.
+ # For example if you list rest in the authorize section of a virtual server,
+ # the settings from the authorize section here will be used.
+ #
+ # The following config items may be listed in any of the sections:
+ # uri - to send the request to.
+ # method - HTTP method to use, one of 'get', 'post', 'put', 'patch',
+ # 'delete' or any custom HTTP method.
+ # body - The format of the HTTP body sent to the remote server.
+ # May be 'none', 'post' or 'json', defaults to 'none'.
+ # attr_num - If true, the attribute number is supplied for each attribute.
+ # Defaults to false.
+ # raw_value - If true, enumerated attribute values are provided as numeric
+ # values. Defaults to false.
+ # data - Send custom freeform data in the HTTP body. Content-type
+ # may be specified with 'body'. Will be expanded.
+ # Values from expansion will not be escaped, this should be
+ # done using the appropriate xlat method e.g. %{urlencode:<attr>}.
+ # force_to - Force the response to be decoded with this decoder.
+ # May be 'plain' (creates reply:REST-HTTP-Body), 'post'
+ # or 'json'.
+ # tls - TLS settings for HTTPS.
+ # auth - HTTP auth method to use, one of 'none', 'srp', 'basic',
+ # 'digest', 'digest-ie', 'gss-negotiate', 'ntlm',
+ # 'ntlm-winbind', 'any', 'safe'. defaults to 'none'.
+ # username - User to authenticate as, will be expanded.
+ # password - Password to use for authentication, will be expanded.
+ # require_auth - Require HTTP authentication.
+ # timeout - HTTP request timeout in seconds, defaults to 4.0.
+ # chunk - Chunk size to use. If set, HTTP chunked encoding is used to
+ # send data to the REST server. Make sure that this is large
+ # enough to fit your largest attribute value's text
+ #  representation.
+ # A number like 8192 is good.
+ #
+ # Additional HTTP headers may be specified with control:REST-HTTP-Header.
+ # The values of those attributes should be in the format:
+ #
+ # control:REST-HTTP-Header := "<HTTP attribute>: <value>"
+ #
+ # The control:REST-HTTP-Header attributes will be consumed
+ # (i.e. deleted) after each call to the rest module, and each
+ # %{rest:} expansion. This is so that headers from one REST
+ # call do not affect headers from a different REST call.
+ #
+ # Body encodings are the same for requests and responses
+ #
+ # POST - All attributes and values are urlencoded
+ # [outer.][<list>:]<attribute0>=<value0>&[outer.][<list>:]<attributeN>=<valueN>
+ #
+ # JSON - All attributes and values are escaped according to the JSON specification
+ # - attribute Name of the attribute.
+ # - attr_num Number of the attribute. Only available if the configuration item
+ # 'attr_num' is enabled.
+ # - type Type of the attribute (e.g. "integer", "string", "ipaddr", "octets", ...).
+ # - value Attribute value, for enumerated attributes the human readable value is
+ # provided and not the numeric value (Depends on the 'raw_value' config item).
+ # {
+ # "<attribute0>":{
+ # "attr_num":<attr_num0>,
+ # "type":"<type0>",
+ # "value":[<value0>,<value1>,<valueN>]
+ # },
+ # "<attribute1>":{
+ # "attr_num":<attr_num1>,
+ # "type":"<type1>",
+ # "value":[...]
+ # },
+ # "<attributeN>":{
+ # "attr_num":<attr_numN>,
+ # "type":"<typeN>",
+ # "value":[...]
+ # },
+ # }
+ #
+ # The response format adds three optional fields:
+ # - do_xlat If true, any values will be xlat expanded. Defaults to true.
+ # - is_json If true, any nested JSON data will be copied to the attribute
+ # in string form. Defaults to true.
+ # - op Controls how the attribute is inserted into the target list.
+ # Defaults to ':='. To create multiple attributes from multiple
+ # values, this should be set to '+=', otherwise only the last
+ # value will be used, and it will be assigned to a single
+ # attribute.
+ # {
+ # "<attribute0>":{
+ # "is_json":<bool>,
+ # "do_xlat":<bool>,
+ # "op":"<operator>",
+ # "value":[<value0>,<value1>,<valueN>]
+ # },
+ # "<attribute1>":"value",
+ # "<attributeN>":{
+ # "value":[<value0>,<value1>,<valueN>],
+ # "op":"+="
+ # }
+ # }
+
+ #
+ # Module return codes are determined by HTTP response codes. These vary depending on the
+ # section.
+ #
+ # If the body is processed and found to be malformed or unsupported fail will be returned.
+ # If the body is processed and found to contain attribute updated will be returned,
+ # except in the case of a 401 code.
+ #
+
+ # Authorize/Authenticate
+ #
+ # Code Meaning Process body Module code
+ # 404 not found no notfound
+ # 410 gone no notfound
+ # 403 forbidden no userlock
+ # 401 unauthorized yes reject
+ # 204 no content no ok
+ # 2xx successful yes ok/updated
+ # 5xx server error no fail
+ # xxx - no invalid
+ #
+ # The status code is held in %{reply:REST-HTTP-Status-Code}.
+ #
+ authorize {
+ uri = "${..connect_uri}/user/%{User-Name}/mac/%{Called-Station-ID}?action=authorize"
+ method = 'get'
+ tls = ${..tls}
+ }
+ authenticate {
+ uri = "${..connect_uri}/user/%{User-Name}/mac/%{Called-Station-ID}?action=authenticate"
+ method = 'get'
+ tls = ${..tls}
+ }
+
+ # Preacct/Accounting/Post-auth/Pre-Proxy/Post-Proxy
+ #
+ # Code Meaning Process body Module code
+ # 204 no content no ok
+ # 2xx successful yes ok/updated
+ # 5xx server error no fail
+ # xxx - no invalid
+ preacct {
+ uri = "${..connect_uri}/user/%{User-Name}/sessions/%{Acct-Unique-Session-ID}?action=preacct"
+ method = 'post'
+ tls = ${..tls}
+ }
+ accounting {
+ uri = "${..connect_uri}/user/%{User-Name}/sessions/%{Acct-Unique-Session-ID}?action=accounting"
+ method = 'post'
+ tls = ${..tls}
+ }
+ post-auth {
+ uri = "${..connect_uri}/user/%{User-Name}/mac/%{Called-Station-ID}?action=post-auth"
+ method = 'post'
+ tls = ${..tls}
+ }
+ pre-proxy {
+ uri = "${..connect_uri}/user/%{User-Name}/mac/%{Called-Station-ID}?action=pre-proxy"
+ method = 'post'
+ tls = ${..tls}
+ }
+ post-proxy {
+ uri = "${..connect_uri}/user/%{User-Name}/mac/%{Called-Station-ID}?action=post-proxy"
+ method = 'post'
+ tls = ${..tls}
+ }
+
+ # Options for calling rest xlats
+ # uri and method will be derived from the string provided to the xlat
+ xlat {
+ #
+ # The whole string passed to a REST xlat is URI encoded.
+ # With body_uri_encode = yes, any body data will remain encoded.
+ # With body_uri_encode = no, the body data will be decoded and sent as provided.
+ #
+ body_uri_encode = yes
+ tls = ${..tls}
+ }
+
+ #
+ # The connection pool is used to pool outgoing connections.
+ #
+ pool {
+ # Connections to create during module instantiation.
+ # If the server cannot create specified number of
+ # connections during instantiation it will exit.
+ # Set to 0 to allow the server to start without the
+ # web service being available.
+ start = ${thread[pool].start_servers}
+
+ # Minimum number of connections to keep open
+ min = ${thread[pool].min_spare_servers}
+
+ # Maximum number of connections
+ #
+ # If these connections are all in use and a new one
+ # is requested, the request will NOT get a connection.
+ #
+ # Setting 'max' to LESS than the number of threads means
+ # that some threads may starve, and you will see errors
+ # like 'No connections available and at max connection limit'
+ #
+ # Setting 'max' to MORE than the number of threads means
+ # that there are more connections than necessary.
+ max = ${thread[pool].max_servers}
+
+ # Spare connections to be left idle
+ #
+ # NOTE: Idle connections WILL be closed if "idle_timeout"
+ # is set. This should be less than or equal to "max" above.
+ spare = ${thread[pool].max_spare_servers}
+
+ # Number of uses before the connection is closed
+ #
+ # 0 means "infinite"
+ uses = 0
+
+ # 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 = 30
+
+ # 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
+
+ # 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/raddb/mods-available/smbpasswd b/raddb/mods-available/smbpasswd
new file mode 100644
index 0000000..d5ad2a0
--- /dev/null
+++ b/raddb/mods-available/smbpasswd
@@ -0,0 +1,16 @@
+# -*- text -*-
+#
+# $Id$
+
+# An example configuration for using /etc/smbpasswd.
+#
+# See the "passwd" file for documentation on the configuration items
+# for this module.
+#
+passwd smbpasswd {
+ filename = /etc/smbpasswd
+ format = "*User-Name::LM-Password:NT-Password:SMB-Account-CTRL-TEXT::"
+ hash_size = 100
+ ignore_nislike = no
+ allow_multiple_keys = no
+}
diff --git a/raddb/mods-available/smsotp b/raddb/mods-available/smsotp
new file mode 100644
index 0000000..c594a9a
--- /dev/null
+++ b/raddb/mods-available/smsotp
@@ -0,0 +1,94 @@
+# -*- text -*-
+#
+# $Id$
+
+# SMS One-Time Password system
+#
+# This module extends FreeRADIUS with a socket interface to create and
+# validate One-Time-Passwords. The program for that creates the socket
+# and interacts with this module is not included here.
+#
+# The module does not check the User-Password, this should be done with
+# the "pap" module. See the example below.
+#
+# The module must be used in the "authorize" section to set
+# Auth-Type properly. The first time through, the module is called
+# in the "authenticate" section to authenticate the user password, and
+# to send the challenge. The second time through, it authenticates
+# the response to the challenge. e.g.:
+#
+# authorize {
+# ...
+# smsotp
+# ...
+# }
+#
+# authenticate {
+# ...
+# Auth-Type smsotp {
+# pap
+# smsotp
+# }
+#
+# Auth-Type smsotp-reply {
+# smsotp
+# }
+# ...
+# }
+#
+smsotp {
+ # The location of the socket.
+ socket = "/var/run/smsotp_socket"
+
+ # Defines the challenge message that will be send to the
+ # NAS. Default is "Enter Mobile PIN" }
+ challenge_message = "Enter Mobile PIN:"
+
+ # Defines the Auth-Type section that is run for the response to
+ # the challenge. Default is "smsotp-reply".
+ challenge_type = "smsotp-reply"
+
+ # Control how many sockets are used to talk to the SMSOTPd
+ #
+ 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.
+ max = 10
+
+ # 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
+
+ # 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/raddb/mods-available/soh b/raddb/mods-available/soh
new file mode 100644
index 0000000..d125ce4
--- /dev/null
+++ b/raddb/mods-available/soh
@@ -0,0 +1,4 @@
+# SoH module
+soh {
+ dhcp = yes
+}
diff --git a/raddb/mods-available/sometimes b/raddb/mods-available/sometimes
new file mode 100644
index 0000000..3a96622
--- /dev/null
+++ b/raddb/mods-available/sometimes
@@ -0,0 +1,12 @@
+# -*- text -*-
+#
+# $Id$
+
+#
+# The "sometimes" module is here for debugging purposes. Each instance
+# randomly returns the configured result, or "noop".
+#
+# It is based on the "always" module.
+sometimes {
+ rcode = fail
+}
diff --git a/raddb/mods-available/sql b/raddb/mods-available/sql
new file mode 100644
index 0000000..0f435ad
--- /dev/null
+++ b/raddb/mods-available/sql
@@ -0,0 +1,376 @@
+# -*- text -*-
+##
+## mods-available/sql -- SQL modules
+##
+## $Id$
+
+######################################################################
+#
+# Configuration for the SQL module
+#
+# The database schemas and queries are located in subdirectories:
+#
+# sql/<DB>/main/schema.sql Schema
+# sql/<DB>/main/queries.conf Authorisation and Accounting queries
+#
+# Where "DB" is mysql, mssql, oracle, or postgresql.
+#
+# The name used to query SQL is sql_user_name, which is set in the file
+#
+# raddb/mods-config/sql/main/${dialect}/queries.conf
+#
+# If you are using realms, that configuration should be changed to use
+# the Stripped-User-Name attribute. See the comments around sql_user_name
+# for more information.
+#
+
+sql {
+ #
+ # The dialect of SQL being used.
+ #
+ # Allowed dialects are:
+ #
+ # mssql
+ # mysql
+ # oracle
+ # postgresql
+ # sqlite
+ # mongo
+ #
+ dialect = "sqlite"
+
+ #
+ # The driver module used to execute the queries. Since we
+ # don't know which SQL drivers are being used, the default is
+ # "rlm_sql_null", which just logs the queries to disk via the
+ # "logfile" directive, below.
+ #
+ # In order to talk to a real database, delete the next line,
+ # and uncomment the one after it.
+ #
+ # If the dialect is "mssql", then the driver should be set to
+ # one of the following values, depending on your system:
+ #
+ # rlm_sql_db2
+ # rlm_sql_firebird
+ # rlm_sql_freetds
+ # rlm_sql_iodbc
+ # rlm_sql_unixodbc
+ #
+ driver = "rlm_sql_null"
+# driver = "rlm_sql_${dialect}"
+
+ #
+ # Driver-specific subsections. They will only be loaded and
+ # used if "driver" is something other than "rlm_sql_null".
+ # When a real driver is used, the relevant driver
+ # configuration section is loaded, and all other driver
+ # configuration sections are ignored.
+ #
+ sqlite {
+ # Path to the sqlite database
+ filename = "/tmp/freeradius.db"
+
+ # How long to wait for write locks on the database to be
+ # released (in ms) before giving up.
+ busy_timeout = 200
+
+ # 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 bootstrap file will be executed.
+ bootstrap = "${modconfdir}/${..:name}/main/sqlite/schema.sql"
+ }
+
+ mysql {
+ # If any of the files below are set, TLS encryption is enabled
+ tls {
+ ca_file = "/etc/ssl/certs/my_ca.crt"
+ ca_path = "/etc/ssl/certs/"
+ certificate_file = "/etc/ssl/certs/private/client.crt"
+ private_key_file = "/etc/ssl/certs/private/client.key"
+ cipher = "DHE-RSA-AES256-SHA:AES128-SHA"
+
+ tls_required = yes
+ tls_check_cert = no
+ tls_check_cert_cn = no
+ }
+
+ # If yes, (or auto and libmysqlclient reports warnings are
+ # available), will retrieve and log additional warnings from
+ # the server if an error has occured. Defaults to 'auto'
+ warnings = auto
+ }
+
+ postgresql {
+
+ # unlike MySQL, which has a tls{} connection configuration, postgresql
+ # uses its connection parameters - see the radius_db option below in
+ # this file
+
+ # Send application_name to the postgres server
+ # Only supported in PG 9.0 and greater. Defaults to no.
+ send_application_name = yes
+
+ #
+ # The default application name is "FreeRADIUS - .." with the current version.
+ # The application name can be customized here to any non-zero value.
+ #
+# application_name = ""
+ }
+
+ #
+ # Configuration for Mongo.
+ #
+ # Note that the Mongo driver is experimental. The FreeRADIUS developers
+ # are unable to help with the syntax of the Mongo queries. Please see
+ # the Mongo documentation for that syntax.
+ #
+ # The Mongo driver supports only the following methods:
+ #
+ # aggregate
+ # findAndModify
+ # findOne
+ # insert
+ #
+ # For examples, see the query files:
+ #
+ # raddb/mods-config/sql/main/mongo/queries.conf
+ # raddb/mods-config/sql/main/ippool/queries.conf
+ #
+ # In order to use findAndModify with an aggretation pipleline, make
+ # sure that you are running MongoDB version 4.2 or greater. FreeRADIUS
+ # assumes that the paramaters passed to the methods are supported by the
+ # version of MongoDB which it is connected to.
+ #
+ mongo {
+ #
+ # The application name to use.
+ #
+ appname = "freeradius"
+
+ #
+ # The TLS parameters here map directly to the Mongo TLS configuration
+ #
+ tls {
+ certificate_file = /path/to/file
+ certificate_password = "password"
+ ca_file = /path/to/file
+ ca_dir = /path/to/directory
+ crl_file = /path/to/file
+ weak_cert_validation = false
+ allow_invalid_hostname = false
+ }
+ }
+
+ # Connection info:
+ #
+# server = "localhost"
+# port = 3306
+# login = "radius"
+# password = "radpass"
+
+ # Connection info for Mongo
+ # Authentication Without SSL
+ # server = "mongodb://USER:PASSWORD@192.16.0.2:PORT/DATABASE?authSource=admin&ssl=false"
+
+ # Authentication With SSL
+ # server = "mongodb://USER:PASSWORD@192.16.0.2:PORT/DATABASE?authSource=admin&ssl=true"
+
+ # Authentication with Certificate
+ # Use this command for retrieve Derived username:
+ # openssl x509 -in mycert.pem -inform PEM -subject -nameopt RFC2253
+ # server = mongodb://<DERIVED USERNAME>@192.168.0.2:PORT/DATABASE?authSource=$external&ssl=true&authMechanism=MONGODB-X509
+
+ # Database table configuration for everything except Oracle
+ radius_db = "radius"
+
+ # If you are using Oracle then use this instead
+# radius_db = "(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521))(CONNECT_DATA=(SID=your_sid)))"
+
+ # If you're using postgresql this can also be used instead of the connection info parameters
+# radius_db = "dbname=radius host=localhost user=radius password=raddpass"
+
+ # Postgreql doesn't take tls{} options in its module config like mysql does - if you want to
+ # use SSL connections then use this form of connection info parameter
+# radius_db = "host=localhost port=5432 dbname=radius user=radius password=raddpass sslmode=verify-full sslcert=/etc/ssl/client.crt sslkey=/etc/ssl/client.key sslrootcert=/etc/ssl/ca.crt"
+
+ # If you want both stop and start records logged to the
+ # same SQL table, leave this as is. If you want them in
+ # different tables, put the start table in acct_table1
+ # and stop table in acct_table2
+ acct_table1 = "radacct"
+ acct_table2 = "radacct"
+
+ # Allow for storing data after authentication
+ postauth_table = "radpostauth"
+
+ # Tables containing 'check' items
+ authcheck_table = "radcheck"
+ groupcheck_table = "radgroupcheck"
+
+ # Tables containing 'reply' items
+ authreply_table = "radreply"
+ groupreply_table = "radgroupreply"
+
+ # Table to keep group info
+ usergroup_table = "radusergroup"
+
+ # If set to 'yes' (default) we read the group tables unless Fall-Through = no in the reply table.
+ # If set to 'no' we do not read the group tables unless Fall-Through = yes in the reply table.
+# read_groups = yes
+
+ # If set to 'yes' (default) we read profiles unless Fall-Through = no in the groupreply table.
+ # If set to 'no' we do not read profiles unless Fall-Through = yes in the groupreply table.
+# read_profiles = yes
+
+ # Remove stale session if checkrad does not see a double login
+ delete_stale_sessions = yes
+
+ # Write SQL queries to a logfile. This is potentially useful for tracing
+ # issues with authorization queries. See also "logfile" directives in
+ # mods-config/sql/main/*/queries.conf. You can enable per-section logging
+ # by enabling "logfile" there, or global logging by enabling "logfile" here.
+ #
+ # Per-section logging can be disabled by setting "logfile = ''"
+# logfile = ${logdir}/sqllog.sql
+
+ # Set the maximum query duration and connection timeout
+ # for rlm_sql_mysql.
+# query_timeout = 5
+
+ # As of v3, the "pool" section has replaced the
+ # following v2 configuration items:
+ #
+ # num_sql_socks
+ # connect_failure_retry_delay
+ # lifetime
+ # max_queries
+
+ #
+ # The connection pool is used to pool outgoing connections.
+ #
+ # When the server is not threaded, the connection pool
+ # limits are ignored, and only one connection is used.
+ #
+ # If you want to have multiple SQL modules re-use the same
+ # connection pool, use "pool = name" instead of a "pool"
+ # section. e.g.
+ #
+ # sql sql1 {
+ # ...
+ # pool {
+ # ...
+ # }
+ # }
+ #
+ # # sql2 will use the connection pool from sql1
+ # sql sql2 {
+ # ...
+ # pool = sql1
+ # }
+ #
+ pool {
+ # Connections to create during module instantiation.
+ # If the server cannot create specified number of
+ # connections during instantiation it will exit.
+ # Set to 0 to allow the server to start without the
+ # database being available.
+ start = ${thread[pool].start_servers}
+
+ # Minimum number of connections to keep open
+ min = ${thread[pool].min_spare_servers}
+
+ # Maximum number of connections
+ #
+ # If these connections are all in use and a new one
+ # is requested, the request will NOT get a connection.
+ #
+ # Setting 'max' to LESS than the number of threads means
+ # that some threads may starve, and you will see errors
+ # like 'No connections available and at max connection limit'
+ #
+ # Setting 'max' to MORE than the number of threads means
+ # that there are more connections than necessary.
+ max = ${thread[pool].max_servers}
+
+ # Spare connections to be left idle
+ #
+ # NOTE: Idle connections WILL be closed if "idle_timeout"
+ # is set. This should be less than or equal to "max" above.
+ spare = ${thread[pool].max_spare_servers}
+
+ # Number of uses before the connection is closed
+ #
+ # 0 means "infinite"
+ uses = 0
+
+ # 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 = 30
+
+ # 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
+
+ # 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.
+
+ # Maximum number of times an operation can be retried
+ # if it returns an error which indicates the connection
+ # needs to be restarted. This includes timeouts.
+ max_retries = 5
+ }
+
+ # Set to 'yes' to read radius clients from the database ('nas' table)
+ # Clients will ONLY be read on server startup.
+ #
+ # A client can be link to a virtual server via the SQL
+ # module. This link is done via the following process:
+ #
+ # If there is no listener in a virtual server, SQL clients
+ # are added to the global list for that virtual server.
+ #
+ # If there is a listener, and the first listener does not
+ # have a "clients=..." configuration item, SQL clients are
+ # added to the global list.
+ #
+ # If there is a listener, and the first one does have a
+ # "clients=..." configuration item, SQL clients are added to
+ # that list. The client { ...} ` configured in that list are
+ # also added for that listener.
+ #
+ # The only issue is if you have multiple listeners in a
+ # virtual server, each with a different client list, then
+ # the SQL clients are added only to the first listener.
+ #
+# read_clients = yes
+
+ # Table to keep radius client info
+ client_table = "nas"
+
+ #
+ # The group attribute specific to this instance of rlm_sql
+ #
+
+ # This entry should be used for additional instances (sql foo {})
+ # of the SQL module.
+# group_attribute = "${.:instance}-SQL-Group"
+
+ # This entry should be used for the default instance (sql {})
+ # of the SQL module.
+ group_attribute = "SQL-Group"
+
+ # Read database-specific queries
+ $INCLUDE ${modconfdir}/${.:name}/main/${dialect}/queries.conf
+}
diff --git a/raddb/mods-available/sql_map b/raddb/mods-available/sql_map
new file mode 100644
index 0000000..93b2636
--- /dev/null
+++ b/raddb/mods-available/sql_map
@@ -0,0 +1,49 @@
+# Configuration for the SQL based Map (rlm_sql_map)
+sql_map {
+ # SQL instance to use (from mods-available/sql)
+ #
+ # If you have multiple sql instances, such as "sql sql1 {...}",
+ # use the *instance* name here: sql1.
+ sql_module_instance = "sql"
+
+ # This is duplicative of info available in the SQL module, but
+ # we have to list it here as we do not yet support nested
+ # reference expansions.
+ dialect = "mysql"
+
+ # Name of the check item attribute to be used as a key in the SQL queries
+ query = "SELECT ... FROM ... "
+
+ #
+ # Mapping of SQL columns 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> <sql column number>
+ #
+ # Where:
+ # <radius attr>: Is the destination RADIUS attribute
+ # with any valid list and request qualifiers.
+ # <op>: Is any assignment attribute (=, :=, +=, -=).
+ # <column num>: The column number (not name), starting from 0
+ #
+ # Request and list qualifiers may also be placed after the 'update'
+ # section name to set defaults destination requests/lists
+ # for unqualified RADIUS attributes.
+ #
+ update {
+ control:Password-With-Header += 0
+# control:NT-Password := 1
+# reply:Reply-Message := 2
+# reply:Tunnel-Type := 3
+# reply:Tunnel-Medium-Type := 4
+# reply:Tunnel-Private-Group-ID := 5
+ }
+
+ # If the 'query' results in multiple rows, it creates the <radius attr>[*] array entry.
+# multiple_rows = yes
+}
diff --git a/raddb/mods-available/sqlcounter b/raddb/mods-available/sqlcounter
new file mode 100644
index 0000000..a2b206e
--- /dev/null
+++ b/raddb/mods-available/sqlcounter
@@ -0,0 +1,122 @@
+# Rather than maintaining separate (GDBM) databases of
+# accounting info for each counter, this module uses the data
+# stored in the raddacct table by the sql modules. This
+# module NEVER does any database INSERTs or UPDATEs. It is
+# totally dependent on the SQL module to process Accounting
+# packets.
+#
+# The sql-module-instance' parameter holds the instance of the sql
+# module to use when querying the SQL database. Normally it
+# is just "sql". If you define more and one SQL module
+# instance (usually for failover situations), you can
+# specify which module has access to the Accounting Data
+# (radacct table).
+#
+# The 'reset' parameter defines when the counters are all
+# reset to zero. It can be hourly, daily, weekly, monthly or
+# never. 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 'reset_day' parameter defines which day of the month the
+# 'monthly' counter should be reset; valid values are 1 to 28.
+#
+# The 'key' parameter specifies the unique identifier for the
+# counter records (usually 'User-Name').
+#
+# The 'query' parameter specifies the SQL query used to get
+# the current Counter value from the database. There are four
+# parameters that can be used in the query:
+#
+# %%b unix time value of beginning of reset period.
+# %%e unix time value of end of reset period.
+# %%k value of 'key' parameter.
+# %%r day of month the counter should be reset.
+#
+# The 'check_name' parameter is the name of the 'check'
+# attribute to use to access the counter in the 'users' file
+# or SQL radcheck or radgroupcheck tables.
+#
+# DEFAULT Max-Daily-Session > 3600, Auth-Type = Reject
+# Reply-Message = "You've used up more than one hour today"
+#
+# The "dailycounter" (or any other sqlcounter module) should be added
+# to "post-auth" section. It will then update the Session-Timeout
+# attribute in the reply. If there is no Session-Timeout attribute,
+# the module will add one. If there is an attribute, the sqlcounter
+# module will make sure that the value is no higher than the limit.
+#
+sqlcounter dailycounter {
+ sql_module_instance = sql
+ dialect = ${modules.sql.dialect}
+
+ counter_name = Daily-Session-Time
+ check_name = Max-Daily-Session
+ reply_name = Session-Timeout
+
+ key = User-Name
+ reset = daily
+
+ $INCLUDE ${modconfdir}/sql/counter/${dialect}/${.:instance}.conf
+}
+
+sqlcounter weeklycounter {
+ sql_module_instance = sql
+ dialect = ${modules.sql.dialect}
+
+ counter_name = Weekly-Session-Time
+ check_name = Max-Weekly-Session
+ reply_name = Session-Timeout
+
+ key = User-Name
+ reset = weekly
+
+ $INCLUDE ${modconfdir}/sql/counter/${dialect}/${.:instance}.conf
+}
+
+sqlcounter monthlycounter {
+ sql_module_instance = sql
+ dialect = ${modules.sql.dialect}
+
+ counter_name = Monthly-Session-Time
+ check_name = Max-Monthly-Session
+ reply_name = Session-Timeout
+ key = User-Name
+ reset = monthly
+ reset_day = 1
+
+ $INCLUDE ${modconfdir}/sql/counter/${dialect}/${.:instance}.conf
+}
+
+sqlcounter noresetcounter {
+ sql_module_instance = sql
+ dialect = ${modules.sql.dialect}
+
+ counter_name = Max-All-Session-Time
+ check_name = Max-All-Session
+ key = User-Name
+ reset = never
+
+ $INCLUDE ${modconfdir}/sql/counter/${dialect}/${.:instance}.conf
+}
+
+#
+# Set an account to expire T seconds after first login.
+# Requires the Expire-After attribute to be set, in seconds.
+# You may need to edit raddb/dictionary to add the Expire-After
+# attribute.
+sqlcounter expire_on_login {
+ sql_module_instance = sql
+ dialect = ${modules.sql.dialect}
+
+ counter_name = Expire-After-Initial-Login
+ check_name = Expire-After
+ key = User-Name
+ reset = never
+
+ $INCLUDE ${modconfdir}/sql/counter/${dialect}/${.:instance}.conf
+}
diff --git a/raddb/mods-available/sqlippool b/raddb/mods-available/sqlippool
new file mode 100644
index 0000000..f17a989
--- /dev/null
+++ b/raddb/mods-available/sqlippool
@@ -0,0 +1,109 @@
+# Configuration for the SQL based IP Pool module (rlm_sqlippool)
+#
+# The database schemas are available at:
+#
+# raddb/mods-config/sql/ippool/<DB>/schema.sql
+#
+# $Id$
+
+sqlippool {
+ # SQL instance to use (from mods-available/sql)
+ #
+ # If you have multiple sql instances, such as "sql sql1 {...}",
+ # use the *instance* name here: sql1.
+ sql_module_instance = "sql"
+
+ # This is duplicative of info available in the SQL module, but
+ # we have to list it here as we do not yet support nested
+ # reference expansions.
+ dialect = "mysql"
+
+ # Name of the check item attribute to be used as a key in the SQL queries
+ pool_name = "Pool-Name"
+
+ # SQL table to use for ippool range and lease info
+ ippool_table = "radippool"
+
+ # IP lease duration. (Leases expire even if Acct Stop packet is lost)
+ #
+ # Note that you SHOULD also set Session-Timeout to this value!
+ # That way the NAS will automatically kick the user offline when the
+ # lease expires.
+ #
+ lease_duration = 3600
+
+ #
+ # Timeout between each consecutive 'allocate_clear' queries (default: 1s)
+ # This will avoid having too many deadlock issues, especially on MySQL backend.
+ #
+ allocate_clear_timeout = 1
+
+ #
+ # The attribute to use for IP address assignment. The
+ # default is Framed-IP-Address. You can change this to any
+ # attribute which is IPv4 or IPv6.
+ #
+ # e.g. Framed-IPv6-Prefix, or Delegated-IPv6-Prefix.
+ #
+ # All of the default queries use this attribute_name. So you
+ # can do IPv6 address assignment simply by putting IPv6
+ # addresses into the pool, and changing the following line to
+ # "Framed-IPv6-Prefix"
+ #
+ # Note that you MUST use separate pools for each attribute. i.e. one pool
+ # for Framed-IP-Address, a different one for Framed-IPv6-prefix, etc.
+ #
+ # This means configuring separate "sqlippool" instances, and different
+ # "ippool_table" in SQL. Then, populate the pool with addresses and
+ # it will all just work.
+ #
+ attribute_name = Framed-IP-Address
+
+ #
+ # Assign the IP address, even if the above attribute already exists
+ # in the reply.
+ #
+# allow_duplicates = no
+
+ # The attribute in which an IP address hint may be supplied
+ req_attribute_name = Framed-IP-Address
+
+ # Attribute which should be considered unique per NAS
+ #
+ # Using NAS-Port gives behaviour similar to rlm_ippool. (And ACS)
+ # Using Calling-Station-Id works for NAS that send fixed NAS-Port
+ # ONLY change this if you know what you are doing!
+ pool_key = "%{NAS-Port}"
+ # pool_key = "%{Calling-Station-Id}"
+
+ ################################################################
+ #
+ # WARNING: MySQL (MyISAM) has certain limitations that means it can
+ # hand out the same IP address to 2 different users.
+ #
+ # We suggest using an SQL DB with proper transaction
+ # support, such as PostgreSQL, or using MySQL
+ # with InnoDB.
+ #
+ ################################################################
+
+ # These messages are added to the "control" items, as
+ # Module-Success-Message. They are not logged anywhere else,
+ # unlike previous versions. If you want to have them logged
+ # to a file, see the "linelog" module, and create an entry
+ # which writes Module-Success-Message message.
+ #
+ messages {
+ exists = "Existing IP: %{reply:${..attribute_name}} (did %{Called-Station-Id} cli %{Calling-Station-Id} port %{NAS-Port} user %{User-Name})"
+
+ success = "Allocated IP: %{reply:${..attribute_name}} from %{control:${..pool_name}} (did %{Called-Station-Id} cli %{Calling-Station-Id} port %{NAS-Port} user %{User-Name})"
+
+ clear = "Released IP %{request:${..attribute_name}} (did %{Called-Station-Id} cli %{Calling-Station-Id} user %{User-Name})"
+
+ failed = "IP Allocation FAILED from %{control:${..pool_name}} (did %{Called-Station-Id} cli %{Calling-Station-Id} port %{NAS-Port} user %{User-Name})"
+
+ nopool = "No ${..pool_name} defined (did %{Called-Station-Id} cli %{Calling-Station-Id} port %{NAS-Port} user %{User-Name})"
+ }
+
+ $INCLUDE ${modconfdir}/sql/ippool/${dialect}/queries.conf
+}
diff --git a/raddb/mods-available/sradutmp b/raddb/mods-available/sradutmp
new file mode 100644
index 0000000..3a2a0e5
--- /dev/null
+++ b/raddb/mods-available/sradutmp
@@ -0,0 +1,16 @@
+# -*- text -*-
+#
+# $Id$
+
+# "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
+ permissions = 0644
+ caller_id = "no"
+}
diff --git a/raddb/mods-available/totp b/raddb/mods-available/totp
new file mode 100644
index 0000000..695365f
--- /dev/null
+++ b/raddb/mods-available/totp
@@ -0,0 +1,40 @@
+# -*- text -*-
+#
+# $Id$
+
+#
+# Time-based One-Time Passwords (TOTP)
+#
+# Defined in RFC 6238, and used in Google Authenticator.
+#
+# This module can only be used in the "authenticate" section.
+#
+# The Base32-encoded secret should be placed into:
+#
+# &control:TOTP-Secret
+#
+# The TOTP password entered by the user should be placed into:
+#
+# &request:TOTP-Password
+#
+# The module will return "ok" if the passwords match, and "fail"
+# if the passwords do not match.
+#
+# Note that this module will NOT interact with Google. The module is
+# intended to be used where the local administrator knows the TOTP
+# secret key, and user has an authenticator app on their phone.
+#
+# Note also that while you can use the Google "chart" APIs to
+# generate a QR code, doing this will give the secret to Google!
+#
+# Administrators should instead install a tool such as "qrcode"
+#
+# https://linux.die.net/man/1/qrencode
+#
+# and then run that locally to get an image.
+#
+#
+# The module takes no configuration items.
+#
+totp {
+}
diff --git a/raddb/mods-available/unbound b/raddb/mods-available/unbound
new file mode 100644
index 0000000..43fbce5
--- /dev/null
+++ b/raddb/mods-available/unbound
@@ -0,0 +1,13 @@
+unbound dns {
+ # Configuration for libunbound
+ # filename = "${raddbdir}/mods-config/unbound/default.conf"
+
+ # File to load resolver details from.
+ # Without this set unbound will query root servers
+ # resolvconf = "/etc/resolv.conf"
+
+ # Hosts entries to load
+ # hosts = "/etc/hosts"
+
+ # timeout = 3000
+}
diff --git a/raddb/mods-available/unix b/raddb/mods-available/unix
new file mode 100644
index 0000000..5165139
--- /dev/null
+++ b/raddb/mods-available/unix
@@ -0,0 +1,25 @@
+# -*- text -*-
+#
+# $Id$
+
+# Unix /etc/passwd style authentication
+#
+# This module calls the system functions to get the "known good"
+# password. This password is usually in the "crypt" form, and is
+# incompatible with CHAP, MS-CHAP, PEAP, etc.
+#
+# If passwords are in /etc/shadow, you will need to set the "group"
+# configuration in radiusd.conf. Look for "shadow", and follow the
+# instructions there.
+#
+unix {
+ #
+ # The location of the "wtmp" file.
+ # The only use for 'radlast'. If you don't use
+ # 'radlast', then you can comment out this item.
+ #
+ # Note that the radwtmp file may get large! You should
+ # rotate it (cp /dev/null radwtmp), or just not use it.
+ #
+ radwtmp = ${logdir}/radwtmp
+}
diff --git a/raddb/mods-available/unpack b/raddb/mods-available/unpack
new file mode 100644
index 0000000..89ef169
--- /dev/null
+++ b/raddb/mods-available/unpack
@@ -0,0 +1,105 @@
+# -*- text -*-
+#
+# $Id$
+
+#
+# This module is useful only for 'xlat'.
+# To use it, add it to the raddb/mods-enabled/ directory.
+#
+# Two xlat functions are provided by this module:
+# - unpack
+# - substring
+#
+# Both are for use on the right-hand side of a variable assignment.
+#
+# unpack
+# ======
+#
+# ... = "%{unpack:data 1 integer}"
+#
+# The arguments are three fields:
+#
+# data
+# Either &Attribute-Name
+# the name of the attribute to unpack.
+# MUST be a "string" or "octets" type.
+#
+# or 0xabcdef
+# e.g. hex data.
+#
+# 1
+# The offset into the string from which
+# it starts unpacking. The offset starts
+# at zero, for the first attribute.
+#
+# integer
+# the data type to unpack at that offset.
+# e.g. integer, ipaddr, byte, short, etc.
+#
+# e.g. if we have Class = 0x0000000102030405, then
+#
+# %{unpack:&Class 4 short}
+#
+# will unpack octets 4 and 5 as a "short", which has
+# value 0x0304.
+#
+# This module is used when vendors put multiple fields
+# into one attribute of type "octets".
+#
+# The module can also be used to unpack substrings, by specifing a
+# data type of "string(len)" or "octets(len)". Where "len" is an
+# actual number. For example:
+#
+# %{unpack:&User-Name 1 string(2)}
+#
+# When given a User-Name of "hello", it will start taking the
+# substring at offset 1 (i.e. "e"), and it will take two characters
+# from that offset, i.e. "el".
+#
+# As a special case, you can unpack an entire string by specifying
+# the offset, and nothing for the length:
+#
+# %{unpack:&User-Name 1 string()}
+#
+# When "octets(len)" is used, the output is printed as hex. e.g. for
+# the above example with Class:
+#
+# %{unpack:&Class 4 octets(4)}
+#
+# Will return the hex string "02030405"
+#
+#
+# substring
+# =========
+#
+# substring will return a substring of a string or attribute using
+# the syntax
+#
+# %{substring:data start len}
+#
+# data
+# Either an attribute name or string data. String data
+# can have leading or trailing spaces. Only a single
+# space before "start" is taken as the separator.
+#
+# start
+# the zero based offset for the start of the substring.
+# A negative value will count in from the end of the
+# string.
+#
+# len
+# the number of characters to return. A Negative value
+# will remove that number of characters from the end.
+# If len is more than the available number of characters
+# then only the available number will be returned.
+#
+# Examples:
+#
+# "%{substring:foobar 2 3}" == "oba"
+# "%{substring:foobar -3 2}" == "ba"
+# "%{substring:foobar 1 -1}" == "ooba"
+# if User-Name is "foobar" "%{substring:&User-Name 1 -2}" == "oob"
+#
+
+unpack {
+}
diff --git a/raddb/mods-available/utf8 b/raddb/mods-available/utf8
new file mode 100644
index 0000000..00812fa
--- /dev/null
+++ b/raddb/mods-available/utf8
@@ -0,0 +1,14 @@
+#
+# Enforces UTF-8 on strings coming in from the NAS.
+#
+# An attribute of type "string" containing UTF-8 makes
+# the module return NOOP.
+#
+# An attribute of type "string" containing non-UTF-8 data
+# makes the module return FAIL.
+#
+# This module takes no configuration.
+#
+utf8 {
+
+}
diff --git a/raddb/mods-available/wimax b/raddb/mods-available/wimax
new file mode 100644
index 0000000..3add59e
--- /dev/null
+++ b/raddb/mods-available/wimax
@@ -0,0 +1,165 @@
+#
+# The WiMAX module currently takes no configuration.
+#
+# ## Instructions for v1 and v2.0 WiMAX
+#
+# It should be listed in the "authorize" and "preacct" sections.
+# This enables the module to fix the horrible binary version
+# of Calling-Station-Id to the normal format, as specified in
+# RFC 3580, Section 3.21.
+#
+# In order to calculate the various WiMAX keys, the module should
+# be listed in the "post-auth" section. If EAP authentication
+# has been used, AND the EAP method derives MSK and EMSK, then
+# the various WiMAX keys can be calculated.
+#
+# Some useful things to remember:
+#
+# WiMAX-MSK = EAP MSK, but is 64 octets.
+#
+# MIP-RK-1 = HMAC-SHA256(ESMK, "miprk@wimaxforum.org" | 0x00020001)
+# MIP-RK-2 = HMAC-SHA256(ESMK, MIP-RK-1 | "miprk@wimaxforum.org" | 0x00020002)
+# MIP-RK = MIP-RK-1 | MIP-RK-2
+#
+# MIP-SPI = first 4 octets of HMAC-SHA256(MIP-RK, "SPI CMIP PMIP")
+# plus some magic... you've got to track *all* MIP-SPI's
+# on your system!
+#
+# SPI-CMIP4 = MIP-SPI
+# SPI-PMIP4 = MIP-SPI + 1
+# SPI-CMIP6 = MIP-SPI + 2
+#
+# MN-NAI is the Mobile node NAI. You have to create it, and put
+# it into the request or reply as something like:
+#
+# WiMAX-MN-NAI = "%{User-Name}"
+#
+# You will also have to have the appropriate IP address (v4 or v6)
+# in order to calculate the keys below.
+#
+# Lifetimes are derived from Session-Timeout. It needs to be set
+# to some useful number.
+#
+# The hash function below H() is HMAC-SHA1.
+#
+#
+# MN-HA-CMIP4 = H(MIP-RK, "CMIP4 MN HA" | HA-IPv4 | MN-NAI)
+#
+# Where HA-IPv4 is WiMAX-hHA-IP-MIP4
+# or maybe WiMAX-vHA-IP-MIP4
+#
+# Which goes into WiMAX-MN-hHA-MIP4-Key
+# or maybe WiMAX-RRQ-MN-HA-Key
+# or maybe even WiMAX-vHA-MIP4-Key
+#
+# The corresponding SPI is SPI-CMIP4, which is MIP-SPI,
+#
+# which goes into WiMAX-MN-hHA-MIP4-SPI
+# or maybe WiMAX-RRQ-MN-HA-SPI
+# or even WiMAX-MN-vHA-MIP4-SPI
+#
+# MN-HA-PMIP4 = H(MIP-RK, "PMIP4 MN HA" | HA-IPv4 | MN-NAI)
+# MN-HA-CMIP6 = H(MIP-RK, "CMIP6 MN HA" | HA-IPv6 | MN-NAI)
+#
+# both with similar comments to above for MN-HA-CMIP4.
+#
+# In order to tell which one to use (CMIP4, PMIP4, or CMIP6),
+# you have to set WiMAX-IP-Technology in the reply to one of
+# the appropriate values.
+#
+#
+# FA-RK = H(MIP-RK, "FA-RK")
+#
+# MN-FA = H(FA-RK, "MN FA" | FA-IP | MN-NAI)
+#
+# Where does the FA-IP come from? No idea...
+#
+#
+# The next two keys (HA-RK and FA-HA) are not generated
+# for every authentication request, but only on demand.
+#
+# HA-RK = 160-bit random number assigned by the AAA server
+# to a specific HA.
+#
+# FA-HA = H(HA-RK, "FA-HA" | HA-IPv4 | FA-CoAv4 | SPI)
+#
+# where HA-IPv4 is as above.
+# and FA-CoAv4 address of the FA as seen by the HA
+# and SPI is the relevant SPI for the HA-RK.
+#
+# DHCP-RK = 160-bit random number assigned by the AAA server
+# to a specific DHCP server. vDHCP-RK is the same
+# thing.
+#
+#
+#
+# ## Instructions for v2.1 (LTE) WiMAX:
+#
+# When called from the "authorize" this module will detect the
+# presence of the following attributes:
+#
+# request:WiMAX-Re-synchronization-Info
+# control:WiMAX-SIM-Ki
+# control:WiMAX-SIM-OPc
+#
+# If all attributes are present, (i.e. a known SIM is requesting a
+# resync) then the module will attempt to extract the new SQN and
+# save it in control:WiMAX-SIM-SQN. It will also save a copy of
+# RAND from the request in control:WiMAX-SIM-RAND.
+#
+# The resulting value of SQN can then be saved in a database
+# e.g. via a call to the sql module using some unlang
+#
+# When called in the "post_auth" section it looks for:
+#
+# control:WiMAX-SIM-Ki
+# control:WiMAX-SIM-OPc
+# control:WiMAX-SIM-AMF
+# control:WiMAX-SIM-SQN
+# request:WiMAX-Visited-PLMN-ID
+#
+# If all these are present then it will attempt to generate the
+# keys for EPS AKA.
+#
+# First it checks for the presence of control:WiMAX-SIM-RAND and
+# if it is not present it generates a new RAND value which is
+# stored in reply:WiMAX-E-UTRAN-Vector-RAND. If it is present then
+# the value is simply copied to the reply attribute.
+#
+# Then it calls the Milenage algorithm to generate:
+#
+# reply:WiMAX-E-UTRAN-Vector-XRES
+# reply:WiMAX-E-UTRAN-Vector-AUTN
+#
+# And finally generates KASME which is stored in:
+# reply:WiMAX-E-UTRAN-Vector-KASME
+#
+#
+# NOTE: It is up to the system administrator to make sure that all
+# the necessary "control" attributes are populated with the
+# required values. The IMSI is likely to be found in User-Name in
+# the request and this can be used as the key to grab the values
+# from a database.
+#
+#
+wimax {
+ #
+ # Some WiMAX equipment requires that the MS-MPPE-*-Key
+ # attributes are sent in the Access-Accept, in addition to
+ # the WiMAX-MSK attribute.
+ #
+ # Other WiMAX equipment request that the MS-MPPE-*-Key
+ # attributes are NOT sent in the Access-Accept.
+ #
+ # By default, the EAP modules sends MS-MPPE-*-Key attributes.
+ # The default virtual server (raddb/sites-available/default)
+ # contains examples of adding the WiMAX-MSK.
+ #
+ # This configuration option makes the WiMAX module delete
+ # the MS-MPPE-*-Key attributes. The default is to leave
+ # them in place.
+ #
+ # If the keys are deleted (by setting this to "yes"), then
+ # the WiMAX-MSK attribute is automatically added to the reply.
+ delete_mppe_keys = no
+}
diff --git a/raddb/mods-available/yubikey b/raddb/mods-available/yubikey
new file mode 100644
index 0000000..9ba61ef
--- /dev/null
+++ b/raddb/mods-available/yubikey
@@ -0,0 +1,158 @@
+#
+# This module decrypts and validates Yubikey static and dynamic
+# OTP tokens.
+#
+yubikey {
+ #
+ # The length (number of ASCII bytes) of the Public-ID portion
+ # of the OTP string.
+ #
+ # Yubikey defaults to a 6 byte ID (2 * 6 = 12)
+# id_length = 12
+
+ #
+ # If true, the authorize method of rlm_yubikey will attempt to split the
+ # value of User-Password, into the user's password, and the OTP token.
+ #
+ # If enabled and successful, the value of &request:User-Password will be
+ # truncated and &request:Yubikey-OTP will be added.
+ #
+# split = yes
+
+ #
+ # Decrypt mode - Tokens will be decrypted and processed locally
+ #
+ # The module itself does not provide persistent storage as this
+ # would be duplicative of functionality already in the server.
+ #
+ # Yubikey authentication needs two attributes retrieved from
+ # persistent storage:
+ # * &control:Yubikey-Key - The AES key used to decrypt the OTP data.
+ # The Yubikey-Public-Id and/or User-Name
+ # attributes may be used to retrieve the key.
+ # * &control:Yubikey-Counter - This is compared with the counter in the OTP
+ # data and used to prevent replay attacks.
+ # This attribute will also be available in
+ # the request list after successful
+ # decryption.
+ #
+ # Yubikey-Counter isn't strictly required, but the server will
+ # generate warnings if it's not present when yubikey.authenticate
+ # is called.
+ #
+ # These attributes are available after authorization:
+ # * &request:Yubikey-Public-ID - The public portion of the OTP string.
+ # and additionally if 'split' is set:
+ # * &request:Yubikey-OTP - The OTP portion of User-Password.
+ #
+ # These attributes are available after authentication (if successful):
+ # * &request:Yubikey-Private-ID - The encrypted ID included in OTP data,
+ # must be verified if tokens share keys.
+ # * &request:Yubikey-Counter - The last counter value (should be recorded).
+ # * &request:Yubikey-Timestamp - Token's internal clock (mainly useful for
+ # debugging).
+ # * &request:Yubikey-Random - Randomly generated value from the token.
+ #
+ decrypt = no
+
+ #
+ # Validation mode - Tokens will be validated against a Yubicloud server
+ #
+ validate = no
+
+ #
+ # Settings for validation mode.
+ #
+ validation {
+ #
+ # URL of validation server, multiple URL config items may be used
+ # to list multiple servers.
+ #
+ # - %d is a placeholder for public ID of the token
+ # - %s is a placeholder for the token string itself
+ #
+ # If no URLs are listed, will default to the default URLs in the
+ # ykclient library, which point to the yubico validation servers.
+ servers {
+# uri = 'https://api.yubico.com/wsapi/2.0/verify?id=%d&otp=%s'
+# uri = 'https://api2.yubico.com/wsapi/2.0/verify?id=%d&otp=%s'
+ }
+
+ #
+ # API Client ID
+ #
+ # Must be set to your client id for the validation server.
+ #
+# client_id = 00000
+
+ #
+ # API Secret key (Base64 encoded)
+ #
+ # Must be set to your API key for the validation server.
+ #
+# api_key = '000000000000000000000000'
+
+ #
+ # Connection pool parameters
+ #
+ pool {
+ # Connections to create during module instantiation.
+ # If the server cannot create specified number of
+ # connections during instantiation it will exit.
+ # Set to 0 to allow the server to start without the
+ # yubikey server being available.
+ start = ${thread[pool].start_servers}
+
+ # Minimum number of connections to keep open
+ min = ${thread[pool].min_spare_servers}
+
+ # Maximum number of connections
+ #
+ # If these connections are all in use and a new one
+ # is requested, the request will NOT get a connection.
+ #
+ # Setting 'max' to LESS than the number of threads means
+ # that some threads may starve, and you will see errors
+ # like 'No connections available and at max connection limit'
+ #
+ # Setting 'max' to MORE than the number of threads means
+ # that there are more connections than necessary.
+ max = ${thread[pool].max_servers}
+
+ # Number of uses before the connection is closed
+ #
+ # NOTE: A setting of 0 means infinite (no limit).
+ uses = 0
+
+ # 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 = 30
+
+ # The lifetime (in seconds) of the connection
+ #
+ # NOTE: A setting of 0 means infinite (no limit).
+ lifetime = 0
+
+ # The idle timeout (in seconds). A connection which is
+ # unused for this length of time will be closed.
+ #
+ # NOTE: A setting of 0 means infinite (no timeout).
+ idle_timeout = 60
+
+ # Cycle over all connections in a pool instead of concentrating
+ # connection use on a few connections.
+ spread = yes
+
+ # 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/raddb/mods-config/README.rst b/raddb/mods-config/README.rst
new file mode 100644
index 0000000..abb4c8d
--- /dev/null
+++ b/raddb/mods-config/README.rst
@@ -0,0 +1,22 @@
+The mods-config Directory
+=========================
+
+This directory contains module-specific configuration files. These
+files are in a format different from the one used by the main
+`radiusd.conf` files. Earlier versions of the server had many
+module-specific files in the main `raddb` directory. The directory
+contained many files, and it was not clear which files did what.
+
+For Version 3 of FreeRADIUS, we have moved to a consistent naming
+scheme. Each module-specific configuration file is placed in this
+directory, in a subdirectory named for the module. Where necessary,
+files in the subdirectory have been named for the processing section
+where they are used.
+
+For example, the `users` file is now located in
+`mods-config/files/authorize`. That filename tells us three things:
+
+1. The file is used in the `authorize` section.
+2. The file is used by the `files` module.
+3. It is a "module configuration" file, which is a specific format.
+
diff --git a/raddb/mods-config/attr_filter/access_challenge b/raddb/mods-config/attr_filter/access_challenge
new file mode 100644
index 0000000..12ed619
--- /dev/null
+++ b/raddb/mods-config/attr_filter/access_challenge
@@ -0,0 +1,19 @@
+#
+# Configuration file for the rlm_attr_filter module.
+# Please see rlm_attr_filter(5) manpage for more information.
+#
+# $Id$
+#
+# This configuration file is used to remove almost all of the
+# attributes From an Access-Challenge message. The RFCs say
+# that an Access-Challenge packet can contain only a few
+# attributes. We enforce that here.
+#
+DEFAULT
+ EAP-Message =* ANY,
+ State =* ANY,
+ Message-Authenticator =* ANY,
+ Reply-Message =* ANY,
+ Proxy-State =* ANY,
+ Session-Timeout =* ANY,
+ Idle-Timeout =* ANY
diff --git a/raddb/mods-config/attr_filter/access_reject b/raddb/mods-config/attr_filter/access_reject
new file mode 100644
index 0000000..47f167b
--- /dev/null
+++ b/raddb/mods-config/attr_filter/access_reject
@@ -0,0 +1,18 @@
+#
+# Configuration file for the rlm_attr_filter module.
+# Please see rlm_attr_filter(5) manpage for more information.
+#
+# $Id$
+#
+# This configuration file is used to remove almost all of the attributes
+# From an Access-Reject message. The RFCs say that an Access-Reject
+# packet can contain only a few attributes. We enforce that here.
+#
+DEFAULT
+ EAP-Message =* ANY,
+ State =* ANY,
+ Message-Authenticator =* ANY,
+ Error-Cause =* ANY,
+ Reply-Message =* ANY,
+ MS-CHAP-Error =* ANY,
+ Proxy-State =* ANY
diff --git a/raddb/mods-config/attr_filter/accounting_response b/raddb/mods-config/attr_filter/accounting_response
new file mode 100644
index 0000000..01e9c6f
--- /dev/null
+++ b/raddb/mods-config/attr_filter/accounting_response
@@ -0,0 +1,16 @@
+#
+# Configuration file for the rlm_attr_filter module.
+# Please see rlm_attr_filter(5) manpage for more information.
+#
+# $Id$
+#
+# This configuration file is used to remove almost all of the attributes
+# From an Accounting-Response message. The RFC's say that an
+# Accounting-Response packet can contain only a few attributes.
+# We enforce that here.
+#
+DEFAULT
+ Vendor-Specific =* ANY,
+ Message-Authenticator =* ANY,
+ Error-Cause =* ANY,
+ Proxy-State =* ANY
diff --git a/raddb/mods-config/attr_filter/coa b/raddb/mods-config/attr_filter/coa
new file mode 100644
index 0000000..89cea2e
--- /dev/null
+++ b/raddb/mods-config/attr_filter/coa
@@ -0,0 +1,22 @@
+#
+# Configuration file for the rlm_attr_filter module.
+# Please see rlm_attr_filter(5) manpage for more information.
+#
+# $Id$
+#
+# This configuration file is used to remove attributes From an
+# CoA-Request or Disconnect-Request message. We have specified
+# a sample list here. This will have to be modified to add
+# attributes needed by your local configuration.
+#
+DEFAULT
+ User-Name =* ANY,
+ NAS-IP-Address =* ANY,
+ NAS-IPv6-Address =* ANY,
+ NAS-Port =* ANY,
+ NAS-Identifier =* ANY,
+ NAS-Port-Type =* ANY,
+ Calling-Station-Id =* ANY,
+ State =* ANY,
+ Message-Authenticator =* ANY,
+ Proxy-State =* ANY
diff --git a/raddb/mods-config/attr_filter/post-proxy b/raddb/mods-config/attr_filter/post-proxy
new file mode 100644
index 0000000..169fe5c
--- /dev/null
+++ b/raddb/mods-config/attr_filter/post-proxy
@@ -0,0 +1,121 @@
+#
+# Configuration file for the rlm_attr_filter module.
+# Please see rlm_attr_filter(5) manpage for more information.
+#
+# $Id$
+#
+# This file contains security and configuration information
+# for each realm. The first field is the realm name and
+# can be up to 253 characters in length. This is followed (on
+# the next line) with the list of filter rules to be used to
+# decide what attributes and/or values we allow proxy servers
+# to pass to the NAS for this realm.
+#
+# When a proxy-reply packet is received from a home server,
+# these attributes and values are tested. Only the first match
+# is used unless the "Fall-Through" variable is set to "Yes".
+# In that case the rules defined in the DEFAULT case are
+# processed as well.
+#
+# A special realm named "DEFAULT" matches on all realm names.
+# You can have only one DEFAULT entry. All entries are processed
+# in the order they appear in this file. The first entry that
+# matches the login-request will stop processing unless you use
+# the Fall-Through variable.
+#
+# Indented (with the tab character) lines following the first
+# line indicate the filter rules.
+#
+# You can include another `attrs' file with `$INCLUDE attrs.other'
+#
+
+#
+# This is a complete entry for realm "fisp". Note that there is no
+# Fall-Through entry so that no DEFAULT entry will be used, and the
+# server will NOT allow any other a/v pairs other than the ones
+# listed here.
+#
+# These rules allow:
+# o Only Framed-User Service-Types ( no telnet, rlogin, tcp-clear )
+# o PPP sessions ( no SLIP, CSLIP, etc. )
+# o dynamic ip assignment ( can't assign a static ip )
+# o an idle timeout value set to 600 seconds (10 min) or less
+# o a max session time set to 28800 seconds (8 hours) or less
+#
+#fisp
+# Service-Type == Framed-User,
+# Framed-Protocol == PPP,
+# Framed-IP-Address == 255.255.255.254,
+# Idle-Timeout <= 600,
+# Session-Timeout <= 28800
+
+#
+# This is a complete entry for realm "tisp". Note that there is no
+# Fall-Through entry so that no DEFAULT entry will be used, and the
+# server will NOT allow any other a/v pairs other than the ones
+# listed here.
+#
+# These rules allow:
+# o Only Login-User Service-Type ( no framed/ppp sessions )
+# o Telnet sessions only ( no rlogin, tcp-clear )
+# o Login host of 192.0.2.1
+#
+#tisp
+# Service-Type == Login-User,
+# Login-Service == Telnet,
+# Login-TCP-Port == 23,
+# Login-IP-Host == 192.0.2.1
+
+#
+# The following example can be used for a home server which is only
+# allowed to supply a Reply-Message, a Session-Timeout attribute of
+# maximum 86400, a Idle-Timeout attribute of maximum 600 and a
+# Acct-Interim-Interval attribute between 300 and 3600.
+# All other attributes sent back will be filtered out.
+#
+#strictrealm
+# Reply-Message =* ANY,
+# Session-Timeout <= 86400,
+# Idle-Timeout <= 600,
+# Acct-Interim-Interval >= 300,
+# Acct-Interim-Interval <= 3600
+
+#
+# This is a complete entry for realm "spamrealm". Fall-Through is used,
+# so that the DEFAULT filter rules are used in addition to these.
+#
+# These rules allow:
+# o Force the application of Filter-ID attribute to be returned
+# in the proxy reply, whether the proxy sent it or not.
+# o The standard DEFAULT rules as defined below
+#
+#spamrealm
+# Framed-Filter-Id := "nosmtp.in",
+# Fall-Through = Yes
+
+#
+# The rest of this file contains the DEFAULT entry.
+# DEFAULT matches with all realm names. (except if the realm previously
+# matched an entry with no Fall-Through)
+#
+
+DEFAULT
+ Framed-IP-Address == 255.255.255.254,
+ Framed-IP-Netmask == 255.255.255.255,
+ Framed-MTU >= 576,
+ Framed-Filter-ID =* ANY,
+ Reply-Message =* ANY,
+ Proxy-State =* ANY,
+ EAP-Message =* ANY,
+ Message-Authenticator =* ANY,
+ MS-MPPE-Recv-Key =* ANY,
+ MS-MPPE-Send-Key =* ANY,
+ MS-CHAP-MPPE-Keys =* ANY,
+ State =* ANY,
+ Session-Timeout <= 28800,
+ Idle-Timeout <= 600,
+ Calling-Station-Id =* ANY,
+ Operator-Name =* ANY,
+ User-Name =* ANY,
+ Chargeable-User-Identity =* ANY,
+ Port-Limit <= 2
diff --git a/raddb/mods-config/attr_filter/pre-proxy b/raddb/mods-config/attr_filter/pre-proxy
new file mode 100644
index 0000000..36d84e8
--- /dev/null
+++ b/raddb/mods-config/attr_filter/pre-proxy
@@ -0,0 +1,67 @@
+#
+# Configuration file for the rlm_attr_filter module.
+# Please see rlm_attr_filter(5) manpage for more information.
+#
+# $Id$
+#
+# This file contains security and configuration information
+# for each realm. It can be used be an rlm_attr_filter module
+# instance to filter attributes before sending packets to the
+# home server of a realm.
+#
+# When a packet is sent to a home server, these attributes
+# and values are tested. Only the first match is used unless
+# the "Fall-Through" variable is set to "Yes". In that case
+# the rules defined in the DEFAULT case are processed as well.
+#
+# A special realm named "DEFAULT" matches on all realm names.
+# You can have only one DEFAULT entry. All entries are processed
+# in the order they appear in this file. The first entry that
+# matches the login-request will stop processing unless you use
+# the Fall-Through variable.
+#
+# The first line indicates the realm to which the rules apply.
+# Indented (with the tab character) lines following the first
+# line indicate the filter rules.
+#
+
+# This is a complete entry for 'nochap' realm. It allows to send very
+# basic attributes to the home server. Note that there is no Fall-Through
+# entry so that no DEFAULT entry will be used. Only the listed attributes
+# will be sent in the packet, all other attributes will be filtered out.
+#
+#nochap
+# User-Name =* ANY,
+# User-Password =* ANY,
+# NAS-IP-Address =* ANY,
+# NAS-Identifier =* ANY
+
+# The entry for the 'brokenas' realm removes the attribute NAS-Port-Type
+# if its value is different from 'Ethernet'. Then the default rules are
+# applied.
+#
+#brokenas
+# NAS-Port-Type == Ethernet
+# Fall-Through = Yes
+
+# The rest of this file contains the DEFAULT entry.
+# DEFAULT matches with all realm names.
+
+DEFAULT
+ User-Name =* ANY,
+ User-Password =* ANY,
+ CHAP-Password =* ANY,
+ CHAP-Challenge =* ANY,
+ MS-CHAP-Challenge =* ANY,
+ MS-CHAP-Response =* ANY,
+ EAP-Message =* ANY,
+ Message-Authenticator =* ANY,
+ State =* ANY,
+ NAS-IP-Address =* ANY,
+ NAS-Identifier =* ANY,
+ Operator-Name =* ANY,
+ Calling-Station-Id =* ANY,
+ Called-Station-Id =* ANY,
+ Operator-Name =* ANY,
+ Chargeable-User-Identity =* ANY,
+ Proxy-State =* ANY
diff --git a/raddb/mods-config/files/accounting b/raddb/mods-config/files/accounting
new file mode 100644
index 0000000..eaf952a
--- /dev/null
+++ b/raddb/mods-config/files/accounting
@@ -0,0 +1,27 @@
+#
+# $Id$
+#
+# This is like the 'users' file, but it is processed only for
+# accounting packets.
+#
+
+# Select between different accounting methods based for example on the
+# Realm, the Huntgroup-Name or any combinaison of the attribute/value
+# pairs contained in an accounting packet.
+#
+# You will need to add an "Acct-Type foo {...}" subsection to the
+# main "accounting" section in order for these sample configurations
+# to work.
+#
+#DEFAULT Realm == "foo.net", Acct-Type := foo
+#
+#DEFAULT Huntgroup-Name == "wifi", Acct-Type := wifi
+#
+#DEFAULT Client-IP-Address == 10.0.0.1, Acct-Type := other
+#
+#DEFAULT Acct-Status-Type == Start, Acct-Type := start
+
+# Replace the User-Name with the Stripped-User-Name, if it exists.
+#
+#DEFAULT
+# User-Name := "%{%{Stripped-User-Name}:-%{User-Name}}"
diff --git a/raddb/mods-config/files/authorize b/raddb/mods-config/files/authorize
new file mode 100644
index 0000000..ddf805f
--- /dev/null
+++ b/raddb/mods-config/files/authorize
@@ -0,0 +1,206 @@
+#
+# Configuration file for the rlm_files module.
+# Please see rlm_files(5) manpage for more information.
+#
+# This file contains authentication security and configuration
+# information for each user. Accounting requests are NOT processed
+# through this file. Instead, see 'accounting', in this directory.
+#
+# The first field is the user's name and can be up to
+# 253 characters in length. This is followed (on the same line) with
+# the list of authentication requirements for that user. This can
+# include password, comm server name, comm server port number, protocol
+# type (perhaps set by the "hints" file), and huntgroup name (set by
+# the "huntgroups" file).
+#
+# If you are not sure why a particular reply is being sent by the
+# server, then run the server in debugging mode (radiusd -X), and
+# you will see which entries in this file are matched.
+#
+# When an authentication request is received from the comm server,
+# these values are tested. Only the first match is used unless the
+# "Fall-Through" variable is set to "Yes".
+#
+# A special user named "DEFAULT" matches on all usernames.
+# You can have several DEFAULT entries. All entries are processed
+# in the order they appear in this file. The first entry that
+# matches the login-request will stop processing unless you use
+# the Fall-Through variable.
+#
+# Indented (with the tab character) lines following the first
+# line indicate the configuration values to be passed back to
+# the comm server to allow the initiation of a user session.
+# This can include things like the PPP configuration values
+# or the host to log the user onto.
+#
+# You can include another `users' file with `$INCLUDE users.other'
+
+#
+# For a list of RADIUS attributes, and links to their definitions,
+# see: http://www.freeradius.org/rfc/attributes.html
+#
+# Entries below this point are examples included in the server for
+# educational purposes. They may be deleted from the deployed
+# configuration without impacting the operation of the server.
+#
+
+#
+# Deny access for a specific user. Note that this entry MUST
+# be before any other 'Auth-Type' attribute which results in the user
+# being authenticated.
+#
+# Note that there is NO 'Fall-Through' attribute, so the user will not
+# be given any additional resources.
+#
+#lameuser Auth-Type := Reject
+# Reply-Message = "Your account has been disabled."
+
+#
+# Deny access for a group of users.
+#
+# Note that there is NO 'Fall-Through' attribute, so the user will not
+# be given any additional resources.
+#
+#DEFAULT Group == "disabled", Auth-Type := Reject
+# Reply-Message = "Your account has been disabled."
+#
+
+#
+# This is a complete entry for "steve". Note that there is no Fall-Through
+# entry so that no DEFAULT entry will be used, and the user will NOT
+# get any attributes in addition to the ones listed here.
+#
+#steve Cleartext-Password := "testing"
+# Service-Type = Framed-User,
+# Framed-Protocol = PPP,
+# Framed-IP-Address = 172.16.3.33,
+# Framed-IP-Netmask = 255.255.255.0,
+# Framed-Routing = Broadcast-Listen,
+# Framed-Filter-Id = "std.ppp",
+# Framed-MTU = 1500,
+# Framed-Compression = Van-Jacobsen-TCP-IP
+
+#
+# The canonical testing user which is in most of the
+# examples.
+#
+#bob Cleartext-Password := "hello"
+# Reply-Message := "Hello, %{User-Name}"
+#
+
+#
+# This is an entry for a user with a space in their name.
+# Note the double quotes surrounding the name. If you have
+# users with spaces in their names, you must also change
+# the "filter_username" policy to allow spaces.
+#
+# See raddb/policy.d/filter, filter_username {} section.
+#
+#"John Doe" Cleartext-Password := "hello"
+# Reply-Message = "Hello, %{User-Name}"
+
+#
+# Dial user back and telnet to the default host for that port
+#
+#Deg Cleartext-Password := "ge55ged"
+# Service-Type = Callback-Login-User,
+# Login-IP-Host = 0.0.0.0,
+# Callback-Number = "9,5551212",
+# Login-Service = Telnet,
+# Login-TCP-Port = Telnet
+
+#
+# Another complete entry. After the user "dialbk" has logged in, the
+# connection will be broken and the user will be dialed back after which
+# he will get a connection to the host "timeshare1".
+#
+#dialbk Cleartext-Password := "callme"
+# Service-Type = Callback-Login-User,
+# Login-IP-Host = timeshare1,
+# Login-Service = PortMaster,
+# Callback-Number = "9,1-800-555-1212"
+
+#
+# user "swilson" will only get a static IP number if he logs in with
+# a framed protocol on a terminal server in Alphen (see the huntgroups file).
+#
+# Note that by setting "Fall-Through", other attributes will be added from
+# the following DEFAULT entries
+#
+#swilson Service-Type == Framed-User, Huntgroup-Name == "alphen"
+# Framed-IP-Address = 192.0.2.65,
+# Fall-Through = Yes
+
+#
+# If the user logs in as 'username.shell', then authenticate them
+# using the default method, give them shell access, and stop processing
+# the rest of the file.
+#
+#DEFAULT Suffix == ".shell"
+# Service-Type = Login-User,
+# Login-Service = Telnet,
+# Login-IP-Host = your.shell.machine
+
+
+#
+# The rest of this file contains the several DEFAULT entries.
+# DEFAULT entries match with all login names.
+# Note that DEFAULT entries can also Fall-Through (see first entry).
+# A name-value pair from a DEFAULT entry will _NEVER_ override
+# an already existing name-value pair.
+#
+
+# Sample defaults for all framed connections.
+#
+#DEFAULT Service-Type == Framed-User
+# Framed-IP-Address = 255.255.255.254,
+# Framed-MTU = 576,
+# Service-Type = Framed-User,
+# Fall-Through = Yes
+
+#
+# Default for PPP: dynamic IP address, PPP mode, VJ-compression.
+# NOTE: we do not use Hint = "PPP", since PPP might also be auto-detected
+# by the terminal server in which case there may not be a "P" suffix.
+# The terminal server sends "Framed-Protocol = PPP" for auto PPP.
+#
+DEFAULT Framed-Protocol == PPP
+ Framed-Protocol = PPP,
+ Framed-Compression = Van-Jacobson-TCP-IP
+
+#
+# Default for CSLIP: dynamic IP address, SLIP mode, VJ-compression.
+#
+DEFAULT Hint == "CSLIP"
+ Framed-Protocol = SLIP,
+ Framed-Compression = Van-Jacobson-TCP-IP
+
+#
+# Default for SLIP: dynamic IP address, SLIP mode.
+#
+DEFAULT Hint == "SLIP"
+ Framed-Protocol = SLIP
+
+#
+# Last default: rlogin to our main server.
+#
+#DEFAULT
+# Service-Type = Login-User,
+# Login-Service = Rlogin,
+# Login-IP-Host = shellbox.ispdomain.com
+
+# #
+# # Last default: shell on the local terminal server.
+# #
+# DEFAULT
+# Service-Type = Administrative-User
+
+
+# On no match, the user is denied access.
+
+
+#########################################################
+# You should add test accounts to the TOP of this file! #
+# See the example user "bob" above. #
+#########################################################
+
diff --git a/raddb/mods-config/files/dhcp b/raddb/mods-config/files/dhcp
new file mode 100644
index 0000000..04f37b5
--- /dev/null
+++ b/raddb/mods-config/files/dhcp
@@ -0,0 +1,153 @@
+#
+# This configuration file that may be used by multiple instances of rlm_files
+# to set reply and control options for defining DHCP replies.
+#
+# The content of this file is all made up and needs to be set appropriate to
+# the network being served.
+#
+
+############################################
+# Global and network-specific parameters #
+############################################
+
+#
+# Note: This section is matched by calling the dhcp_network instance of the
+# files module.
+#
+
+
+#
+# Default options that can be overridden by subsequent matches.
+#
+network
+ DHCP-Domain-Name-Server := 192.0.1.100,
+ DHCP-Domain-Name-Server += 192.0.1.101,
+ DHCP-Time-Server := 192.0.1.200,
+ DHCP-Domain-Name := "example.org",
+ DHCP-IP-Address-Lease-Time := 7200,
+ Fall-Through := yes
+
+
+#
+# The following examples set options specific to the Layer 2 network, matched
+# on whether the internal attribute DHCP-Network-Subnet (that acts as a
+# network identifier) is within the indicated range. This is equivalent to a
+# "shared-network" or "multinet" configuration (i.e. one that is possibly
+# composed of multiple subnets) as defined by some other DHCP servers.
+#
+
+#
+# Here is an example for a network containing a single IP subnet. We can set
+# the network-specific options *and* we directly set the DHCP-Subnet-Mask,
+# DHCP-Router-Address and DHCP-Broadcast-Address since it is a common reply
+# parameter for all DHCP requests originating from this network.
+#
+# The use of the ^= "prepend" operator for setting DHCP-Domain-Name-Server
+# results in this new value being inserted at the start of the list, meaning
+# this will become the first DNS server presented in the reply.
+#
+# Note: If the architecture has only a single subnet for each Layer 2 network
+# then by placing all subnet-related options here we can avoid calling the
+# dhcp_subnet policy after IP allocation.
+#
+network DHCP-Network-Subnet < 10.20.0.0/16, Pool-Name := "smalldept"
+ DHCP-IP-Address-Lease-Time := 3600,
+ DHCP-Domain-Name := "smalldept.example.org",
+ DHCP-Subnet-Mask := 255.255.0.0,
+ DHCP-Router-Address := 10.20.0.1,
+ DHCP-Domain-Name-Server ^= 10.20.0.2,
+ DHCP-Broadcast-Address := 10.20.255.255
+
+#
+# Here is an example for a network that consists of multiple IP subnets, each
+# of which is valid for a DHCP request originating from the network. We set
+# the Pool-Name parameter to identify a single pool that contains the IP
+# address within each subnet, any of which is suitable.
+#
+# We set the options that are common to the network but we defer the setting
+# of DHCP-Subnet-Mask, DHCP-Router-Address and DHCP-Broadcast-Address until an
+# address has been allocated. Only then do we know which subnet parameters are
+# required. See the next section.
+#
+network DHCP-Network-Subnet < 10.30.0.0/16, Pool-Name := "bigdept"
+ DHCP-Domain-Name := "bigdept.example.org"
+
+
+#
+# Here is an example for a network that has a dedicated pool for admin staff
+# and a seperate pool for everything else.
+#
+network DHCP-Network-Subnet < 192.0.2.0/24, DHCP-Group-Name == "admin", Pool-Name := "admin-only"
+network DHCP-Network-Subnet < 192.0.2.0/24, Pool-Name := "general"
+
+
+################################
+# Subnet-specific parameters #
+################################
+
+#
+# Note: This section is matched by calling the dhcp_subnet policy which sets
+# DHCP-Network-Subnet to the allocated IP address of the device and then
+# calls the dhcp_subnet instance of the files module.
+#
+# Layer 2 networks many contain multiple subnets, each with their own gateway.
+# We call this section *after* the allocation of an IP address (e.g. from a
+# single pool containing addresses within multiple equally-valid subnets for
+# the network) so that we then know which subnet-specific parameters to
+# return.
+#
+
+#
+# Subnet-specific options, matched on whether the allocated IP address is
+# within the indicated range.
+#
+subnet DHCP-Network-Subnet < 10.30.10.0/24
+ DHCP-Subnet-Mask := 255.255.255.0,
+ DHCP-Router-Address := 10.30.10.1,
+ DHCP-Broadcast-Address := 10.30.10.255
+
+subnet DHCP-Network-Subnet < 10.30.20.0/24
+ DHCP-Subnet-Mask := 255.255.255.0,
+ DHCP-Router-Address := 10.30.20.1,
+ DHCP-Broadcast-Address := 10.30.20.255
+
+
+###############################
+# Group-specific parameters #
+###############################
+
+#
+# Note: This section is matched by calling the dhcp_group_options policy.
+#
+# It should be called *after* defining the device's group memberships in
+# DHCP-Group-Name request attributes. In the default dhcp virtual server this
+# is demonstrated with the help of the dhcp_group_membership instance of the
+# passwd module.
+#
+
+#
+# Group-specific options, keyed by DHCP-Group-Name
+#
+group1
+ DHCP-Server-Host-Name := "terminal-booter.example.org",
+ DHCP-Boot-Filename := "bootfile.pxe"
+
+
+##############################
+# Host-specific parameters #
+##############################
+
+#
+# Note: This section is matched by calling the dhcp_hosts instance of the
+# files module.
+#
+
+#
+# Host-specific options, keyed by DHCP-Client-Hardware-Address
+#
+host-00:10:20:30:40:50
+ DHCP-Boot-Filename := "customboot.pxe"
+
+host-10:90:80:70:aa:bb
+ DHCP-X-Window-Font-Server := 10.20.1.10,
+ DHCP-Impress-Server := 10.20.1.20
diff --git a/raddb/mods-config/files/pre-proxy b/raddb/mods-config/files/pre-proxy
new file mode 100644
index 0000000..7292e23
--- /dev/null
+++ b/raddb/mods-config/files/pre-proxy
@@ -0,0 +1,31 @@
+#
+# Configuration file for the rlm_files module.
+# Please see rlm_files(5) manpage for more information.
+#
+# $Id$
+#
+# This file is similar to the "users" file. The check items
+# are compared against the request, but the "reply" items are
+# used to update the proxied packet, not the reply to the NAS.
+#
+# You can use this file to re-write requests which are about to
+# be sent to a home server.
+#
+
+#
+# Requests destinated to realm "extisp" are sent to a RADIUS
+# home server hosted by an other company which doesn't know about
+# the IP addresses of our NASes. Therefore we replace the value of
+# the NAS-IP-Address attribute by a unique value we communicated
+# to them.
+#
+#DEFAULT Realm == "extisp"
+# NAS-IP-Address := 10.1.2.3
+
+#
+# For all proxied packets, set the User-Name in the proxied packet
+# to the Stripped-User-Name, if it exists. If not, set it to the
+# User-Name from the original request.
+#
+#DEFAULT
+# User-Name := `%{%{Stripped-User-Name}:-%{User-Name}}`
diff --git a/raddb/mods-config/perl/example.pl b/raddb/mods-config/perl/example.pl
new file mode 100644
index 0000000..f00b17b
--- /dev/null
+++ b/raddb/mods-config/perl/example.pl
@@ -0,0 +1,230 @@
+
+#
+# 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 The FreeRADIUS server project
+# Copyright 2002 Boian Jordanov <bjordanov@orbitel.bg>
+#
+
+#
+# Example code for use with rlm_perl
+#
+# You can use every module that comes with your perl distribution!
+#
+# If you are using DBI and do some queries to DB, please be sure to
+# use the CLONE function to initialize the DBI connection to DB.
+#
+
+use strict;
+use warnings;
+
+# use ...
+use Data::Dumper;
+
+# Bring the global hashes into the package scope
+our (%RAD_REQUEST, %RAD_REPLY, %RAD_CHECK, %RAD_STATE, %RAD_PERLCONF);
+
+# This is hash wich hold original request from radius
+#my %RAD_REQUEST;
+# In this hash you add values that will be returned to NAS.
+#my %RAD_REPLY;
+#This is for check items
+#my %RAD_CHECK;
+# This is the session-sate
+#my %RAD_STATE;
+# This is configuration items from "config" perl module configuration section
+#my %RAD_PERLCONF;
+
+# Multi-value attributes are mapped to perl arrayrefs.
+#
+# update request {
+# Filter-Id := 'foo'
+# Filter-Id += 'bar'
+# }
+#
+# This results to the following entry in %RAD_REQUEST:
+#
+# $RAD_REQUEST{'Filter-Id'} = [ 'foo', 'bar' ];
+#
+# Likewise, you can assign an arrayref to return multi-value attributes
+
+#
+# This the remapping of return values
+#
+use constant {
+ RLM_MODULE_REJECT => 0, # immediately reject the request
+ RLM_MODULE_OK => 2, # the module is OK, continue
+ RLM_MODULE_HANDLED => 3, # the module handled the request, so stop
+ RLM_MODULE_INVALID => 4, # the module considers the request invalid
+ RLM_MODULE_USERLOCK => 5, # reject the request (user is locked out)
+ RLM_MODULE_NOTFOUND => 6, # user not found
+ RLM_MODULE_NOOP => 7, # module succeeded without doing anything
+ RLM_MODULE_UPDATED => 8, # OK (pairs modified)
+ RLM_MODULE_NUMCODES => 9 # How many return codes there are
+};
+
+# Same as src/include/log.h
+use constant {
+ L_AUTH => 2, # Authentication message
+ L_INFO => 3, # Informational message
+ L_ERR => 4, # Error message
+ L_WARN => 5, # Warning
+ L_PROXY => 6, # Proxy messages
+ L_ACCT => 7, # Accounting messages
+ L_DBG => 16, # Only displayed when debugging is enabled
+ L_DBG_WARN => 17, # Warning only displayed when debugging is enabled
+ L_DBG_ERR => 18, # Error only displayed when debugging is enabled
+ L_DBG_WARN_REQ => 19, # Less severe warning only displayed when debugging is enabled
+ L_DBG_ERR_REQ => 20, # Less severe error only displayed when debugging is enabled
+};
+
+# Global variables can persist across different calls to the module.
+#
+#
+# {
+# my %static_global_hash = ();
+#
+# sub post_auth {
+# ...
+# }
+# ...
+# }
+
+
+# Function to handle authorize
+sub authorize {
+ # For debugging purposes only
+# &log_request_attributes;
+
+ # Here's where your authorization code comes
+ # You can call another function from here:
+ &test_call;
+
+ return RLM_MODULE_OK;
+}
+
+# Function to handle authenticate
+sub authenticate {
+ # For debugging purposes only
+# &log_request_attributes;
+
+ if ($RAD_REQUEST{'User-Name'} =~ /^baduser/i) {
+ # Reject user and tell him why
+ $RAD_REPLY{'Reply-Message'} = "Denied access by rlm_perl function";
+ return RLM_MODULE_REJECT;
+ } else {
+ # Accept user and set some attribute
+ if (&radiusd::xlat("%{client:group}") eq 'UltraAllInclusive') {
+ # User called from NAS with unlim plan set, set higher limits
+ $RAD_REPLY{'h323-credit-amount'} = "1000000";
+ } else {
+ $RAD_REPLY{'h323-credit-amount'} = "100";
+ }
+ return RLM_MODULE_OK;
+ }
+}
+
+# Function to handle preacct
+sub preacct {
+ # For debugging purposes only
+# &log_request_attributes;
+
+ return RLM_MODULE_OK;
+}
+
+# Function to handle accounting
+sub accounting {
+ # For debugging purposes only
+# &log_request_attributes;
+
+ # You can call another subroutine from here
+ &test_call;
+
+ return RLM_MODULE_OK;
+}
+
+# Function to handle checksimul
+sub checksimul {
+ # For debugging purposes only
+# &log_request_attributes;
+
+ return RLM_MODULE_OK;
+}
+
+# Function to handle pre_proxy
+sub pre_proxy {
+ # For debugging purposes only
+# &log_request_attributes;
+
+ return RLM_MODULE_OK;
+}
+
+# Function to handle post_proxy
+sub post_proxy {
+ # For debugging purposes only
+# &log_request_attributes;
+
+ return RLM_MODULE_OK;
+}
+
+# Function to handle post_auth
+sub post_auth {
+ # For debugging purposes only
+# &log_request_attributes;
+
+ return RLM_MODULE_OK;
+}
+
+# Function to handle xlat
+sub xlat {
+ # For debugging purposes only
+# &log_request_attributes;
+
+ # Loads some external perl and evaluate it
+ my ($filename,$a,$b,$c,$d) = @_;
+ &radiusd::radlog(L_DBG, "From xlat $filename ");
+ &radiusd::radlog(L_DBG,"From xlat $a $b $c $d ");
+ local *FH;
+ open FH, $filename or die "open '$filename' $!";
+ local($/) = undef;
+ my $sub = <FH>;
+ close FH;
+ my $eval = qq{ sub handler{ $sub;} };
+ eval $eval;
+ eval {main->handler;};
+}
+
+# Function to handle detach
+sub detach {
+ # For debugging purposes only
+# &log_request_attributes;
+}
+
+#
+# Some functions that can be called from other functions
+#
+
+sub test_call {
+ # Some code goes here
+}
+
+sub log_request_attributes {
+ # This shouldn't be done in production environments!
+ # This is only meant for debugging!
+ for (keys %RAD_REQUEST) {
+ &radiusd::radlog(L_DBG, "RAD_REQUEST: $_ = $RAD_REQUEST{$_}");
+ }
+}
+
diff --git a/raddb/mods-config/preprocess/hints b/raddb/mods-config/preprocess/hints
new file mode 100644
index 0000000..84d4d78
--- /dev/null
+++ b/raddb/mods-config/preprocess/hints
@@ -0,0 +1,86 @@
+#
+# hints
+#
+# The hints file. This file is used to match
+# a request, and then add attributes to it. This
+# process allows a user to login as "bob.ppp" (for example),
+# and receive a PPP connection, even if the NAS doesn't
+# ask for PPP. The "hints" file is used to match the
+# ".ppp" portion of the username, and to add a set of
+# "user requested PPP" attributes to the request.
+#
+# Matching can take place with the the Prefix and Suffix
+# attributes, just like in the "users" file.
+# These attributes operate ONLY on the username, though.
+#
+# Note that the attributes that are set for each entry are
+# NOT added to the reply attributes passed back to the NAS.
+# Instead they are added to the list of attributes in the
+# request that has been SENT by the NAS.
+#
+# This extra information can be used in the users file to
+# match on. Usually this is done in the DEFAULT entries,
+# of which there can be more than one.
+#
+# In addition a matching entry can transform a username
+# for authentication purposes if the "Strip-User-Name"
+# variable is set to Yes in an entry (default is Yes).
+#
+# A special non-protocol name-value pair called "Hint"
+# can be set to match on in the "users" file.
+#
+# As with the "users" file, the first entry that matches the
+# incoming request will cause the server to stop looking for
+# more hints. If the "Fall-Through" attribute is set to
+# "Yes" in an entry then the server will not stop, but
+# continue to process further hints from the file. Matches
+# on subsequent hints will be against the altered request
+# from the previous hints, not against the original request.
+#
+# The following is how most dial-up ISPs want to set this up.
+#
+# Version: $Id$
+#
+
+
+DEFAULT Suffix == ".ppp", Strip-User-Name = Yes
+ Hint = "PPP",
+ Service-Type = Framed-User,
+ Framed-Protocol = PPP
+
+DEFAULT Suffix == ".slip", Strip-User-Name = Yes
+ Hint = "SLIP",
+ Service-Type = Framed-User,
+ Framed-Protocol = SLIP
+
+DEFAULT Suffix == ".cslip", Strip-User-Name = Yes
+ Hint = "CSLIP",
+ Service-Type = Framed-User,
+ Framed-Protocol = SLIP,
+ Framed-Compression = Van-Jacobson-TCP-IP
+
+######################################################################
+#
+# These entries are old, and commented out by default.
+# They confuse too many people when "Peter" logs in, and the
+# server thinks that the user "eter" is asking for PPP.
+#
+#DEFAULT Prefix == "U", Strip-User-Name = No
+# Hint = "UUCP"
+
+#DEFAULT Prefix == "P", Strip-User-Name = Yes
+# Hint = "PPP",
+# Service-Type = Framed-User,
+# Framed-Protocol = PPP
+
+#DEFAULT Prefix == "S", Strip-User-Name = Yes
+# Hint = "SLIP",
+# Service-Type = Framed-User,
+# Framed-Protocol = SLIP
+
+#DEFAULT Prefix == "C", Strip-User-Name = Yes
+# Hint = "CSLIP",
+# Service-Type = Framed-User,
+# Framed-Protocol = SLIP,
+# Framed-Compression = Van-Jacobson-TCP-IP
+
diff --git a/raddb/mods-config/preprocess/huntgroups b/raddb/mods-config/preprocess/huntgroups
new file mode 100644
index 0000000..da28dba
--- /dev/null
+++ b/raddb/mods-config/preprocess/huntgroups
@@ -0,0 +1,43 @@
+#
+# huntgroups This file defines the `huntgroups' that you have. A
+# huntgroup is defined by specifying the IP address of
+# the NAS and possibly a port.
+#
+# Matching is done while RADIUS scans the user file; if it
+# includes the selection criteria "Huntgroup-Name == XXX"
+# the huntgroup is looked up in this file to see if it
+# matches. There can be multiple definitions of the same
+# huntgroup; the first one that matches will be used.
+#
+# This file can also be used to define restricted access
+# to certain huntgroups. The second and following lines
+# define the access restrictions (based on username and
+# UNIX usergroup) for the huntgroup.
+#
+
+#
+# Our POP in Alphen a/d Rijn has 3 terminal servers. Create a Huntgroup-Name
+# called Alphen that matches on all three terminal servers.
+#
+#alphen NAS-IP-Address == 192.0.2.5
+#alphen NAS-IP-Address == 192.0.2.6
+#alphen NAS-IP-Address == 192.0.2.7
+
+#
+# The POP in Delft consists of only one terminal server.
+#
+#delft NAS-IP-Address == 198.51.100.5
+
+#
+# Port 0 on the first terminal server in Alphen are connected to
+# a huntgroup that is for business users only. Note that only one
+# of the username or groupname has to match to get access (OR/OR).
+#
+# Note that this huntgroup is a subset of the "alphen" huntgroup.
+#
+#business NAS-IP-Address == 198.51.100.5, NAS-Port-Id == 0
+# User-Name == rogerl,
+# User-Name == henks,
+# Group == business,
+# Group == staff
+
diff --git a/raddb/mods-config/realm/freeradius-naptr-to-home-server.sh b/raddb/mods-config/realm/freeradius-naptr-to-home-server.sh
new file mode 100755
index 0000000..66388d3
--- /dev/null
+++ b/raddb/mods-config/realm/freeradius-naptr-to-home-server.sh
@@ -0,0 +1,161 @@
+#!/bin/sh
+
+# This script looks up radsec srv records in DNS for the one realm
+# given as argument, and creates a home_server template based on the
+# information found.
+#
+# It currently ignores weight markers, but does sort servers on
+# priority marker, lowest number first. For host command this is
+# column 5, for dig it is column 1.
+#
+# It then tells FreeRADIUS (via radmin) that
+# there is a new home server.
+#
+# Note that in order for it to work, you need to have the
+# "control-socket" enabled.
+
+usage() {
+ echo "Usage: ${0} [OPTIONS] <realm> <optional NAPTR tag>"
+ echo " -d RADIUS_DIR Set radius directory"
+ echo " -t test (skip running radmin)"
+ exit 1
+}
+
+test -n "${1}" || usage
+
+RADDB=/etc/raddb
+RADMIN=y
+
+#
+# Parse command-line options
+#
+while [ `echo "$1" | cut -c 1` = "-" ]
+do
+ case "$1" in
+ -d)
+ RADDB=$2
+ shift;shift
+ ;;
+ -t)
+ RADMIN=
+ shift
+ ;;
+
+ *)
+ usage
+ ;;
+ esac
+done
+
+test -n "${2}" && NAPTRTAG="${2}" || NAPTRTAG="x-eduroam:radius.tls"
+
+DIGCMD=$(command -v dig)
+HOSTCMD=$(command -v host)
+PRINTCMD=$(command -v printf)
+
+#
+# These validations prevent rogue DNS records from pwning your RADIUS installation.
+#
+# See https://github.com/radsecproxy/radsecproxy/security/advisories/GHSA-56gw-9rj9-55rc
+# and https://www.usenix.org/conference/usenixsecurity21/presentation/jeitner
+#
+# The contents of these validation routines should NOT be changed without a deep understanding
+# of DNS!
+#
+validate_host() {
+ echo ${@} | tr -d '\n\t\r' | grep -E '^[_0-9a-zA-Z][-._0-9a-zA-Z]*$'
+}
+
+validate_port() {
+ echo ${@} | tr -d '\n\t\r' | grep -E '^[0-9]+$'
+}
+
+dig_it_srv() {
+ ${DIGCMD} +short srv $SRV_HOST | sort -n -k1 |
+ while read line; do
+ set $line
+ PORT=$(validate_port $3)
+ HOST=$(validate_host $4)
+ if [ -n "${HOST}" ] && [ -n "${PORT}" ]; then
+ $PRINTCMD "\tipaddr = ${HOST%.}\n\tport = ${PORT}\n"
+ fi
+ done
+}
+
+dig_it_naptr() {
+ ${DIGCMD} +short naptr "${REALM}" | grep $NAPTRTAG | sort -n -k1 |
+ while read line; do
+ set $line
+ TYPE=$3
+ HOST=$(validate_host $6)
+ if ( [ "$TYPE" = "\"s\"" ] || [ "$TYPE" = "\"S\"" ] ) && [ -n "${HOST}" ]; then
+ SRV_HOST=${HOST%.}
+ dig_it_srv
+ fi
+ done
+}
+
+host_it_srv() {
+ ${HOSTCMD} -t srv $SRV_HOST | sort -n -k5 |
+ while read line; do
+ set $line
+ PORT=$(validate_port $7)
+ HOST=$(validate_host $8)
+ if [ -n "${HOST}" ] && [ -n "${PORT}" ]; then
+ $PRINTCMD "\tipaddr ${HOST%.}:${PORT}\n"
+ fi
+ done
+}
+
+host_it_naptr() {
+ ${HOSTCMD} -t naptr "${REALM}" | grep $NAPTRTAG | sort -n -k5 |
+ while read line; do
+ set $line
+ TYPE=$7
+ HOST=$(validate_host ${10})
+ if ( [ "$TYPE" = "\"s\"" ] || [ "$TYPE" = "\"S\"" ] ) && [ -n "${HOST}" ]; then
+ SRV_HOST=${HOST%.}
+ host_it_srv
+ fi
+ done
+}
+
+REALM=$(validate_host ${1})
+if [ -z "${REALM}" ]; then
+ echo "realm \"${1}\" failed validation" >&2
+ usage
+fi
+
+if [ -x "${DIGCMD}" ]; then
+ SERVERS=$(dig_it_naptr)
+
+elif [ -x "${HOSTCMD}" ]; then
+ SERVERS=$(host_it_naptr)
+
+else
+ echo "${0} requires either \"dig\" or \"host\" command." >&2
+ exit 1
+fi
+
+if [ ! -n "${SERVERS}" ]; then
+ echo "No servers found" >&2
+ exit 1
+fi
+
+#
+# Just testing - don't do anything else.
+#
+if [ -z "${RADMIN}" ]; then
+ $PRINTCMD "home_server ${REALM} {\n${SERVERS}\n\t\$INCLUDE tls.conf\n}\n"
+ exit 0
+fi
+
+#
+# Print out the template, and include the site-local tls.conf file.
+#
+$PRINTCMD "home_server ${REALM} {\n${SERVERS}\n\t\$INCLUDE tls.conf\n}\n" > $RADDB/home_servers/$1
+
+#
+# @todo - use ${prefix} or some such thing to find radmin.
+#
+/usr/sbin/radmin -e "add home_server file $RADDB/home_servers/$1"
diff --git a/raddb/mods-config/sql/counter/mysql/dailycounter.conf b/raddb/mods-config/sql/counter/mysql/dailycounter.conf
new file mode 100644
index 0000000..67c7f35
--- /dev/null
+++ b/raddb/mods-config/sql/counter/mysql/dailycounter.conf
@@ -0,0 +1,46 @@
+#
+# This query properly handles calls that span from the
+# previous reset period into the current period but
+# involves more work for the SQL server than those
+# below
+#
+query = "\
+ SELECT SUM(acctsessiontime - GREATEST((%%b - UNIX_TIMESTAMP(acctstarttime)), 0)) \
+ FROM radacct \
+ WHERE username = '%{${key}}' \
+ AND UNIX_TIMESTAMP(acctstarttime) + acctsessiontime > '%%b'"
+
+#
+# This query ignores calls that started in a previous
+# reset period and continue into into this one. But it
+# is a little easier on the SQL server
+#
+#query = "\
+# SELECT SUM(acctsessiontime) \
+# FROM radacct \
+# WHERE username = '%{${key}}' \
+# AND acctstarttime > FROM_UNIXTIME('%%b')"
+
+#
+# This query is the same as above, but demonstrates an
+# additional counter parameter '%%e' which is the
+# timestamp for the end of the period
+#
+#query = "\
+# SELECT SUM(acctsessiontime) \
+# FROM radacct \
+# WHERE username = '%{${key}}' \
+# AND acctstarttime BETWEEN FROM_UNIXTIME('%%b') AND FROM_UNIXTIME('%%e')"
+
+#
+# This query allows retrieving the entries based on a
+# period that resets on a particular day of the month.
+#
+#reset_day = 21
+#query = "\
+# SELECT SUM(acctsessiontime) FROM radacct WHERE username = '%{${key}}' AND \
+# IF (DAY(CURDATE()) >= ${reset_day}, \
+# acctstarttime > DATE(DATE_FORMAT(NOW(), '%Y-%m-${reset_day}')), \
+# acctstarttime > DATE(DATE_FORMAT(NOW() - INTERVAL 1 MONTH, '%Y-%m-${reset_day}')) \
+# )"
+#
diff --git a/raddb/mods-config/sql/counter/mysql/expire_on_login.conf b/raddb/mods-config/sql/counter/mysql/expire_on_login.conf
new file mode 100644
index 0000000..73e2ca3
--- /dev/null
+++ b/raddb/mods-config/sql/counter/mysql/expire_on_login.conf
@@ -0,0 +1,6 @@
+query = "\
+ SELECT IFNULL( MAX(TIME_TO_SEC(TIMEDIFF(NOW(), acctstarttime))),0) \
+ FROM radacct \
+ WHERE UserName='%{${key}}' \
+ ORDER BY acctstarttime \
+ LIMIT 1;"
diff --git a/raddb/mods-config/sql/counter/mysql/monthlycounter.conf b/raddb/mods-config/sql/counter/mysql/monthlycounter.conf
new file mode 100644
index 0000000..8999765
--- /dev/null
+++ b/raddb/mods-config/sql/counter/mysql/monthlycounter.conf
@@ -0,0 +1,34 @@
+#
+# This query properly handles calls that span from the
+# previous reset period into the current period but
+# involves more work for the SQL server than those
+# below
+#
+query = "\
+ SELECT SUM(acctsessiontime - GREATEST((%%b - UNIX_TIMESTAMP(acctstarttime)), 0)) \
+ FROM radacct \
+ WHERE username='%{${key}}' \
+ AND UNIX_TIMESTAMP(acctstarttime) + acctsessiontime > '%%b'"
+
+#
+# This query ignores calls that started in a previous
+# reset period and continue into into this one. But it
+# is a little easier on the SQL server
+#
+#query = "\
+# SELECT SUM(acctsessiontime) \
+# FROM radacct\
+# WHERE username='%{${key}}' \
+# AND acctstarttime > FROM_UNIXTIME('%%b')"
+
+#
+# This query is the same as above, but demonstrates an
+# additional counter parameter '%%e' which is the
+# timestamp for the end of the period
+#
+#query = "\
+# SELECT SUM(acctsessiontime) \
+# FROM radacct \
+# WHERE username='%{${key}}' \
+# AND acctstarttime BETWEEN FROM_UNIXTIME('%%b') \
+# AND FROM_UNIXTIME('%%e')"
diff --git a/raddb/mods-config/sql/counter/mysql/noresetcounter.conf b/raddb/mods-config/sql/counter/mysql/noresetcounter.conf
new file mode 100644
index 0000000..abcb21b
--- /dev/null
+++ b/raddb/mods-config/sql/counter/mysql/noresetcounter.conf
@@ -0,0 +1,4 @@
+query = "\
+ SELECT IFNULL(SUM(AcctSessionTime),0) \
+ FROM radacct \
+ WHERE UserName='%{${key}}'"
diff --git a/raddb/mods-config/sql/counter/mysql/weeklycounter.conf b/raddb/mods-config/sql/counter/mysql/weeklycounter.conf
new file mode 100644
index 0000000..bf8a4c4
--- /dev/null
+++ b/raddb/mods-config/sql/counter/mysql/weeklycounter.conf
@@ -0,0 +1,11 @@
+#
+# This query properly handles calls that span from the
+# previous reset period into the current period but
+# involves more work for the SQL server than those
+# below
+#
+query = "\
+ SELECT SUM(acctsessiontime - GREATEST((%%b - UNIX_TIMESTAMP(acctstarttime)), 0)) \
+ FROM radacct \
+ WHERE username = '%{${key}}' \
+ AND UNIX_TIMESTAMP(acctstarttime) + acctsessiontime > '%%b'"
diff --git a/raddb/mods-config/sql/counter/postgresql/dailycounter.conf b/raddb/mods-config/sql/counter/postgresql/dailycounter.conf
new file mode 100644
index 0000000..1e2f7fa
--- /dev/null
+++ b/raddb/mods-config/sql/counter/postgresql/dailycounter.conf
@@ -0,0 +1,34 @@
+#
+# This query properly handles calls that span from the
+# previous reset period into the current period but
+# involves more work for the SQL server than those
+# below
+#
+query = "\
+ SELECT SUM(AcctSessionTime - GREATEST((%%b - EXTRACT(epoch FROM AcctStartTime)), 0)) \
+ FROM radacct \
+ WHERE UserName='%{${key}}' \
+ AND EXTRACT(epoch FROM AcctStartTime) + AcctSessionTime > '%%b'"
+
+#
+# This query ignores calls that started in a previous
+# reset period and continue into into this one. But it
+# is a little easier on the SQL server
+#
+#query = "\
+# SELECT SUM(AcctSessionTime) \
+# FROM radacct \
+# WHERE UserName='%{${key}}' \
+# AND EXTRACT(epoch FROM AcctStartTime) > '%%b'"
+
+#
+# This query is the same as above, but demonstrates an
+# additional counter parameter '%%e' which is the
+# timestamp for the end of the period
+#
+#query = "\
+# SELECT SUM(AcctSessionTime) \
+# FROM radacct \
+# WHERE UserName='%{${key}}' \
+# AND EXTRACT(epoch FROM AcctStartTime) BETWEEN '%%b' \
+# AND '%%e'"
diff --git a/raddb/mods-config/sql/counter/postgresql/expire_on_login.conf b/raddb/mods-config/sql/counter/postgresql/expire_on_login.conf
new file mode 100644
index 0000000..6ec4c4e
--- /dev/null
+++ b/raddb/mods-config/sql/counter/postgresql/expire_on_login.conf
@@ -0,0 +1,6 @@
+query = "\
+ SELECT EXTRACT(EPOCH FROM (NOW() - acctstarttime)) \
+ FROM radacct \
+ WHERE UserName='%{${key}}' \
+ ORDER BY acctstarttime \
+ LIMIT 1;"
diff --git a/raddb/mods-config/sql/counter/postgresql/monthlycounter.conf b/raddb/mods-config/sql/counter/postgresql/monthlycounter.conf
new file mode 100644
index 0000000..cdaf83a
--- /dev/null
+++ b/raddb/mods-config/sql/counter/postgresql/monthlycounter.conf
@@ -0,0 +1,31 @@
+# This query properly handles calls that span from the
+# previous reset period into the current period but
+# involves more work for the SQL server than those
+# below
+query = "\
+ SELECT SUM(AcctSessionTime - GREATEST((%%b - EXTRACT(epoch FROM AcctStartTime)), 0)) \
+ FROM radacct \
+ WHERE UserName='%{${key}}' \
+ AND EXTRACT(epoch FROM AcctStartTime) + AcctSessionTime > '%%b'"
+
+#
+# This query ignores calls that started in a previous
+# reset period and continue into into this one. But it
+# is a little easier on the SQL server
+#
+#query = "\
+# SELECT SUM(AcctSessionTime) \
+# FROM radacct \
+# WHERE UserName='%{${key}}' \
+# AND EXTRACT(epoch FROM AcctStartTime) > '%%b'"
+
+#
+# This query is the same as above, but demonstrates an
+# additional counter parameter '%%e' which is the
+# timestamp for the end of the period
+#
+#query = "\
+# SELECT SUM(AcctSessionTime) \
+# FROM radacct \
+# WHERE UserName='%{${key}}' \
+# AND EXTRACT(epoch FROM AcctStartTime) BETWEEN '%%b' AND '%%e'"
diff --git a/raddb/mods-config/sql/counter/postgresql/noresetcounter.conf b/raddb/mods-config/sql/counter/postgresql/noresetcounter.conf
new file mode 100644
index 0000000..ac5182e
--- /dev/null
+++ b/raddb/mods-config/sql/counter/postgresql/noresetcounter.conf
@@ -0,0 +1,4 @@
+query = "\
+ SELECT SUM(AcctSessionTime) \
+ FROM radacct \
+ WHERE UserName='%{${key}}'"
diff --git a/raddb/mods-config/sql/counter/postgresql/weeklycounter.conf b/raddb/mods-config/sql/counter/postgresql/weeklycounter.conf
new file mode 100644
index 0000000..0d809c1
--- /dev/null
+++ b/raddb/mods-config/sql/counter/postgresql/weeklycounter.conf
@@ -0,0 +1,12 @@
+#
+# This query properly handles calls that span from the
+# previous reset period into the current period but
+# involves more work for the SQL server than those
+# below
+#
+query = "\
+ SELECT SUM(AcctSessionTime - GREATEST((%%b - EXTRACT(epoch FROM AcctStartTime)), 0)) \
+ FROM radacct \
+ WHERE UserName='%{${key}}' \
+ AND EXTRACT(epoch FROM AcctStartTime) + AcctSessionTime > '%%b'"
+
diff --git a/raddb/mods-config/sql/counter/sqlite/dailycounter.conf b/raddb/mods-config/sql/counter/sqlite/dailycounter.conf
new file mode 100644
index 0000000..9a2ec38
--- /dev/null
+++ b/raddb/mods-config/sql/counter/sqlite/dailycounter.conf
@@ -0,0 +1,33 @@
+#
+# This query properly handles calls that span from the
+# previous reset period into the current period but
+# involves more work for the SQL server than those
+# below
+#
+query = "\
+ SELECT SUM(acctsessiontime - GREATEST((%%b - strftime('%%s', acctstarttime)), 0)) \
+ FROM radacct \
+ WHERE username = '%{${key}}' \
+ AND (strftime('%%s', acctstarttime) + acctsessiontime) > %%b"
+
+#
+# This query ignores calls that started in a previous
+# reset period and continue into into this one. But it
+# is a little easier on the SQL server
+#
+#query = "\
+# SELECT SUM(acctsessiontime) \
+# FROM radacct \
+# WHERE \username = '%{${key}}' \
+# AND acctstarttime > %%b"
+
+#
+# This query is the same as above, but demonstrates an
+# additional counter parameter '%%e' which is the
+# timestamp for the end of the period
+#
+#query = "\
+# SELECT SUM(acctsessiontime) FROM radacct \
+# WHERE username = '%{${key}}' \
+# AND acctstarttime BETWEEN %%b \
+# AND %%e"
diff --git a/raddb/mods-config/sql/counter/sqlite/expire_on_login.conf b/raddb/mods-config/sql/counter/sqlite/expire_on_login.conf
new file mode 100644
index 0000000..f4e95a5
--- /dev/null
+++ b/raddb/mods-config/sql/counter/sqlite/expire_on_login.conf
@@ -0,0 +1,6 @@
+query = "\
+ SELECT GREATEST(strftime('%%s', NOW()) - strftime('%%s', acctstarttime), 0) AS expires \
+ FROM radacct \
+ WHERE username = '%{${key}}' \
+ ORDER BY acctstarttime \
+ LIMIT 1;"
diff --git a/raddb/mods-config/sql/counter/sqlite/monthlycounter.conf b/raddb/mods-config/sql/counter/sqlite/monthlycounter.conf
new file mode 100644
index 0000000..5262097
--- /dev/null
+++ b/raddb/mods-config/sql/counter/sqlite/monthlycounter.conf
@@ -0,0 +1,34 @@
+#
+# This query properly handles calls that span from the
+# previous reset period into the current period but
+# involves more work for the SQL server than those
+# below
+#
+query = "\
+ SELECT SUM(acctsessiontime - GREATEST((%%b - strftime('%%s', acctstarttime)), 0)) \
+ FROM radacct \
+ WHERE username = '%{${key}}' AND \
+ (strftime('%%s', acctstarttime) + acctsessiontime) > %%b"
+
+#
+# This query ignores calls that started in a previous
+# reset period and continue into into this one. But it
+# is a little easier on the SQL server
+#
+#query = "\
+# SELECT SUM(acctsessiontime) \
+# FROM radacct \
+# WHERE username = '%{${key}}' \
+# AND acctstarttime > %%b"
+
+#
+# This query is the same as above, but demonstrates an
+# additional counter parameter '%%e' which is the
+# timestamp for the end of the period
+#
+#query = "\
+# SELECT SUM(acctsessiontime) \
+# FROM radacct \
+# WHERE username = '%{${key}}' \
+# AND acctstarttime BETWEEN %%b \
+# AND %%e"
diff --git a/raddb/mods-config/sql/counter/sqlite/noresetcounter.conf b/raddb/mods-config/sql/counter/sqlite/noresetcounter.conf
new file mode 100644
index 0000000..ac2d869
--- /dev/null
+++ b/raddb/mods-config/sql/counter/sqlite/noresetcounter.conf
@@ -0,0 +1,4 @@
+query = "\
+ SELECT IFNULL(SUM(acctsessiontime),0) \
+ FROM radacct \
+ WHERE username = '%{${key}}'"
diff --git a/raddb/mods-config/sql/counter/sqlite/weeklycounter.conf b/raddb/mods-config/sql/counter/sqlite/weeklycounter.conf
new file mode 100644
index 0000000..06ce3b6
--- /dev/null
+++ b/raddb/mods-config/sql/counter/sqlite/weeklycounter.conf
@@ -0,0 +1,12 @@
+#
+# This query properly handles calls that span from the
+# previous reset period into the current period but
+# involves more work for the SQL server than those
+# below
+#
+query = "\
+ SELECT SUM(acctsessiontime - GREATEST((%%b - strftime('%%s', acctstarttime)), 0)) \
+ FROM radacct \
+ WHERE username = '%{${key}}' \
+ AND (strftime('%%s', acctstarttime) + acctsessiontime) > %%b"
+
diff --git a/raddb/mods-config/sql/cui/mysql/queries.conf b/raddb/mods-config/sql/cui/mysql/queries.conf
new file mode 100644
index 0000000..f8f18ca
--- /dev/null
+++ b/raddb/mods-config/sql/cui/mysql/queries.conf
@@ -0,0 +1,50 @@
+# -*- text -*-
+#
+# cui/mysql/queries.conf -- Queries to update a MySQL CUI table.
+#
+# $Id$
+
+post-auth {
+ query = "\
+ INSERT IGNORE INTO ${..cui_table} \
+ (clientipaddress, callingstationid, username, cui, lastaccounting) \
+ VALUES \
+ ('%{%{Packet-Src-IPv6-Address}:-%{Packet-Src-IP-Address}}', '%{Calling-Station-Id}', \
+ '%{User-Name}', '%{reply:Chargeable-User-Identity}', NULL) \
+ ON DUPLICATE KEY UPDATE \
+ lastaccounting='0000-00-00 00:00:00', \
+ cui='%{reply:Chargeable-User-Identity}'"
+
+}
+
+accounting {
+ reference = "%{tolower:type.%{Acct-Status-Type}.query}"
+ type {
+ start {
+ query = "\
+ UPDATE ${....cui_table} SET \
+ lastaccounting = CURRENT_TIMESTAMP \
+ WHERE clientipaddress = '%{%{Packet-Src-IPv6-Address}:-%{Packet-Src-IP-Address}}' \
+ AND callingstationid = '%{Calling-Station-Id}' \
+ AND username = '%{User-Name}' \
+ AND cui = '%{Chargeable-User-Identity}'"
+ }
+ interim-update {
+ query ="\
+ UPDATE ${....cui_table} SET \
+ lastaccounting = CURRENT_TIMESTAMP \
+ WHERE clientipaddress = '%{%{Packet-Src-IPv6-Address}:-%{Packet-Src-IP-Address}}' \
+ AND callingstationid = '%{Calling-Station-Id}' \
+ AND username = '%{User-Name}' \
+ AND cui = '%{Chargeable-User-Identity}'"
+ }
+ stop {
+ query ="\
+ DELETE FROM ${....cui_table} \
+ WHERE clientipaddress = '%{%{Packet-Src-IPv6-Address}:-%{Packet-Src-IP-Address}}' \
+ AND callingstationid = '%{Calling-Station-Id}' \
+ AND username = '%{User-Name}' \
+ AND cui = '%{Chargeable-User-Identity}'"
+ }
+ }
+}
diff --git a/raddb/mods-config/sql/cui/mysql/schema.sql b/raddb/mods-config/sql/cui/mysql/schema.sql
new file mode 100644
index 0000000..da9b2f7
--- /dev/null
+++ b/raddb/mods-config/sql/cui/mysql/schema.sql
@@ -0,0 +1,9 @@
+CREATE TABLE `cui` (
+ `clientipaddress` varchar(46) NOT NULL default '',
+ `callingstationid` varchar(50) NOT NULL default '',
+ `username` varchar(64) NOT NULL default '',
+ `cui` varchar(32) NOT NULL default '',
+ `creationdate` timestamp NOT NULL default CURRENT_TIMESTAMP,
+ `lastaccounting` timestamp NOT NULL default '0000-00-00 00:00:00',
+ PRIMARY KEY (`username`,`clientipaddress`,`callingstationid`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
diff --git a/raddb/mods-config/sql/cui/postgresql/queries.conf b/raddb/mods-config/sql/cui/postgresql/queries.conf
new file mode 100644
index 0000000..6c2215f
--- /dev/null
+++ b/raddb/mods-config/sql/cui/postgresql/queries.conf
@@ -0,0 +1,47 @@
+# -*- text -*-
+#
+# cui/postgresql/queries.conf -- Queries to update a PostgreSQL CUI table.
+#
+# $Id$
+
+post-auth {
+ query = "\
+ INSERT INTO ${..cui_table} \
+ (clientipaddress, callingstationid, username, cui) \
+ VALUES \
+ ('%{%{Packet-Src-IPv6-Address}:-%{Packet-Src-IP-Address}}', '%{Calling-Station-Id}', \
+ '%{User-Name}', '%{reply:Chargeable-User-Identity}')"
+
+}
+
+accounting {
+ reference = "%{tolower:type.%{Acct-Status-Type}.query}"
+ type {
+ start {
+ query = "\
+ UPDATE ${....cui_table} SET \
+ lastaccounting = now() \
+ WHERE clientipaddress = '%{%{Packet-Src-IPv6-Address}:-%{Packet-Src-IP-Address}}' \
+ AND callingstationid = '%{Calling-Station-Id}' \
+ AND username = '%{User-Name}' \
+ AND cui = '%{Chargeable-User-Identity}'"
+ }
+ interim-update {
+ query ="\
+ UPDATE ${....cui_table} SET \
+ lastaccounting = now() \
+ WHERE clientipaddress = '%{%{Packet-Src-IPv6-Address}:-%{Packet-Src-IP-Address}}' \
+ AND callingstationid = '%{Calling-Station-Id}' \
+ AND username = '%{User-Name}' \
+ AND cui = '%{Chargeable-User-Identity}'"
+ }
+ stop {
+ query ="\
+ DELETE FROM ${....cui_table} \
+ WHERE clientipaddress = '%{%{Packet-Src-IPv6-Address}:-%{Packet-Src-IP-Address}}' \
+ AND callingstationid = '%{Calling-Station-Id}' \
+ AND username = '%{User-Name}' \
+ AND cui = '%{Chargeable-User-Identity}'"
+ }
+ }
+}
diff --git a/raddb/mods-config/sql/cui/postgresql/schema.sql b/raddb/mods-config/sql/cui/postgresql/schema.sql
new file mode 100644
index 0000000..3b24401
--- /dev/null
+++ b/raddb/mods-config/sql/cui/postgresql/schema.sql
@@ -0,0 +1,14 @@
+CREATE TABLE cui (
+ clientipaddress INET NOT NULL DEFAULT '0.0.0.0',
+ callingstationid varchar(50) NOT NULL DEFAULT '',
+ username varchar(64) NOT NULL DEFAULT '',
+ cui varchar(32) NOT NULL DEFAULT '',
+ creationdate TIMESTAMP with time zone NOT NULL default 'now()',
+ lastaccounting TIMESTAMP with time zone NOT NULL default '-infinity'::timestamp,
+ PRIMARY KEY (username, clientipaddress, callingstationid)
+);
+
+CREATE RULE postauth_query AS ON INSERT TO cui
+ WHERE EXISTS(SELECT 1 FROM cui WHERE (username, clientipaddress, callingstationid)=(NEW.username, NEW.clientipaddress, NEW.callingstationid))
+ DO INSTEAD UPDATE cui SET lastaccounting ='-infinity'::timestamp with time zone, cui=NEW.cui WHERE (username, clientipaddress, callingstationid)=(NEW.username, NEW.clientipaddress, NEW.callingstationid);
+
diff --git a/raddb/mods-config/sql/cui/sqlite/queries.conf b/raddb/mods-config/sql/cui/sqlite/queries.conf
new file mode 100644
index 0000000..41741eb
--- /dev/null
+++ b/raddb/mods-config/sql/cui/sqlite/queries.conf
@@ -0,0 +1,47 @@
+# -*- text -*-
+#
+# cui/sqlite/queries.conf -- Queries to update a sqlite CUI table.
+#
+# $Id$
+
+post-auth {
+ query = "\
+ INSERT OR REPLACE INTO ${..cui_table} \
+ (clientipaddress, callingstationid, username, cui, lastaccounting) \
+ VALUES \
+ ('%{%{Packet-Src-IPv6-Address}:-%{Packet-Src-IP-Address}}', '%{Calling-Station-Id}', \
+ '%{User-Name}', '%{reply:Chargeable-User-Identity}', NULL)"
+
+}
+
+accounting {
+ reference = "%{tolower:type.%{Acct-Status-Type}.query}"
+ type {
+ start {
+ query = "\
+ UPDATE ${....cui_table} SET \
+ lastaccounting = CURRENT_TIMESTAMP \
+ WHERE clientipaddress = '%{%{Packet-Src-IPv6-Address}:-%{Packet-Src-IP-Address}}' \
+ AND callingstationid = '%{Calling-Station-Id}' \
+ AND username = '%{User-Name}' \
+ AND cui = '%{Chargeable-User-Identity}'"
+ }
+ interim-update {
+ query ="\
+ UPDATE ${....cui_table} SET \
+ lastaccounting = CURRENT_TIMESTAMP \
+ WHERE clientipaddress = '%{%{Packet-Src-IPv6-Address}:-%{Packet-Src-IP-Address}}' \
+ AND callingstationid = '%{Calling-Station-Id}' \
+ AND username = '%{User-Name}' \
+ AND cui = '%{Chargeable-User-Identity}'"
+ }
+ stop {
+ query ="\
+ DELETE FROM ${....cui_table} \
+ WHERE clientipaddress = '%{%{Packet-Src-IPv6-Address}:-%{Packet-Src-IP-Address}}' \
+ AND callingstationid = '%{Calling-Station-Id}' \
+ AND username = '%{User-Name}' \
+ AND cui = '%{Chargeable-User-Identity}'"
+ }
+ }
+}
diff --git a/raddb/mods-config/sql/cui/sqlite/schema.sql b/raddb/mods-config/sql/cui/sqlite/schema.sql
new file mode 100644
index 0000000..8473534
--- /dev/null
+++ b/raddb/mods-config/sql/cui/sqlite/schema.sql
@@ -0,0 +1,9 @@
+CREATE TABLE `cui` (
+ `clientipaddress` varchar(46) NOT NULL default '',
+ `callingstationid` varchar(50) NOT NULL default '',
+ `username` varchar(64) NOT NULL default '',
+ `cui` varchar(32) NOT NULL default '',
+ `creationdate` timestamp NOT NULL default CURRENT_TIMESTAMP,
+ `lastaccounting` timestamp NOT NULL default '0000-00-00 00:00:00',
+ PRIMARY KEY (`username`,`clientipaddress`,`callingstationid`)
+);
diff --git a/raddb/mods-config/sql/dhcp/mssql/queries.conf b/raddb/mods-config/sql/dhcp/mssql/queries.conf
new file mode 100644
index 0000000..8345c70
--- /dev/null
+++ b/raddb/mods-config/sql/dhcp/mssql/queries.conf
@@ -0,0 +1,52 @@
+# -*- text -*-
+#
+# dhcp/mssql/queries.conf -- MSSQL configuration for DHCP schema (schema.sql)
+#
+# $Id$
+
+# Safe characters list for sql queries. Everything else is replaced
+# with their mime-encoded equivalents.
+# The default list should be ok
+# safe_characters = "@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_: /"
+
+#######################################################################
+# Query config: Identifier
+#######################################################################
+# This is the identifier that will get substituted, escaped, and added
+# as attribute 'SQL-User-Name'. '%{SQL-User-Name}' should be used
+# below everywhere an identifier substitution is needed so you you can
+# be sure the identifier passed from the client is escaped properly.
+#
+sql_user_name = "%{control:DHCP-SQL-Option-Identifier}"
+
+#######################################################################
+# Attribute Lookup Queries
+#######################################################################
+# These queries setup the reply items in ${dhcpreply_table} and
+# ${group_reply_query}. You can use any query/tables you want, but
+# the return data for each row MUST be in the following order:
+#
+# 0. Row ID (currently unused)
+# 1. Identifier
+# 2. Item Attr Name
+# 3. Item Attr Value
+# 4. Item Attr Operation
+#######################################################################
+
+authorize_reply_query = "\
+ SELECT id, Identifier, Attribute, Value, op \
+ FROM ${dhcpreply_table} \
+ WHERE Identifier = '%{SQL-User-Name}' AND Context = '%{control:DHCP-SQL-Option-Context}' \
+ ORDER BY id"
+
+authorize_group_reply_query = "\
+ SELECT id, GroupName, Attribute, Value, op \
+ FROM ${groupreply_table} \
+ WHERE GroupName = '%{${group_attribute}}' AND Context = '%{control:DHCP-SQL-Option-Context}' \
+ ORDER BY id"
+
+group_membership_query = "\
+ SELECT GroupName \
+ FROM ${dhcpgroup_table} \
+ WHERE Identifier='%{SQL-User-Name}' AND Context = '%{control:DHCP-SQL-Option-Context}' \
+ ORDER BY priority"
diff --git a/raddb/mods-config/sql/dhcp/mssql/schema.sql b/raddb/mods-config/sql/dhcp/mssql/schema.sql
new file mode 100644
index 0000000..8584949
--- /dev/null
+++ b/raddb/mods-config/sql/dhcp/mssql/schema.sql
@@ -0,0 +1,91 @@
+-- $Id$
+--
+-- MSSQL schema for DHCP for FreeRADIUS
+--
+-- To load:
+-- isql -S db_ip_addr -d db_name -U db_login -P db_passwd -i schema.sql
+
+--
+-- Table structure for table 'dhcpgroupreply'
+--
+CREATE TABLE [dhcpgroupreply] (
+ [id] [int] IDENTITY (1, 1) NOT NULL,
+ [GroupName] [varchar] (64) NOT NULL,
+ [Attribute] [varchar] (32) NOT NULL,
+ [Value] [varchar] (253) NOT NULL,
+ [op] [char] (2) NULL,
+ [prio] [int] NOT NULL,
+ [Context] [varchar] (16) NOT NULL
+) ON [PRIMARY]
+GO
+
+ALTER TABLE [dhcpgroupreply] WITH NOCHECK ADD
+ CONSTRAINT [DF_dhcpgroupreply_GroupName] DEFAULT ('') FOR [GroupName],
+ CONSTRAINT [DF_dhcpgroupreply_Attribute] DEFAULT ('') FOR [Attribute],
+ CONSTRAINT [DF_dhcpgroupreply_Value] DEFAULT ('') FOR [Value],
+ CONSTRAINT [DF_dhcpgroupreply_op] DEFAULT (null) FOR [op],
+ CONSTRAINT [DF_dhcpgroupreply_prio] DEFAULT (0) FOR [prio],
+ CONSTRAINT [DF_dhcpgroupreply_context] DEFAULT ('') FOR [Context],
+ CONSTRAINT [PK_dhcpgroupreply] PRIMARY KEY NONCLUSTERED
+ (
+ [id]
+ ) ON [PRIMARY]
+GO
+
+CREATE INDEX [GroupName] ON [dhcpgroupreply]([Context],[GroupName]) ON [PRIMARY]
+GO
+
+
+--
+-- Table structure for table 'dhcpreply'
+--
+CREATE TABLE [dhcpreply] (
+ [id] [int] IDENTITY (1, 1) NOT NULL,
+ [Identifier] [varchar] (64) NOT NULL,
+ [Attribute] [varchar] (32) NOT NULL,
+ [Value] [varchar] (253) NOT NULL,
+ [op] [char] (2) NULL,
+ [Context] [varchar] (16) NOT NULL
+) ON [PRIMARY]
+GO
+
+ALTER TABLE [dhcpreply] WITH NOCHECK ADD
+ CONSTRAINT [DF_dhcpreply_Identifier] DEFAULT ('') FOR [Identifier],
+ CONSTRAINT [DF_dhcpreply_Attribute] DEFAULT ('') FOR [Attribute],
+ CONSTRAINT [DF_dhcpreply_Value] DEFAULT ('') FOR [Value],
+ CONSTRAINT [DF_dhcpreply_op] DEFAULT (null) FOR [op],
+ CONSTRAINT [DF_dhcpreply_Context] DEFAULT ('') FOR [Context],
+ CONSTRAINT [PK_dhcpreply] PRIMARY KEY NONCLUSTERED
+ (
+ [id]
+ ) ON [PRIMARY]
+GO
+
+CREATE INDEX [Identifier] ON [dhcpreply]([Context],[Identifier]) ON [PRIMARY]
+GO
+
+
+--
+-- Table structure for table 'dhcpgroup'
+--
+CREATE TABLE [dhcpgroup] (
+ [id] [int] IDENTITY (1, 1) NOT NULL,
+ [Identifier] [varchar] (64) NOT NULL,
+ [GroupName] [varchar] (64) NULL,
+ [Priority] [int] NULL,
+ [Context] [varchar] (16) NULL
+) ON [PRIMARY]
+GO
+
+ALTER TABLE [dhcpgroup] WITH NOCHECK ADD
+ CONSTRAINT [DF_dhcpgroup_Identifier] DEFAULT ('') FOR [Identifier],
+ CONSTRAINT [DF_dhcpgroup_GroupName] DEFAULT ('') FOR [GroupName],
+ CONSTRAINT [DF_dhcpgroup_Context] DEFAULT ('') FOR [Context],
+ CONSTRAINT [PK_dhcpgroup] PRIMARY KEY NONCLUSTERED
+ (
+ [id]
+ ) ON [PRIMARY]
+GO
+
+CREATE INDEX [Identifier] ON [dhcpgroup]([Context],[Identifier]) ON [PRIMARY]
+GO
diff --git a/raddb/mods-config/sql/dhcp/mysql/queries.conf b/raddb/mods-config/sql/dhcp/mysql/queries.conf
new file mode 100644
index 0000000..a28037b
--- /dev/null
+++ b/raddb/mods-config/sql/dhcp/mysql/queries.conf
@@ -0,0 +1,75 @@
+# -*- text -*-
+#
+# dhcp/mysql/queries.conf -- MySQL configuration for DHCP schema (schema.sql)
+#
+# $Id$
+
+# Use the driver specific SQL escape method.
+#
+# If you enable this configuration item, the "safe_characters"
+# configuration is ignored. FreeRADIUS then uses the PostgreSQL escape
+# functions to escape input strings. The only downside to making this
+# change is that the PostgreSQL escaping method is not the same the one
+# used by FreeRADIUS. So characters which are NOT in the
+# "safe_characters" list will now be stored differently in the database.
+#
+#auto_escape = yes
+
+# Safe characters list for sql queries. Everything else is replaced
+# with their mime-encoded equivalents.
+# The default list should be ok
+# Using 'auto_escape' is preferred
+safe_characters = "@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_: /"
+
+#######################################################################
+# Connection config
+#######################################################################
+# The character set is not configurable. The default character set of
+# the mysql client library is used. To control the character set,
+# create/edit my.cnf (typically in /etc/mysql/my.cnf or /etc/my.cnf)
+# and enter
+# [client]
+# default-character-set = utf8
+#
+
+#######################################################################
+# Query config: Identifier
+#######################################################################
+# This is the identifier that will get substituted, escaped, and added
+# as attribute 'SQL-User-Name'. '%{SQL-User-Name}' should be used
+# below everywhere an identifier substitution is needed so you you can
+# be sure the identifier passed from the client is escaped properly.
+#
+sql_user_name = "%{control:DHCP-SQL-Option-Identifier}"
+
+#######################################################################
+# Attribute Lookup Queries
+#######################################################################
+# These queries setup the reply items in ${dhcpreply_table} and
+# ${group_reply_query}. You can use any query/tables you want, but
+# the return data for each row MUST be in the following order:
+#
+# 0. Row ID (currently unused)
+# 1. Identifier
+# 2. Item Attr Name
+# 3. Item Attr Value
+# 4. Item Attr Operation
+#######################################################################
+
+authorize_reply_query = "\
+ SELECT id, identifier, attribute, value, Op \
+ FROM ${dhcpreply_table} \
+ WHERE identifier = '%{SQL-User-Name}' AND context = '%{control:DHCP-SQL-Option-Context}' \
+ ORDER BY id"
+
+authorize_group_reply_query = "\
+ SELECT id, groupname, attribute, value, op \
+ FROM ${groupreply_table} \
+ WHERE groupname = '%{${group_attribute}}' AND context = '%{control:DHCP-SQL-Option-Context}' \
+ ORDER BY id"
+
+group_membership_query = "\
+ SELECT groupnme \
+ FROM ${dhcpgroup_table} \
+ WHERE identifier='%{SQL-User-Name}' AND context = '%{control:DHCP-SQL-Option-Context}' \
+ ORDER BY priority"
diff --git a/raddb/mods-config/sql/dhcp/mysql/schema.sql b/raddb/mods-config/sql/dhcp/mysql/schema.sql
new file mode 100644
index 0000000..85a121a
--- /dev/null
+++ b/raddb/mods-config/sql/dhcp/mysql/schema.sql
@@ -0,0 +1,47 @@
+#
+# $Id$
+#
+# PostgreSQL schema for DHCP for FreeRADIUS
+#
+#
+
+#
+# Table structure for table 'dhcpgroupreply'
+#
+CREATE TABLE IF NOT EXISTS dhcpgroupreply (
+ 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 '',
+ context varchar(16) NOT NULL default '',
+ PRIMARY KEY (id),
+ KEY groupname (context,groupname(32))
+);
+
+#
+# Table structure for table 'dhcpreply'
+#
+CREATE TABLE IF NOT EXISTS dhcpreply (
+ id int(11) unsigned NOT NULL auto_increment,
+ identifier varchar(253) NOT NULL default '',
+ attribute varchar(64) NOT NULL default '',
+ op char(2) NOT NULL DEFAULT '=',
+ value varchar(253) NOT NULL default '',
+ context varchar(16) NOT NULL default '',
+ PRIMARY KEY (id),
+ KEY identifier (context,identifier(32))
+);
+
+#
+# Table structure for table 'dhcpgroup'
+#
+CREATE TABLE IF NOT EXISTS dhcpgroup (
+ id int(11) unsigned NOT NULL auto_increment,
+ identifier varchar(253) NOT NULL default '',
+ groupname varchar(64) NOT NULL default '',
+ priority int(11) NOT NULL default '1',
+ context varchar(16) NOT NULL default '',
+ PRIMARY KEY (id),
+ KEY identifier (context,identifier(32))
+);
diff --git a/raddb/mods-config/sql/dhcp/mysql/setup.sql b/raddb/mods-config/sql/dhcp/mysql/setup.sql
new file mode 100644
index 0000000..d20a82c
--- /dev/null
+++ b/raddb/mods-config/sql/dhcp/mysql/setup.sql
@@ -0,0 +1,21 @@
+/*
+ * setup.sql -- MySQL commands for creating the RADIUS user.
+ *
+ * WARNING: You should change 'localhost' and 'radpass'
+ * to something else. Also update raddb/mods-available/sql
+ * 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'@'localhost' IDENTIFIED BY 'radpass';
+
+GRANT SELECT ON radius.dhcpreply TO 'radius'@'localhost';
+GRANT SELECT ON radius.dhcpgroupreply TO 'radius'@'localhost';
+GRANT SELECT ON radius.dhcpgroup TO 'radius'@'localhost';
diff --git a/raddb/mods-config/sql/dhcp/oracle/queries.conf b/raddb/mods-config/sql/dhcp/oracle/queries.conf
new file mode 100644
index 0000000..dd312d5
--- /dev/null
+++ b/raddb/mods-config/sql/dhcp/oracle/queries.conf
@@ -0,0 +1,47 @@
+# -*- text -*-
+#
+# dhcp/oracle/queries.conf -- Oracle configuration for DHCP schema (schema.sql)
+#
+# $Id$
+
+#######################################################################
+# Query config: Identifier
+#######################################################################
+# This is the identifier that will get substituted, escaped, and added
+# as attribute 'SQL-User-Name'. '%{SQL-User-Name}' should be used
+# below everywhere an identifier substitution is needed so you you can
+# be sure the identifier passed from the client is escaped properly.
+#
+sql_user_name = "%{control:DHCP-SQL-Option-Identifier}"
+
+#######################################################################
+# Attribute Lookup Queries
+#######################################################################
+# These queries setup the reply items in ${dhcpreply_table} and
+# ${group_reply_query}. You can use any query/tables you want, but
+# the return data for each row MUST be in the following order:
+#
+# 0. Row ID (currently unused)
+# 1. Identifier
+# 2. Item Attr Name
+# 3. Item Attr Value
+# 4. Item Attr Operation
+#######################################################################
+
+authorize_reply_query = "\
+ SELECT id, identifier, attribute, value, op \
+ FROM ${dhcpreply_table} \
+ WHERE identifier = '%{SQL-User-Name}' AND context = '%{control:DHCP-SQL-Option-Context}' \
+ ORDER BY id"
+
+authorize_group_reply_query = "\
+ SELECT id, groupname, attribute, value, op \
+ FROM ${groupreply_table} \
+ WHERE groupname = '%{${group_attribute}}' AND context = '%{control:DHCP-SQL-Option-Context}' \
+ ORDER BY id"
+
+group_membership_query = "\
+ SELECT groupname \
+ FROM ${dhcpgroup_table} \
+ WHERE identifier='%{SQL-User-Name}' AND context = '%{control:DHCP-SQL-Option-Context}' \
+ ORDER BY priority"
diff --git a/raddb/mods-config/sql/dhcp/oracle/schema.sql b/raddb/mods-config/sql/dhcp/oracle/schema.sql
new file mode 100644
index 0000000..085e346
--- /dev/null
+++ b/raddb/mods-config/sql/dhcp/oracle/schema.sql
@@ -0,0 +1,81 @@
+/*
+ * $Id$
+ *
+ * Oracle schema for DHCP for FreeRADIUS
+ *
+ */
+
+/*
+ * Table structure for table 'dhcpgroupreply'
+ */
+CREATE TABLE dhcpgroupreply (
+ id INT PRIMARY KEY,
+ groupname VARCHAR(64) NOT NULL,
+ attribute VARCHAR(64) NOT NULL,
+ op CHAR(2) NOT NULL,
+ value VARCHAR(253) NOT NULL,
+ context VARCHAR(16) NOT NULL
+);
+CREATE INDEX dhcpgroupreply_idx1 ON dhcpgroupreply(context,groupname);
+CREATE SEQUENCE dhcpgroupreply_seq START WITH 1 INCREMENT BY 1;
+
+/* Trigger to emulate a serial # on the primary key */
+CREATE OR REPLACE TRIGGER dhcpgroupreply_serialnumber
+ BEFORE INSERT OR UPDATE OF id ON dhcpgroupreply
+ FOR EACH ROW
+ BEGIN
+ if ( :new.id = 0 or :new.id is null ) then
+ SELECT dhcpgroupreply_seq.nextval into :new.id from dual;
+ end if;
+ END;
+/
+
+/*
+ * Table structure for table 'dhcpreply'
+ */
+CREATE TABLE dhcpreply (
+ id INT PRIMARY KEY,
+ identifier VARCHAR(253) NOT NULL,
+ attribute VARCHAR(64) NOT NULL,
+ op CHAR(2) NOT NULL,
+ value VARCHAR(253) NOT NULL,
+ context VARCHAR(16) NOT NULL
+);
+CREATE INDEX dhcpreply_idx1 ON dhcpreply(context,identifier);
+CREATE SEQUENCE dhcpreply_seq START WITH 1 INCREMENT BY 1;
+
+/* Trigger to emulate a serial # on the primary key */
+CREATE OR REPLACE TRIGGER dhcpreply_serialnumber
+ BEFORE INSERT OR UPDATE OF id ON dhcpreply
+ FOR EACH ROW
+ BEGIN
+ if ( :new.id = 0 or :new.id is null ) then
+ SELECT dhcpreply_seq.nextval into :new.id from dual;
+ end if;
+ END;
+/
+
+/*
+ * Table structure for table 'dhcpgroup'
+ */
+CREATE TABLE dhcpgroup (
+ id INT PRIMARY KEY,
+ identifier VARCHAR(253) NOT NULL,
+ groupname VARCHAR(64) NOT NULL,
+ priority INT NOT NULL,
+ context VARCHAR(16) NOT NULL
+);
+CREATE INDEX dhcpgroup_idx1 ON dhcpgroup(context,identifier);
+CREATE SEQUENCE dhcpgroup_seq START WITH 1 INCREMENT BY 1;
+
+/* Trigger to emulate a serial # on the primary key */
+CREATE OR REPLACE TRIGGER dhcpgroup_serialnumber
+ BEFORE INSERT OR UPDATE OF id ON dhcpgroup
+ FOR EACH ROW
+ BEGIN
+ if ( :new.id = 0 or :new.id is null ) then
+ SELECT dhcpgroup_seq.nextval into :new.id from dual;
+ end if;
+ END;
+/
+
diff --git a/raddb/mods-config/sql/dhcp/postgresql/queries.conf b/raddb/mods-config/sql/dhcp/postgresql/queries.conf
new file mode 100644
index 0000000..14ca79a
--- /dev/null
+++ b/raddb/mods-config/sql/dhcp/postgresql/queries.conf
@@ -0,0 +1,76 @@
+# -*- text -*-
+#
+# dhcp/postgresql/queries.conf -- PostgreSQL configuration for DHCP schema (schema.sql)
+#
+# $Id$
+
+# Use the driver specific SQL escape method.
+#
+# If you enable this configuration item, the "safe_characters"
+# configuration is ignored. FreeRADIUS then uses the PostgreSQL escape
+# functions to escape input strings. The only downside to making this
+# change is that the PostgreSQL escaping method is not the same the one
+# used by FreeRADIUS. So characters which are NOT in the
+# "safe_characters" list will now be stored differently in the database.
+#
+#auto_escape = yes
+
+# Safe characters list for sql queries. Everything else is replaced
+# with their mime-encoded equivalents.
+# The default list should be ok
+# Using 'auto_escape' is preferred
+# safe_characters = "@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_: /"
+
+#######################################################################
+# Query config: Identifier
+#######################################################################
+# This is the identifier that will get substituted, escaped, and added
+# as attribute 'SQL-User-Name'. '%{SQL-User-Name}' should be used
+# below everywhere an identifier substitution is needed so you you can
+# be sure the identifier passed from the client is escaped properly.
+#
+sql_user_name = "%{control:DHCP-SQL-Option-Identifier}"
+
+#######################################################################
+# Open Query
+#######################################################################
+# This query is run whenever a new connection is opened.
+# It is commented out by default.
+#
+# If you have issues with connections hanging for too long, uncomment
+# the next line, and set the timeout in milliseconds. As a general
+# rule, if the queries take longer than a second, something is wrong
+# with the database.
+#open_query = "set statement_timeout to 1000"
+
+#######################################################################
+# Attribute Lookup Queries
+#######################################################################
+# These queries setup the reply items in ${dhcpreply_table} and
+# ${group_reply_query}. You can use any query/tables you want, but
+# the return data for each row MUST be in the following order:
+#
+# 0. Row ID (currently unused)
+# 1. Identifier
+# 2. Item Attr Name
+# 3. Item Attr Value
+# 4. Item Attr Operation
+#######################################################################
+
+authorize_reply_query = "\
+ SELECT id, Identifier, Attribute, Value, Op \
+ FROM ${dhcpreply_table} \
+ WHERE Identifier = '%{SQL-User-Name}' AND Context = '%{control:DHCP-SQL-Option-Context}' \
+ ORDER BY id"
+
+authorize_group_reply_query = "\
+ SELECT id, GroupName, Attribute, Value, op \
+ FROM ${groupreply_table} \
+ WHERE GroupName = '%{${group_attribute}}' AND Context = '%{control:DHCP-SQL-Option-Context}' \
+ ORDER BY id"
+
+group_membership_query = "\
+ SELECT GroupName \
+ FROM ${dhcpgroup_table} \
+ WHERE Identifier='%{SQL-User-Name}' AND Context = '%{control:DHCP-SQL-Option-Context}' \
+ ORDER BY priority"
diff --git a/raddb/mods-config/sql/dhcp/postgresql/schema.sql b/raddb/mods-config/sql/dhcp/postgresql/schema.sql
new file mode 100644
index 0000000..0d1727f
--- /dev/null
+++ b/raddb/mods-config/sql/dhcp/postgresql/schema.sql
@@ -0,0 +1,44 @@
+/*
+ * $Id$
+ *
+ * PostgreSQL schema for DHCP for FreeRADIUS
+ *
+ */
+
+/*
+ * Table structure for table 'dhcpgroupreply'
+ */
+CREATE TABLE IF NOT EXISTS dhcpgroupreply (
+ 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 '',
+ Context text NOT NULL DEFAULT ''
+);
+CREATE INDEX dhcpgroupreply_GroupName ON dhcpgroupreply (Context,GroupName,Attribute);
+
+/*
+ * Table structure for table 'dhcpreply'
+ */
+CREATE TABLE IF NOT EXISTS dhcpreply (
+ id serial PRIMARY KEY,
+ Identifier text NOT NULL DEFAULT '',
+ Attribute text NOT NULL DEFAULT '',
+ op VARCHAR(2) NOT NULL DEFAULT '=',
+ Value text NOT NULL DEFAULT '',
+ Context text NOT NULL DEFAULT ''
+);
+CREATE INDEX dhcpreply_Identifier ON dhcpreply (Context,Identifier,Attribute);
+
+/*
+ * Table structure for table 'dhcpgroup'
+ */
+CREATE TABLE IF NOT EXISTS dhcpgroup (
+ id serial PRIMARY KEY,
+ Identifier text NOT NULL DEFAULT '',
+ GroupName text NOT NULL DEFAULT '',
+ Priority integer NOT NULL DEFAULT 0,
+ Context text NOT NULL DEFAULT ''
+);
+CREATE INDEX dhcpgroup_Identifier ON dhcpgroup (Context,Identifier);
diff --git a/raddb/mods-config/sql/dhcp/postgresql/setup.sql b/raddb/mods-config/sql/dhcp/postgresql/setup.sql
new file mode 100644
index 0000000..884aa5a
--- /dev/null
+++ b/raddb/mods-config/sql/dhcp/postgresql/setup.sql
@@ -0,0 +1,28 @@
+/*
+ * admin.sql -- PostgreSQL commands for creating the RADIUS user.
+ *
+ * WARNING: You should change 'localhost' and 'radpass'
+ * to something else. Also update raddb/mods-available/sql
+ * 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';
+
+/*
+ * The server can read any table in SQL
+ */
+GRANT SELECT ON dhcpreply TO radius;
+GRANT SELECT ON dhcpgroupreply TO radius;
+GRANT SELECT ON dhcpgroup TO radius;
+
+GRANT USAGE, SELECT ON SEQUENCE dhcpgroupreply_id_seq TO radius;
+GRANT USAGE, SELECT ON SEQUENCE dhcpreply_id_seq TO radius;
+GRANT USAGE, SELECT ON SEQUENCE dhcpgroup_id_seq TO radius;
diff --git a/raddb/mods-config/sql/dhcp/sqlite/queries.conf b/raddb/mods-config/sql/dhcp/sqlite/queries.conf
new file mode 100644
index 0000000..0cc7202
--- /dev/null
+++ b/raddb/mods-config/sql/dhcp/sqlite/queries.conf
@@ -0,0 +1,52 @@
+# -*- text -*-
+#
+# dhcp/sqlite/queries.conf -- SQLite configuration for DHCP schema (schema.sql)
+#
+# $Id$
+
+# Safe characters list for sql queries. Everything else is replaced
+# with their mime-encoded equivalents.
+# The default list should be ok
+# safe_characters = "@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_: /"
+
+#######################################################################
+# Query config: Identifier
+#######################################################################
+# This is the identifier that will get substituted, escaped, and added
+# as attribute 'SQL-User-Name'. '%{SQL-User-Name}' should be used
+# below everywhere an identifier substitution is needed so you you can
+# be sure the identifier passed from the client is escaped properly.
+#
+sql_user_name = "%{control:DHCP-SQL-Option-Identifier}"
+
+#######################################################################
+# Attribute Lookup Queries
+#######################################################################
+# These queries setup the reply items in ${dhcpreply_table} and
+# ${group_reply_query}. You can use any query/tables you want, but
+# the return data for each row MUST be in the following order:
+#
+# 0. Row ID (currently unused)
+# 1. Identifier
+# 2. Item Attr Name
+# 3. Item Attr Value
+# 4. Item Attr Operation
+#######################################################################
+
+authorize_reply_query = "\
+ SELECT id, identifier, attribute, value, op \
+ FROM ${dhcpreply_table} \
+ WHERE identifier = '%{SQL-User-Name}' AND context = '%{control:DHCP-SQL-Option-Context}' \
+ ORDER BY id"
+
+authorize_group_reply_query = "\
+ SELECT id, groupname, attribute, value, op \
+ FROM ${groupreply_table} \
+ WHERE groupname = '%{${group_attribute}}' AND context = '%{control:DHCP-SQL-Option-Context}' \
+ ORDER BY id"
+
+group_membership_query = "\
+ SELECT groupname \
+ FROM ${dhcpgroup_table} \
+ WHERE identifier='%{SQL-User-Name}' AND context = '%{control:DHCP-SQL-Option-Context}' \
+ ORDER BY priority"
diff --git a/raddb/mods-config/sql/dhcp/sqlite/schema.sql b/raddb/mods-config/sql/dhcp/sqlite/schema.sql
new file mode 100644
index 0000000..54a9abb
--- /dev/null
+++ b/raddb/mods-config/sql/dhcp/sqlite/schema.sql
@@ -0,0 +1,46 @@
+-----------------------------------------------------------------------------
+-- $Id$ â‰Â·Â·Â·Â· --
+-- --
+-- schema.sql rlm_sql - FreeRADIUS SQLite Module --
+-- --
+-- Database schema for SQLite rlm_sql module for DHCP --
+-- --
+-----------------------------------------------------------------------------
+
+--
+-- Table structure for table 'dhcpgroupreply'
+--
+CREATE TABLE IF NOT EXISTS dhcpgroupreply (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ groupname varchar(64) NOT NULL default '',
+ attribute varchar(64) NOT NULL default '',
+ op char(2) NOT NULL DEFAULT '=',
+ value varchar(253) NOT NULL default '',
+ context varchar(16) NOT NULL default ''
+);
+CREATE INDEX dhcpgroupreply_groupname ON dhcpgroupreply(context,groupname);
+
+--
+-- Table structure for table 'dhcpreply'
+--
+CREATE TABLE IF NOT EXISTS dhcpreply (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ identifier varchar(253) NOT NULL default '',
+ attribute varchar(64) NOT NULL default '',
+ op char(2) NOT NULL DEFAULT '=',
+ value varchar(253) NOT NULL default '',
+ context varchar(16) NOT NULL default ''
+);
+CREATE INDEX dhcpreply_identifier ON dhcpreply(context,identifier);
+
+--
+-- Table structure for table 'dhcpgroup'
+--
+CREATE TABLE IF NOT EXISTS dhcpgroup (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ identifier varchar(253) NOT NULL default '',
+ groupname varchar(64) NOT NULL default '',
+ priority int(11) NOT NULL default '1',
+ context varchar(16) NOT NULL default ''
+);
+CREATE INDEX dhcpgroup_identifier ON dhcpgroup(context,identifier);
diff --git a/raddb/mods-config/sql/ippool-dhcp/mssql/procedure.sql b/raddb/mods-config/sql/ippool-dhcp/mssql/procedure.sql
new file mode 100644
index 0000000..4cfbe1c
--- /dev/null
+++ b/raddb/mods-config/sql/ippool-dhcp/mssql/procedure.sql
@@ -0,0 +1,159 @@
+--
+-- A stored procedure to reallocate a user's previous address, otherwise
+-- provide a free address.
+--
+-- Using this SP reduces the usual set dialogue of queries to a single
+-- query:
+--
+-- BEGIN TRAN; "SELECT FOR UPDATE"; UPDATE; COMMIT TRAN; -> EXEC sp
+--
+-- The stored procedure is executed on an database instance within a single
+-- round trip which often leads to reduced deadlocking and significant
+-- performance improvements especially on multi-master clusters, perhaps even
+-- by an order of magnitude or more.
+--
+-- To use this stored procedure the corresponding queries.conf statements must
+-- be configured as follows:
+--
+-- allocate_begin = ""
+-- allocate_find = "\
+-- EXEC fr_dhcp_allocate_previous_or_new_framedipaddress \
+-- @v_pool_name = '%{control:${pool_name}}', \
+-- @v_gateway = '%{DHCP-Gateway-IP-Address}', \
+-- @v_pool_key = '${pool_key}', \
+-- @v_lease_duration = ${lease_duration}, \
+-- @v_requested_address = '%{%{${req_attribute_name}}:-0.0.0.0}' \
+-- "
+-- allocate_update = ""
+-- allocate_commit = ""
+--
+
+CREATE OR ALTER PROCEDURE fr_dhcp_allocate_previous_or_new_framedipaddress
+ @v_pool_name VARCHAR(64),
+ @v_gateway VARCHAR(15),
+ @v_pool_key VARCHAR(64),
+ @v_lease_duration INT,
+ @v_requested_address VARCHAR(15)
+AS
+ BEGIN
+
+ -- MS SQL lacks a "SELECT FOR UPDATE" statement, and its table
+ -- hints do not provide a direct means to implement the row-level
+ -- read lock needed to guarentee that concurrent queries do not
+ -- select the same Framed-IP-Address for allocation to distinct
+ -- users.
+ --
+ -- The "WITH cte AS ( SELECT ... ) UPDATE cte ... OUTPUT INTO"
+ -- patterns in this procedure body compensate by wrapping
+ -- the SELECT in a synthetic UPDATE which locks the row.
+
+ DECLARE @r_address_tab TABLE(id VARCHAR(15));
+ DECLARE @r_address VARCHAR(15);
+
+ BEGIN TRAN;
+
+ -- Reissue an existing IP address lease when re-authenticating a session
+ --
+ WITH cte AS (
+ SELECT TOP(1) FramedIPAddress
+ FROM dhcpippool WITH (rowlock, readpast)
+ JOIN dhcpstatus
+ ON dhcpstatus.status_id = dhcpippool.status_id
+ WHERE pool_name = @v_pool_name
+ AND expiry_time > CURRENT_TIMESTAMP
+ AND pool_key = @v_pool_key
+ AND dhcpstatus.status IN ('dynamic', 'static')
+ )
+ UPDATE cte
+ SET FramedIPAddress = FramedIPAddress
+ OUTPUT INSERTED.FramedIPAddress INTO @r_address_tab;
+ SELECT @r_address = id FROM @r_address_tab;
+
+ -- Reissue an user's previous IP address, provided that the lease is
+ -- available (i.e. enable sticky IPs)
+ --
+ -- When using this SELECT you should delete the one above. You must also
+ -- set allocate_clear = "" in queries.conf to persist the associations
+ -- for expired leases.
+ --
+ -- WITH cte AS (
+ -- SELECT TOP(1) FramedIPAddress
+ -- FROM dhcpippool WITH (rowlock, readpast)
+ -- JOIN dhcpstatus
+ -- ON dhcpstatus.status_id = dhcpippool.status_id
+ -- WHERE pool_name = @v_pool_name
+ -- AND pool_key = @v_pool_key
+ -- AND dhcpstatus.status IN ('dynamic', 'static')
+ -- )
+ -- UPDATE cte
+ -- SET FramedIPAddress = FramedIPAddress
+ -- OUTPUT INSERTED.FramedIPAddress INTO @r_address_tab;
+ -- SELECT @r_address = id FROM @r_address_tab;
+
+ -- Issue the requested IP address if it is available
+ --
+ IF @r_address IS NULL AND @v_requested_address <> '0.0.0.0'
+ BEGIN
+ WITH cte AS (
+ SELECT TOP(1) FramedIPAddress
+ FROM dhcpippool WITH (rowlock, readpast)
+ JOIN dhcpstatus
+ ON dhcpstatus.status_id = dhcpippool.status_id
+ WHERE pool_name = @v_pool_name
+ AND framedipaddress = @v_requested_address
+ AND dhcpstatus.status = 'dynamic'
+ AND ( pool_key = @v_pool_name OR expiry_time < CURRENT_TIMESTAMP )
+ )
+ UPDATE cte
+ SET FramedIPAddress = FramedIPAddress
+ OUTPUT INSERTED.FramedIPAddress INTO @r_address_tab;
+ SELECT @r_address = id FROM @r_address_tab;
+ END
+
+ -- If we didn't reallocate a previous address then pick the least
+ -- recently used address from the pool which maximises the likelihood
+ -- of re-assigning the other addresses to their recent user
+ --
+ IF @r_address IS NULL
+ BEGIN
+ WITH cte AS (
+ SELECT TOP(1) FramedIPAddress
+ FROM dhcpippool WITH (rowlock, readpast)
+ JOIN dhcpstatus
+ ON dhcpstatus.status_id = dhcpippool.status_id
+ WHERE pool_name = @v_pool_name
+ AND expiry_time < CURRENT_TIMESTAMP
+ AND dhcpstatus.status = 'dynamic'
+ ORDER BY
+ expiry_time
+ )
+ UPDATE cte
+ SET FramedIPAddress = FramedIPAddress
+ OUTPUT INSERTED.FramedIPAddress INTO @r_address_tab;
+ SELECT @r_address = id FROM @r_address_tab;
+ END
+
+ -- Return nothing if we failed to allocated an address
+ --
+ IF @r_address IS NULL
+ BEGIN
+ COMMIT TRAN;
+ RETURN;
+ END
+
+ -- Update the pool having allocated an IP address
+ --
+ UPDATE dhcpippool
+ SET
+ gateway = @v_gateway,
+ pool_key = @v_pool_key,
+ expiry_time = DATEADD(SECOND,@v_lease_duration,CURRENT_TIMESTAMP)
+ WHERE framedipaddress = @r_address;
+
+ COMMIT TRAN;
+
+ -- Return the address that we allocated
+ SELECT @r_address;
+
+ END
+GO
diff --git a/raddb/mods-config/sql/ippool-dhcp/mssql/queries.conf b/raddb/mods-config/sql/ippool-dhcp/mssql/queries.conf
new file mode 100644
index 0000000..c919e2d
--- /dev/null
+++ b/raddb/mods-config/sql/ippool-dhcp/mssql/queries.conf
@@ -0,0 +1,257 @@
+# -*- text -*-
+#
+# ippool-dhcp/mssql/queries.conf -- MSSQL queries for rlm_sqlippool
+#
+# $Id$
+
+# *****************
+# * DHCP DISCOVER *
+# *****************
+
+#
+# This series of queries allocates an IP address
+#
+
+#
+# MSSQL-specific syntax - required if finding the address and updating
+# it are separate queries
+#
+#allocate_begin = "BEGIN TRAN"
+#allocate_commit = "COMMIT TRAN"
+
+allocate_begin = ""
+allocate_commit = ""
+
+#
+# Attempt to find the most recent existing IP address for the client
+#
+allocate_existing = "\
+ WITH cte AS ( \
+ SELECT TOP(1) framedipaddress, expiry_time, gateway \
+ FROM ${ippool_table} WITH (xlock rowlock readpast) \
+ JOIN dhcpstatus ON ${ippool_table}.status_id = dhcpstatus.status_id \
+ WHERE pool_name = '%{control:${pool_name}}' \
+ AND pool_key = '${pool_key}' \
+ AND dhcpstatus.status IN ('dynamic', 'static') \
+ ORDER BY expiry_time DESC \
+ ) \
+ UPDATE cte \
+ SET expiry_time = DATEADD(SECOND,${offer_duration},CURRENT_TIMESTAMP), \
+ gateway = '%{DHCP-Gateway-IP-Address}' \
+ OUTPUT INSERTED.FramedIPAddress \
+ FROM ${ippool_table}"
+
+#
+# Determine whether the requested IP address is available
+#
+allocate_requested = "\
+ WITH cte AS ( \
+ SELECT TOP(1) framedipaddress, expiry_time, gateway \
+ FROM ${ippool_table} WITH (xlock rowlock readpast) \
+ JOIN dhcpstatus ON ${ippool_table}.status_id = dhcpstatus.status_id \
+ WHERE pool_name = '%{control:${pool_name}}' \
+ AND framedipaddress = '%{%{${req_attribute_name}}:-0.0.0.0}' \
+ AND dhcpstatus.status = 'dynamic' \
+ AND expiry_time < CURRENT_TIMESTAMP \
+ ) \
+ UPDATE cte \
+ SET expiry_time = DATEADD(SECOND,${offer_duration},CURRENT_TIMESTAMP), \
+ gateway = '%{DHCP-Gateway-IP-Address}', \
+ pool_key = '${pool_key}' \
+ OUTPUT INSERTED.FramedIPAddress \
+ FROM ${ippool_table}"
+
+#
+# If the existing address can't be found this query will be run to
+# find a free address
+#
+allocate_find = "\
+ WITH cte AS ( \
+ SELECT TOP(1) framedipaddress, expiry_time, gateway, pool_key \
+ FROM ${ippool_table} WITH (xlock rowlock readpast) \
+ JOIN dhcpstatus ON ${ippool_table}.status_id = dhcpstatus.status_id \
+ WHERE pool_name = '%{control:${pool_name}}' \
+ AND expiry_time < CURRENT_TIMESTAMP \
+ AND dhcpstatus.status = 'dynamic' \
+ ORDER BY expiry_time \
+ ) \
+ UPDATE cte \
+ SET expiry_time = DATEADD(SECOND,${offer_duration},CURRENT_TIMESTAMP), \
+ gateway = '%{DHCP-Gateway-IP-Address}', \
+ pool_key = '${pool_key}' \
+ OUTPUT INSERTED.FramedIPAddress \
+ FROM ${ippool_table}"
+
+#
+# Alternatively attempt all in one, more complex, query
+#
+# The ORDER BY clause of this query tries to allocate the same IP-address
+# which user had last session. Ensure that pool_key is unique to the user
+# within a given pool.
+#
+#allocate_find = "\
+# UPDATE TOP(1) ${ippool_table} \
+# SET FramedIPAddress = FramedIPAddress, \
+# pool_key = '${pool_key}', \
+# expiry_time = DATEADD(SECOND,${offer_duration},CURRENT_TIMESTAMP), \
+# GatewayIPAddress = '%{DHCP-Gateway-IP-Address}' \
+# OUTPUT INSERTED.FramedIPAddress \
+# FROM ${ippool_table} \
+# WHERE ${ippool_table}.id IN ( \
+# SELECT TOP (1) id FROM ( \
+# (SELECT TOP(1) id, 1 AS o FROM ${ippool_table} WITH (xlock rowlock readpast) \
+# JOIN dhcpstatus ON ${ippool_table}.status_id = dhcpstatus.status_id \
+# WHERE pool_name = '%{control:${pool_name}}' \
+# AND pool_key = '${pool_key}' \
+# AND dhcpstatus.status IN ('dynamic', 'static')) \
+# UNION \
+# (SELECT TOP(1) id, 2 AS o FROM ${ippool_table} WITH (xlock rowlock readpast) \
+# JOIN dhcpstatus ON ${ippool_table}.status_id = dhcpstatus.status_id \
+# WHERE pool_name = '%{control:${pool_name}}' \
+# AND framedipaddress = '%{%{${req_attribute_name}}:-0.0.0.0}' \
+# AND dhcpstatus.status = 'dynamic' \
+# AND ( pool_key = '%{pool_key}' OR expiry_time < CURRENT_TIMESTAMP )) \
+# UNION \
+# (SELECT TOP(1) id, 3 AS o FROM ${ippool_table} WITH (xlock rowlock readpast) \
+# JOIN dhcpstatus ON ${ippool_table}.status_id = dhcpstatus.status_id \
+# WHERE pool_name = '%{control:${pool_name}}' \
+# AND expiry_time < CURRENT_TIMESTAMP \
+# AND dhcpstatus.status = 'dynamic' \
+# ORDER BY expiry_time) \
+# ) AS q ORDER BY q.o \
+# )"
+
+#
+# If you prefer to allocate a random IP address every time, use this query instead.
+# Note: This is very slow if you have a lot of free IPs.
+#
+#allocate_find = "\
+# WITH cte AS ( \
+# SELECT TOP(1) FramedIPAddress FROM ${ippool_table} \
+# JOIN dhcpstatus ON ${ippool_table}.status_id = dhcpstatus.status_id \
+# WHERE pool_name = '%{control:${pool_name}}' \
+# AND expiry_time < CURRENT_TIMESTAMP \
+# AND dhcpstatus.status = 'dynamic' \
+# ORDER BY \
+# newid() \
+# ) \
+# UPDATE cte WITH (rowlock, readpast) \
+# SET FramedIPAddress = FramedIPAddress \
+# OUTPUT INSERTED.FramedIPAddress"
+
+#
+# If an IP could not be allocated, check to see if the pool exists or not
+# This allows the module to differentiate between a full pool and no pool
+# Note: If you are not running redundant pool modules this query may be
+# commented out to save running this query every time an ip is not allocated.
+#
+pool_check = "\
+ SELECT TOP(1) id \
+ FROM ${ippool_table} \
+ WHERE pool_name='%{control:${pool_name}}'"
+
+#
+# This is the final IP Allocation query, which saves the allocated ip details.
+# Only needed if the initial "find" query is not storing the allocation.
+#
+#allocate_update = "\
+# UPDATE ${ippool_table} \
+# SET \
+# gateway = '%{DHCP-Gateway-IP-Address}', pool_key = '${pool_key}', \
+# expiry_time = DATEADD(SECOND,${offer_duration},CURRENT_TIMESTAMP) \
+# WHERE FramedIPAddress = '%I'"
+
+#
+# Use a stored procedure to find AND allocate the address. Read and customise
+# `procedure.sql` in this directory to determine the optimal configuration.
+#
+#allocate_begin = ""
+#allocate_find = "\
+# EXEC fr_dhcp_allocate_previous_or_new_framedipaddress \
+# @v_pool_name = '%{control:${pool_name}}', \
+# @v_gateway = '%{DHCP-Gateway-IP-Address}', \
+# @v_pool_key = '${pool_key}', \
+# @v_lease_duration = ${offer_duration}, \
+# @v_requested_address = '%{%{${req_attribute_name}}:-0.0.0.0}' \
+# "
+#allocate_update = ""
+#allocate_commit = ""
+
+
+# ****************
+# * DHCP REQUEST *
+# ****************
+
+#
+# This query revokes any active offers for addresses that a client is not
+# requesting when a DHCP REQUEST packet arrives
+#
+start_update = "\
+ UPDATE ${ippool_table} \
+ SET \
+ gateway = '', \
+ pool_key = '', \
+ expiry_time = CURRENT_TIMESTAMP \
+ WHERE pool_name = '%{control:${pool_name}}' \
+ AND pool_key = '${pool_key}' \
+ AND framedipaddress <> '%{DHCP-Requested-IP-Address}' \
+ AND expiry_time > CURRENT_TIMESTAMP \
+ AND ${ippool_table}.status_id IN \
+ (SELECT status_id FROM dhcpstatus WHERE status = 'dynamic')"
+
+#
+# This query extends an existing lease (or offer) when a DHCP REQUEST packet
+# arrives. This query must update a row when a lease is succesfully requested
+# - queries that update no rows will result in a "notfound" response to
+# the module which by default will give a DHCP-NAK reply. In this example
+# incrementing "counter" is used to achieve this.
+#
+alive_update = "\
+ UPDATE ${ippool_table} \
+ SET \
+ expiry_time = DATEADD(SECOND,${lease_duration},CURRENT_TIMESTAMP), \
+ counter = counter + 1 \
+ WHERE pool_name = '%{control:${pool_name}}' \
+ AND pool_key = '${pool_key}' \
+ AND framedipaddress = '%{%{DHCP-Requested-IP-Address}:-%{DHCP-Client-IP-Address}}'"
+
+
+# ****************
+# * DHCP RELEASE *
+# ****************
+
+#
+# This query frees an IP address when a DHCP RELEASE packet arrives
+#
+stop_clear = "\
+ UPDATE ${ippool_table} \
+ SET \
+ gateway = '', \
+ pool_key = '', \
+ expiry_time = CURRENT_TIMESTAMP \
+ WHERE pool_name = '%{control:${pool_name}}' \
+ AND pool_key = '${pool_key}' \
+ AND FramedIPAddress = '%{DHCP-Client-IP-Address}' \
+ AND ${ippool_table}.status_id IN \
+ (SELECT status_id FROM dhcpstatus WHERE status = 'dynamic')"
+
+#
+# This query is not applicable to DHCP
+#
+on_clear = ""
+
+
+# ****************
+# * DHCP DECLINE *
+# ****************
+
+#
+# This query marks an IP address as declined when a DHCP Decline
+# packet arrives
+#
+off_clear = "\
+ UPDATE ${ippool_table} \
+ SET status_id = (SELECT status_id FROM dhcpstatus WHERE status = 'declined') \
+ WHERE pool_name = '%{control:${pool_name}}' \
+ AND pool_key = '${pool_key}' \
+ AND framedipaddress = '%{DHCP-Requested-IP-Address}'"
diff --git a/raddb/mods-config/sql/ippool-dhcp/mssql/schema.sql b/raddb/mods-config/sql/ippool-dhcp/mssql/schema.sql
new file mode 100644
index 0000000..dae4eff
--- /dev/null
+++ b/raddb/mods-config/sql/ippool-dhcp/mssql/schema.sql
@@ -0,0 +1,40 @@
+--
+-- Table structure for table 'dhcpippool'
+--
+-- See also "procedure.sql" in this directory for
+-- a stored procedure that gives much faster response.
+--
+
+CREATE TABLE dhcpstatus (
+ status_id int NOT NULL,
+ status varchar(10) NOT NULL,
+ PRIMARY KEY (status_id)
+)
+GO
+
+INSERT INTO dhcpstatus (status_id, status) VALUES (1, 'dynamic'), (2, 'static'), (3, 'declined'), (4, 'disabled')
+GO
+
+CREATE TABLE dhcpippool (
+ id int IDENTITY (1,1) NOT NULL,
+ pool_name varchar(30) NOT NULL,
+ FramedIPAddress varchar(15) NOT NULL default '',
+ pool_key varchar(30) NOT NULL default '',
+ gateway varchar(15) NOT NULL default '',
+ expiry_time DATETIME NOT NULL default CURRENT_TIMESTAMP,
+ status_id int NOT NULL default 1,
+ counter int NOT NULL default 0,
+ CONSTRAINT fk_status_id FOREIGN KEY (status_id) REFERENCES dhcpstatus (status_id),
+ PRIMARY KEY (id)
+)
+GO
+
+CREATE INDEX dhcp_poolname_expire ON dhcpippool(pool_name, expiry_time)
+GO
+
+CREATE INDEX dhcp_FramedIPAddress ON dhcpippool(FramedIPAddress)
+GO
+
+CREATE INDEX dhcp_poolname_poolkey_FramedIPAddress ON dhcpippool(pool_name, pool_key, FramedIPAddress)
+GO
+
diff --git a/raddb/mods-config/sql/ippool-dhcp/mysql/procedure-no-skip-locked.sql b/raddb/mods-config/sql/ippool-dhcp/mysql/procedure-no-skip-locked.sql
new file mode 100644
index 0000000..bee37de
--- /dev/null
+++ b/raddb/mods-config/sql/ippool-dhcp/mysql/procedure-no-skip-locked.sql
@@ -0,0 +1,160 @@
+--
+-- A stored procedure to reallocate a user's previous address, otherwise
+-- provide a free address.
+--
+-- NOTE: This version of the SP is intended for MySQL variants that do not
+-- support the SKIP LOCKED pragma, i.e. MariaDB and versions of MySQL
+-- prior to 8.0. It should be a lot faster than using the default SP
+-- without the SKIP LOCKED pragma under highly concurrent workloads
+-- and not result in thread starvation.
+--
+-- It is however a *useful hack* which should not be used if SKIP
+-- LOCKED is available.
+--
+-- WARNING: This query uses server-local, "user locks" (GET_LOCK and
+-- RELEASE_LOCK), without the need for a transaction, to emulate
+-- row locking with locked-row skipping. User locks are not
+-- supported on clusters such as Galera and MaxScale.
+--
+-- Using this SP reduces the usual set dialogue of queries to a single
+-- query:
+--
+-- START TRANSACTION; SELECT FOR UPDATE; UPDATE; COMMIT; -> CALL sp()
+--
+-- The stored procedure is executed within a single round trip which often
+-- leads to reduced deadlocking and significant performance improvements.
+--
+-- To use this stored procedure the corresponding queries.conf statements must
+-- be configured as follows:
+--
+-- allocate_begin = ""
+-- allocate_find = "\
+-- CALL fr_dhcp_allocate_previous_or_new_framedipaddress( \
+-- '%{control:${pool_name}}', \
+-- '%{DHCP-Gateway-IP-Address}', \
+-- '${pool_key}', \
+-- ${lease_duration}, \
+-- '%{%{${req_attribute_name}}:-0.0.0.0}' \
+-- )"
+-- allocate_update = ""
+-- allocate_commit = ""
+--
+
+DELIMITER $$
+
+DROP PROCEDURE IF EXISTS fr_dhcp_allocate_previous_or_new_framedipaddress;
+CREATE PROCEDURE fr_allocate_previous_or_new_framedipaddress (
+ IN v_pool_name VARCHAR(64),
+ IN v_gateway VARCHAR(15),
+ IN v_pool_key VARCHAR(64),
+ IN v_lease_duration INT,
+ IN v_requested_address VARCHAR(15)
+)
+SQL SECURITY INVOKER
+proc:BEGIN
+ DECLARE r_address VARCHAR(15);
+
+ -- Reissue an existing IP address lease when re-authenticating a session
+ --
+ -- Note: In this query we get away without the need for FOR UPDATE
+ -- becase:
+ --
+ -- (a) Each existing lease only belongs to a single device, so
+ -- no two devices will be racing over a single address.
+ -- (b) The set of existing leases (not yet expired) are
+ -- disjoint from the set of free leases, so not subject to
+ -- reallocation.
+ --
+ SELECT framedipaddress INTO r_address
+ FROM dhcpippool
+ WHERE pool_name = v_pool_name
+ AND expiry_time > NOW()
+ AND pool_key = v_pool_key
+ AND `status` IN ('dynamic', 'static')
+ LIMIT 1;
+
+ -- Reissue an user's previous IP address, provided that the lease is
+ -- available (i.e. enable sticky IPs)
+ --
+ -- When using this SELECT you should delete the one above. You must also
+ -- set allocate_clear = "" in queries.conf to persist the associations
+ -- for expired leases.
+ --
+ -- SELECT framedipaddress INTO r_address
+ -- FROM dhcpippool
+ -- WHERE pool_name = v_pool_name
+ -- AND pool_key = v_pool_key
+ -- AND `status` IN ('dynamic', 'static')
+ -- LIMIT 1;
+
+ --
+ -- Normally here we would honour an IP address hint if the IP were
+ -- available, however we cannot do that without taking a lock which
+ -- defeats the purpose of this version of the stored procedure.
+ --
+ -- It you need to honour an IP address hint then use a database with
+ -- support for SKIP LOCKED and use the normal stored procedure.
+ --
+
+ IF r_address IS NOT NULL THEN
+ UPDATE dhcpippool
+ SET
+ gateway = v_gateway,
+ pool_key = v_pool_key,
+ expiry_time = NOW() + INTERVAL v_lease_duration SECOND
+ WHERE
+ framedipaddress = r_address;
+ SELECT r_address;
+ LEAVE proc;
+ END IF;
+
+ REPEAT
+
+ -- If we didn't reallocate a previous address then pick the least
+ -- recently used address from the pool which maximises the likelihood
+ -- of re-assigning the other addresses to their recent user
+ --
+ SELECT framedipaddress INTO r_address
+ FROM dhcpippool
+ WHERE pool_name = v_pool_name
+ AND expiry_time < NOW()
+ AND `status` = 'dynamic'
+ --
+ -- WHERE ... GET_LOCK(...,0) = 1 is a poor man's SKIP LOCKED that simulates
+ -- a row-level lock using a "user lock" that allows the locked "rows" to be
+ -- skipped. After the user lock is acquired and the SELECT retired it does
+ -- not mean that the entirety of the WHERE clause is still true: Another
+ -- thread may have updated the expiry time and released the lock after we
+ -- checked the expiry_time but before we acquired the lock since SQL is free
+ -- to reorder the WHERE condition. Therefore we must recheck the condition
+ -- in the UPDATE statement below to detect this race.
+ --
+ AND GET_LOCK(CONCAT('dhcpippool_', framedipaddress), 0) = 1
+ LIMIT 1;
+
+ IF r_address IS NULL THEN
+ DO RELEASE_LOCK(CONCAT('dhcpippool_', r_address));
+ LEAVE proc;
+ END IF;
+
+ UPDATE dhcpippool
+ SET
+ gateway = v_gateway,
+ pool_key = v_pool_key,
+ expiry_time = NOW() + INTERVAL v_lease_duration SECOND
+ WHERE
+ framedipaddress = r_address
+ --
+ -- Here we re-evaluate the original condition for selecting the address
+ -- to detect a race, in which case we try again...
+ --
+ AND expiry_time<NOW();
+
+ UNTIL ROW_COUNT() <> 0 END REPEAT;
+
+ DO RELEASE_LOCK(CONCAT('dhcpippool_', r_address));
+ SELECT r_address;
+
+END$$
+
+DELIMITER ;
diff --git a/raddb/mods-config/sql/ippool-dhcp/mysql/procedure.sql b/raddb/mods-config/sql/ippool-dhcp/mysql/procedure.sql
new file mode 100644
index 0000000..b5dfae0
--- /dev/null
+++ b/raddb/mods-config/sql/ippool-dhcp/mysql/procedure.sql
@@ -0,0 +1,144 @@
+--
+-- A stored procedure to reallocate a user's previous address, otherwise
+-- provide a free address.
+--
+-- Using this SP reduces the usual set dialogue of queries to a single
+-- query:
+--
+-- START TRANSACTION; SELECT FOR UPDATE; UPDATE; COMMIT; -> CALL sp()
+--
+-- The stored procedure is executed on an database instance within a single
+-- round trip which often leads to reduced deadlocking and significant
+-- performance improvements especially on multi-master clusters, perhaps even
+-- by an order of magnitude or more.
+--
+-- To use this stored procedure the corresponding queries.conf statements must
+-- be configured as follows:
+--
+-- allocate_begin = ""
+-- allocate_find = "\
+-- CALL fr_dhcp_allocate_previous_or_new_framedipaddress( \
+-- '%{control:${pool_name}}', \
+-- '%{DHCP-Gateway-IP-Address}', \
+-- '${pool_key}', \
+-- ${lease_duration}, \
+-- '%{%{${req_attribute_name}}:-0.0.0.0}' \
+-- )"
+-- allocate_update = ""
+-- allocate_commit = ""
+--
+
+DELIMITER $$
+
+DROP PROCEDURE IF EXISTS fr_dhcp_allocate_previous_or_new_framedipaddress;
+CREATE PROCEDURE fr_dhcp_allocate_previous_or_new_framedipaddress (
+ IN v_pool_name VARCHAR(30),
+ IN v_gateway VARCHAR(15),
+ IN v_pool_key VARCHAR(30),
+ IN v_lease_duration INT,
+ IN v_requested_address VARCHAR(15)
+)
+SQL SECURITY INVOKER
+proc:BEGIN
+ DECLARE r_address VARCHAR(15);
+
+ DECLARE EXIT HANDLER FOR SQLEXCEPTION
+ BEGIN
+ ROLLBACK;
+ RESIGNAL;
+ END;
+
+ SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
+
+ START TRANSACTION;
+
+ -- Reissue an existing IP address lease when re-authenticating a session
+ --
+ SELECT framedipaddress INTO r_address
+ FROM dhcpippool
+ WHERE pool_name = v_pool_name
+ AND expiry_time > NOW()
+ AND pool_key = v_pool_key
+ AND `status` IN ('dynamic', 'static')
+ LIMIT 1
+ FOR UPDATE;
+-- FOR UPDATE SKIP LOCKED; -- Better performance, but limited support
+
+ -- NOTE: You should enable SKIP LOCKED here (as well as any other
+ -- instances) if your database server supports it. If it is not
+ -- supported and you are not running a multi-master cluster (e.g.
+ -- Galera or MaxScale) then you should instead consider using the
+ -- SP in procedure-no-skip-locked.sql which will be faster and
+ -- less likely to result in thread starvation under highly
+ -- concurrent load.
+
+ -- Reissue an user's previous IP address, provided that the lease is
+ -- available (i.e. enable sticky IPs)
+ --
+ -- When using this SELECT you should delete the one above. You must also
+ -- set allocate_clear = "" in queries.conf to persist the associations
+ -- for expired leases.
+ --
+ -- SELECT framedipaddress INTO r_address
+ -- FROM dhcpippool
+ -- WHERE pool_name = v_pool_name
+ -- AND pool_key = v_pool_key
+ -- AND `status` IN ('dynamic', 'static')
+ -- LIMIT 1
+ -- FOR UPDATE;
+ -- -- FOR UPDATE SKIP LOCKED; -- Better performance, but limited support
+
+ -- Issue the requested IP address if it is available
+ --
+ IF r_address IS NULL AND v_requested_address <> '0.0.0.0' THEN
+ SELECT framedipaddress INTO r_address
+ FROM dhcpippool
+ WHERE pool_name = v_pool_name
+ AND framedipaddress = v_requested_address
+ AND `status` = 'dynamic'
+ AND ( pool_key = v_pool_key OR expiry_time < NOW() )
+ FOR UPDATE;
+-- FOR UPDATE SKIP LOCKED; -- Better performance, but limited support
+ END IF;
+
+ -- If we didn't reallocate a previous address then pick the least
+ -- recently used address from the pool which maximises the likelihood
+ -- of re-assigning the other addresses to their recent user
+ --
+ IF r_address IS NULL THEN
+ SELECT framedipaddress INTO r_address
+ FROM dhcpippool
+ WHERE pool_name = v_pool_name
+ AND expiry_time < NOW()
+ AND `status` = 'dynamic'
+ ORDER BY
+ expiry_time
+ LIMIT 1
+ FOR UPDATE;
+-- FOR UPDATE SKIP LOCKED; -- Better performance, but limited support
+ END IF;
+
+ -- Return nothing if we failed to allocated an address
+ --
+ IF r_address IS NULL THEN
+ COMMIT;
+ LEAVE proc;
+ END IF;
+
+ -- Update the pool having allocated an IP address
+ --
+ UPDATE dhcpippool
+ SET
+ gateway = v_gateway,
+ pool_key = v_pool_key,
+ expiry_time = NOW() + INTERVAL v_lease_duration SECOND
+ WHERE framedipaddress = r_address;
+
+ COMMIT;
+
+ -- Return the address that we allocated
+ SELECT r_address;
+
+END$$
+
+DELIMITER ;
diff --git a/raddb/mods-config/sql/ippool-dhcp/mysql/queries.conf b/raddb/mods-config/sql/ippool-dhcp/mysql/queries.conf
new file mode 100644
index 0000000..6aaecb1
--- /dev/null
+++ b/raddb/mods-config/sql/ippool-dhcp/mysql/queries.conf
@@ -0,0 +1,221 @@
+# -*- text -*-
+#
+# ippool-dhcp/mysql/queries.conf -- MySQL queries for rlm_sqlippool
+#
+# $Id$
+
+# *****************
+# * DHCP DISCOVER *
+# *****************
+
+#
+# This series of queries allocates an IP address
+
+# If using MySQL < 8.0.1 then remove SKIP LOCKED
+#
+# Attempt to find the most recent existing IP address for the client
+#
+allocate_existing = "\
+ SELECT framedipaddress FROM ${ippool_table} \
+ WHERE pool_name = '%{control:${pool_name}}' \
+ AND pool_key = '${pool_key}' \
+ AND `status` IN ('dynamic', 'static') \
+ ORDER BY expiry_time DESC LIMIT 1 FOR UPDATE SKIP LOCKED"
+
+#
+# Determine whether the requested IP address is available
+#
+allocate_requested = "\
+ SELECT framedipaddress FROM ${ippool_table} \
+ WHERE pool_name = '%{control:${pool_name}}' \
+ AND framedipaddress = '%{%{${req_attribute_name}}:-0.0.0.0}' \
+ AND `status` = 'dynamic' \
+ AND expiry_time < NOW() \
+ FOR UPDATE SKIP LOCKED"
+
+#
+# If the existing address can't be found this query will be run to
+# find a free address
+#
+allocate_find = "\
+ SELECT framedipaddress FROM ${ippool_table} \
+ WHERE pool_name = '%{control:${pool_name}}' \
+ AND expiry_time < NOW() \
+ AND `status` = 'dynamic' \
+ ORDER BY expiry_time LIMIT 1 FOR UPDATE SKIP LOCKED"
+
+#
+# The ORDER BY clause of this query tries to allocate the same IP-address
+# which the user last had. Ensure that pool_key is unique to the user
+# within a given pool.
+#
+
+#
+# Alternatively do the operations in one query. Depending on transaction
+# isolation mode, this can cause deadlocks
+#
+#allocate_find = "\
+# (SELECT framedipaddress, 1 AS o FROM ${ippool_table} \
+# WHERE pool_name = '%{control:${pool_name}}' \
+# AND pool_key = '${pool_key}' \
+# AND `status` IN ('dynamic', 'static') \
+# ORDER BY expiry_time DESC LIMIT 1 FOR UPDATE SKIP LOCKED \
+# ) UNION ( \
+# SELECT framedipaddress, 2 AS o FROM ${ippool_table} \
+# WHERE pool_name = '%{control:${pool_name}}' \
+# AND framedipaddress = '%{%{${req_attribute_name}}:-0.0.0.0}' \
+# AND `status` = 'dynamic' \
+# AND ( pool_key = '${pool_key}' OR expiry_time < NOW() ) \
+# FOR UPDATE SKIP LOCKED \
+# ) UNION ( \
+# SELECT framedipaddress, 3 AS o FROM ${ippool_table} \
+# WHERE pool_name = '%{control:${pool_name}}' \
+# AND expiry_time < NOW() \
+# AND `status` = 'dynamic' \
+# ORDER BY expiry_time LIMIT 1 FOR UPDATE SKIP LOCKED \
+# ) ORDER BY o \
+# LIMIT 1"
+
+#
+# If you prefer to allocate a random IP address every time, use this query instead.
+# Note: This is very slow if you have a lot of free IPs.
+#
+#allocate_find = "\
+# SELECT framedipaddress FROM ${ippool_table} \
+# WHERE pool_name = '%{control:${pool_name}}' \
+# AND expiry_time < NOW() \
+# AND `status` = 'dynamic' \
+# ORDER BY \
+# RAND() \
+# LIMIT 1 \
+# FOR UPDATE"
+
+#
+# The above query again, but with SKIP LOCKED. This requires MySQL >= 8.0.1,
+# and InnoDB.
+#
+#allocate_find = "\
+# SELECT framedipaddress FROM ${ippool_table} \
+# WHERE pool_name = '%{control:${pool_name}}' \
+# AND expiry_time < NOW() \
+# AND `status` = 'dynamic' \
+# ORDER BY \
+# RAND() \
+# LIMIT 1 \
+# FOR UPDATE SKIP LOCKED"
+
+#
+# If an IP could not be allocated, check to see if the pool exists or not
+# This allows the module to differentiate between a full pool and no pool
+# Note: If you are not running redundant pool modules this query may be
+# commented out to save running this query every time an ip is not allocated.
+#
+pool_check = "\
+ SELECT id \
+ FROM ${ippool_table} \
+ WHERE pool_name='%{control:${pool_name}}' \
+ LIMIT 1"
+
+#
+# This is the final IP Allocation query, which saves the allocated ip details.
+#
+allocate_update = "\
+ UPDATE ${ippool_table} \
+ SET \
+ gateway = '%{DHCP-Gateway-IP-Address}', pool_key = '${pool_key}', \
+ expiry_time = NOW() + INTERVAL ${offer_duration} SECOND \
+ WHERE framedipaddress = '%I'"
+
+#
+# Use a stored procedure to find AND allocate the address. Read and customise
+# `procedure.sql` in this directory to determine the optimal configuration.
+#
+#allocate_begin = ""
+#allocate_find = "\
+# CALL fr_dhcp_allocate_previous_or_new_framedipaddress( \
+# '%{control:${pool_name}}', \
+# '%{DHCP-Gateway-IP-Address}', \
+# '${pool_key}', \
+# ${offer_duration}, \
+# '%{%{${req_attribute_name}}:-0.0.0.0}' \
+# )"
+#allocate_update = ""
+#allocate_commit = ""
+
+
+# ****************
+# * DHCP REQUEST *
+# ****************
+
+#
+# This query revokes any active offers for addresses that a client is not
+# requesting when a DHCP REQUEST packet arrives
+#
+start_update = "\
+ UPDATE ${ippool_table} \
+ SET \
+ gateway = '', \
+ pool_key = '', \
+ expiry_time = NOW() \
+ WHERE pool_name = '%{control:${pool_name}}' \
+ AND pool_key = '${pool_key}' \
+ AND framedipaddress <> '%{DHCP-Requested-IP-Address}' \
+ AND expiry_time > NOW() \
+ AND `status` = 'dynamic'"
+
+#
+# This query extends an existing lease (or offer) when a DHCP REQUEST packet
+# arrives. This query must update a row when a lease is succesfully requested
+# - queries that update no rows will result in a "notfound" response to
+# the module which by default will give a DHCP-NAK reply. In this example
+# incrementing "counter" is used to achieve this.
+#
+alive_update = "\
+ UPDATE ${ippool_table} \
+ SET \
+ expiry_time = NOW() + INTERVAL ${lease_duration} SECOND, \
+ counter = counter + 1 \
+ WHERE pool_name = '%{control:${pool_name}}' \
+ AND pool_key = '${pool_key}' \
+ AND framedipaddress = '%{%{DHCP-Requested-IP-Address}:-%{DHCP-Client-IP-Address}}'"
+
+
+# ****************
+# * DHCP RELEASE *
+# ****************
+
+#
+# This query frees an IP address when a DHCP RELEASE packet arrives
+#
+stop_clear = "\
+ UPDATE ${ippool_table} \
+ SET \
+ gateway = '', \
+ pool_key = '', \
+ expiry_time = NOW() \
+ WHERE pool_name = '%{control:${pool_name}}' \
+ AND pool_key = '${pool_key}' \
+ AND framedipaddress = '%{DHCP-Client-IP-Address}' \
+ AND `status` = 'dynamic'"
+
+
+#
+# This query is not applicable to DHCP
+#
+on_clear = ""
+
+
+# ****************
+# * DHCP DECLINE *
+# ****************
+
+#
+# This query marks an IP address as declined when a DHCP Decline
+# packet arrives
+#
+off_clear = "\
+ UPDATE ${ippool_table} \
+ SET status = 'declined' \
+ WHERE pool_name = '%{control:${pool_name}}' \
+ AND pool_key = '${pool_key}' \
+ AND framedipaddress = '%{DHCP-Requested-IP-Address}'"
diff --git a/raddb/mods-config/sql/ippool-dhcp/mysql/schema.sql b/raddb/mods-config/sql/ippool-dhcp/mysql/schema.sql
new file mode 100644
index 0000000..d8b1219
--- /dev/null
+++ b/raddb/mods-config/sql/ippool-dhcp/mysql/schema.sql
@@ -0,0 +1,21 @@
+--
+-- Table structure for table 'dhcpippool'
+--
+-- See also "procedure.sql" in this directory for a stored procedure
+-- that is much faster.
+--
+
+CREATE TABLE dhcpippool (
+ id int unsigned NOT NULL auto_increment,
+ pool_name varchar(30) NOT NULL,
+ framedipaddress varchar(15) NOT NULL default '',
+ pool_key varchar(30) NOT NULL default '',
+ gateway varchar(15) NOT NULL default '',
+ expiry_time DATETIME NOT NULL default NOW(),
+ `status` ENUM('dynamic', 'static', 'declined', 'disabled') DEFAULT 'dynamic',
+ counter int unsigned NOT NULL default 0,
+ PRIMARY KEY (id),
+ KEY dhcpippool_poolname_expire (pool_name, expiry_time),
+ KEY framedipaddress (framedipaddress),
+ KEY dhcpippool_poolname_poolkey_ipaddress (pool_name, pool_key, framedipaddress)
+) ENGINE=InnoDB;
diff --git a/raddb/mods-config/sql/ippool-dhcp/oracle/procedure.sql b/raddb/mods-config/sql/ippool-dhcp/oracle/procedure.sql
new file mode 100644
index 0000000..84b4596
--- /dev/null
+++ b/raddb/mods-config/sql/ippool-dhcp/oracle/procedure.sql
@@ -0,0 +1,217 @@
+--
+-- A stored procedure to reallocate a user's previous address, otherwise
+-- provide a free address.
+--
+-- Using this SP reduces the usual set dialogue of queries to a single
+-- query:
+--
+-- BEGIN; SELECT FOR UPDATE; UPDATE; COMMIT; -> SELECT sp() FROM dual
+--
+-- The stored procedure is executed on an database instance within a single
+-- round trip which often leads to reduced deadlocking and significant
+-- performance improvements especially on multi-master clusters, perhaps even
+-- by an order of magnitude or more.
+--
+-- To use this stored procedure the corresponding queries.conf statements must
+-- be configured as follows:
+--
+-- allocate_begin = ""
+-- allocate_find = "\
+-- SELECT fr_dhcp_allocate_previous_or_new_framedipaddress( \
+-- '%{control:${pool_name}}', \
+-- '%{DHCP-Gateway-IP-Address}', \
+-- '${pool_key}', \
+-- ${lease_duration}, \
+-- '%{%{${req_attribute_name}}:-0.0.0.0}' \
+-- ) FROM dual"
+-- allocate_update = ""
+-- allocate_commit = ""
+--
+
+CREATE OR REPLACE FUNCTION fr_dhcp_allocate_previous_or_new_framedipaddress (
+ v_pool_name IN VARCHAR2,
+ v_gateway IN VARCHAR2,
+ v_pool_key IN VARCHAR2,
+ v_lease_duration IN INTEGER,
+ v_requested_address IN VARCHAR2
+)
+RETURN varchar2 IS
+ PRAGMA AUTONOMOUS_TRANSACTION;
+ r_address varchar2(15);
+BEGIN
+
+ -- Reissue an existing IP address lease when re-authenticating a session
+ --
+ BEGIN
+ SELECT framedipaddress INTO r_address FROM dhcpippool WHERE id IN (
+ SELECT id FROM (
+ SELECT *
+ FROM dhcpippool
+ JOIN dhcpstatus
+ ON dhcpstatus.status_id = dhcpippool.status_id
+ WHERE pool_name = v_pool_name
+ AND expiry_time > current_timestamp
+ AND pool_key = v_pool_key
+ AND dhcpstatus.status IN ('dynamic', 'static')
+ ) WHERE ROWNUM <= 1
+ ) FOR UPDATE SKIP LOCKED;
+ EXCEPTION
+ WHEN NO_DATA_FOUND THEN
+ r_address := NULL;
+ END;
+
+ -- Oracle >= 12c version of the above query
+ --
+ -- BEGIN
+ -- SELECT framedipaddress INTO r_address FROM dhcpippool WHERE id IN (
+ -- SELECT id FROM dhcpippool
+ -- JOIN dhcpstatus
+ -- ON dhcpstatus.status_id = dhcpippool.status_id
+ -- WHERE pool_name = v_pool_name
+ -- AND expiry_time > current_timestamp
+ -- AND pool_key = v_pool_key
+ -- AND dhcpstatus.status IN ('dynamic', 'static')
+ -- FETCH FIRST 1 ROWS ONLY
+ -- ) FOR UPDATE SKIP LOCKED;
+ -- EXCEPTION
+ -- WHEN NO_DATA_FOUND THEN
+ -- r_address := NULL;
+ -- END;
+
+
+
+ -- Reissue an user's previous IP address, provided that the lease is
+ -- available (i.e. enable sticky IPs)
+ --
+ -- When using this SELECT you should delete the one above. You must also
+ -- set allocate_clear = "" in queries.conf to persist the associations
+ -- for expired leases.
+ --
+ -- BEGIN
+ -- SELECT framedipaddress INTO r_address FROM dhcpippool WHERE id IN (
+ -- SELECT id FROM (
+ -- SELECT *
+ -- FROM dhcpippool
+ -- JOIN dhcpstatus
+ -- ON dhcpstatus.status_id = dhcpippool.status_id
+ -- WHERE pool_name = v_pool_name
+ -- AND pool_key = v_pool_key
+ -- AND dhcpstatus.status IN ('dynamic', 'static')
+ -- ) WHERE ROWNUM <= 1
+ -- ) FOR UPDATE SKIP LOCKED;
+ -- EXCEPTION
+ -- WHEN NO_DATA_FOUND THEN
+ -- r_address := NULL;
+ -- END;
+
+ -- Oracle >= 12c version of the above query
+ --
+ -- BEGIN
+ -- SELECT framedipaddress INTO r_address FROM dhcpippool WHERE id IN (
+ -- SELECT id FROM dhcpippool
+ -- JOIN dhcpstatus
+ -- ON dhcpstatus.status_id = dhcpippool.status_id
+ -- WHERE pool_name = v_pool_name
+ -- AND pool_key = v_pool_key
+ -- AND dhcpstatus.status IN ('dynamic', 'static')
+ -- FETCH FIRST 1 ROWS ONLY
+ -- ) FOR UPDATE SKIP LOCKED;
+ -- EXCEPTION
+ -- WHEN NO_DATA_FOUND THEN
+ -- r_address := NULL;
+ -- END;
+
+
+
+ -- Issue the requested IP address if it is available
+ --
+ IF r_address IS NULL AND v_requested_address <> '0.0.0.0' THEN
+ BEGIN
+ SELECT framedipaddress INTO r_address FROM dhcpippool WHERE id IN (
+ SELECT id FROM (
+ SELECT *
+ FROM dhcpippool
+ JOIN dhcpstatus
+ ON dhcpstatus.status_id = dhcpippool.status_id
+ WHERE pool_name = v_pool_name
+ AND framedipaddress = v_requested_address
+ AND dhcpstatus.status = 'dynamic'
+ AND expiry_time < CURRENT_TIMESTAMP
+ ) WHERE ROWNUM <= 1
+ ) FOR UPDATE SKIP LOCKED;
+ EXCEPTION
+ WHEN NO_DATA_FOUND THEN
+ r_address := NULL;
+ END;
+ END IF;
+
+ -- Oracle >= 12c version of the above query
+ --
+ -- IF r_address IS NULL AND v_requested_address <> '0.0.0.0' THEN
+ -- BEGIN
+ -- SELECT framedipaddress INTO r_address FROM dhcpippool WHERE id IN (
+ -- SELECT id FROM dhcpippool
+ -- JOIN dhcpstatus
+ -- ON dhcpstatus.status_id = dhcpippool.status_id
+ -- WHERE pool_name = v_pool_name
+ -- AND framedipaddress = v_requested_address
+ -- AND dhcpstatus.status = 'dynamic'
+ -- AND expiry_time < CURRENT_TIMESTAMP
+ -- FETCH FIRST 1 ROWS ONLY
+ -- ) FOR UPDATE SKIP LOCKED;
+ -- EXCEPTION
+ -- WHEN NO_DATA_FOUND THEN
+ -- r_address := NULL;
+ -- END;
+ -- END IF;
+
+
+
+ -- If we didn't reallocate a previous address then pick the least
+ -- recently used address from the pool which maximises the likelihood
+ -- of re-assigning the other addresses to their recent user
+ --
+ IF r_address IS NULL THEN
+ DECLARE
+ l_cursor sys_refcursor;
+ BEGIN
+ OPEN l_cursor FOR
+ SELECT framedipaddress
+ FROM dhcpippool
+ JOIN dhcpstatus
+ ON dhcpstatus.status_id = dhcpippool.status_id
+ WHERE pool_name = v_pool_name
+ AND expiry_time < CURRENT_TIMESTAMP
+ AND dhcpstatus.status = 'dynamic'
+ ORDER BY expiry_time
+ FOR UPDATE SKIP LOCKED;
+ FETCH l_cursor INTO r_address;
+ CLOSE l_cursor;
+ EXCEPTION
+ WHEN NO_DATA_FOUND THEN
+ r_address := NULL;
+ END;
+ END IF;
+
+ -- Return nothing if we failed to allocated an address
+ --
+ IF r_address IS NULL THEN
+ COMMIT;
+ RETURN r_address;
+ END IF;
+
+ -- Update the pool having allocated an IP address
+ --
+ UPDATE dhcpippool
+ SET
+ gateway = v_gateway,
+ pool_key = v_pool_key,
+ expiry_time = CURRENT_TIMESTAMP + v_lease_duration * INTERVAL '1' SECOND(1)
+ WHERE framedipaddress = r_address;
+
+ -- Return the address that we allocated
+ COMMIT;
+ RETURN r_address;
+
+END;
+
diff --git a/raddb/mods-config/sql/ippool-dhcp/oracle/queries.conf b/raddb/mods-config/sql/ippool-dhcp/oracle/queries.conf
new file mode 100644
index 0000000..0fcffc3
--- /dev/null
+++ b/raddb/mods-config/sql/ippool-dhcp/oracle/queries.conf
@@ -0,0 +1,200 @@
+# -*- text -*-
+#
+# ippool-dhcp/oracle/queries.conf -- Oracle queries for rlm_sqlippool
+#
+# $Id$
+
+start_begin = "commit"
+alive_begin = "commit"
+stop_begin = "commit"
+on_begin = "commit"
+off_begin = "commit"
+
+
+# *****************
+# * DHCP DISCOVER *
+# *****************
+
+#
+# Use a stored procedure to find AND allocate the address. Read and customise
+# `procedure.sql` in this directory to determine the optimal configuration.
+# Oracle's locking mechanism limitations prevents the use of single queries
+# that can either find a client's existing address or the first available one.
+#
+allocate_begin = ""
+allocate_find = "\
+ SELECT fr_dhcp_allocate_previous_or_new_framedipaddress( \
+ '%{control:${pool_name}}', \
+ '%{DHCP-Gateway-IP-Address}', \
+ '${pool_key}', \
+ '${offer_duration}', \
+ '%{%{${req_attribute_name}}:-0.0.0.0}' \
+ ) FROM dual"
+allocate_update = ""
+allocate_commit = ""
+
+
+#
+# If you prefer to allocate a random IP address every time, use this query instead
+# Note: This is very slow if you have a lot of free IPs.
+#
+#allocate_find = "\
+# SELECT framedipaddress FROM ${ippool_table} WHERE id IN ( \
+# SELECT id FROM ( \
+# SELECT * \
+# FROM ${ippool_table} \
+# JOIN dhcpstatus \
+# ON ${ippool_table}.status_id = dhcpstatus.status_id \
+# WHERE pool_name = '%{control:${pool_name}}' \
+# AND expiry_time < current_timestamp \
+# AND dhcpstatus.status = 'dynamic' \
+# ORDER BY DBMS_RANDOM.VALUE \
+# ) WHERE ROWNUM <= 1 \
+# ) FOR UPDATE"
+
+#
+# The above query again, but with SKIP LOCKED. This requires Oracle > 11g.
+# It may work in 9i and 10g, but is not documented, so YMMV.
+#
+#allocate_find = "\
+# SELECT framedipaddress FROM ${ippool_table} WHERE id IN ( \
+# SELECT id FROM (\
+# SELECT * \
+# FROM ${ippool_table} \
+# JOIN dhcpstatus \
+# ON ${ippool_table}.status_id = dhcpstatus.status_id \
+# WHERE pool_name = '%{control:${pool_name}}' \
+# AND expiry_time < current_timestamp \
+# AND dhcpstatus.status = 'dynamic' \
+# ORDER BY DBMS_RANDOM.VALUE \
+# ) WHERE ROWNUM <= 1 \
+# ) FOR UPDATE SKIP LOCKED"
+
+#
+# A tidier version that needs Oracle >= 12c
+#
+#allocate_find = "\
+# SELECT framedipaddress FROM ${ippool_table} WHERE id IN (
+# SELECT id FROM ${ippool_table} \
+# JOIN dhcpstatus \
+# ON ${ippool_table}.status_id = dhcpstatus.status_id \
+# WHERE pool_name = '%{control:${pool_name}}' \
+# AND expiry_time < current_timestamp \
+# AND dhcpstatus.status = 'dynamic' \
+# ORDER BY DBMS_RANDOM.VALUE \
+# FETCH FIRST 1 ROWS ONLY
+# ) FOR UPDATE SKIP LOCKED"
+
+#
+# If an IP could not be allocated, check to see whether the pool exists or not
+# This allows the module to differentiate between a full pool and no pool
+# Note: If you are not running redundant pool modules this query may be commented
+# out to save running this query every time an ip is not allocated.
+#
+pool_check = "\
+ SELECT id \
+ FROM (\
+ SELECT id \
+ FROM ${ippool_table} \
+ WHERE pool_name='%{control:${pool_name}}'\
+ ) \
+ WHERE ROWNUM = 1"
+
+#
+# This query marks the IP address handed out by "allocate-find" as used
+# for the period of "offer_duration" after which time it may be reused.
+# Only needed if allocate_find is not using the stored procedure and therefore
+# not updating the lease
+#
+#allocate_update = "\
+# UPDATE ${ippool_table} \
+# SET \
+# gateway = '%{DHCP-Gateway-IP-Address}', \
+# pool_key = '${pool_key}', \
+# expiry_time = current_timestamp + INTERVAL '${offer_duration}' second(1) \
+# WHERE framedipaddress = '%I'"
+
+
+# ****************
+# * DHCP REQUEST *
+# ****************
+
+#
+# This query revokes any active offers for addresses that a client is not
+# requesting when a DHCP REQUEST packet arrives
+#
+start_update = "\
+ UPDATE ${ippool_table} \
+ SET \
+ gateway = '', \
+ pool_key = '0', \
+ expiry_time = current_timestamp - INTERVAL '1' second(1) \
+ WHERE pool_name = '%{control:${pool_name}}' \
+ AND pool_key = '${pool_key}' \
+ AND framedipaddress <> '%{DHCP-Requested-IP-Address}' \
+ AND expiry_time > current_timestamp \
+ AND ${ippool_table}.status_id IN \
+ (SELECT status_id FROM dhcpstatus WHERE status = 'dynamic')"
+start_commit = "COMMIT"
+
+#
+# This query extends an existing lease (or offer) when a DHCP REQUEST packet
+# arrives. This query must update a row when a lease is succesfully requested
+# - queries that update no rows will result in a "notfound" response to
+# the module which by default will give a DHCP-NAK reply. In this example
+# incrementing "counter" is used to achieve this.
+#
+alive_update = "\
+ UPDATE ${ippool_table} \
+ SET \
+ expiry_time = current_timestamp + INTERVAL '${lease_duration}' second(1), \
+ counter = counter + 1 \
+ WHERE pool_name = '%{control:${pool_name}}' \
+ AND pool_key = '${pool_key}' \
+ AND framedipaddress = '%{%{DHCP-Requested-IP-Address}:-%{DHCP-Client-IP-Address}}'"
+alive_commit = "COMMIT"
+
+
+# ****************
+# * DHCP RELEASE *
+# ****************
+
+#
+# This query frees an IP address when a DHCP RELEASE packet arrives
+#
+stop_clear = "\
+ UPDATE ${ippool_table} \
+ SET \
+ gateway = '', \
+ pool_key = '0', \
+ expiry_time = current_timestamp - INTERVAL '1' second(1) \
+ WHERE pool_name = '%{control:${pool_name}}' \
+ AND pool_key = '${pool_key}' \
+ AND framedipaddress = '%{DHCP-Client-IP-Address}' \
+ AND ${ippool_table}.status_id IN \
+ (SELECT status_id FROM dhcpstatus WHERE status = 'dynamic')"
+stop_commit = "COMMIT"
+
+
+#
+# This query is not applicable to DHCP
+#
+on_clear = ""
+
+
+# ****************
+# * DHCP DECLINE *
+# ****************
+
+#
+# This query marks an IP address as declined when a DHCP Decline
+# packet arrives
+#
+off_clear = "\
+ UPDATE ${ippool_table} \
+ SET status_id = (SELECT status_id FROM dhcpstatus WHERE status = 'declined') \
+ WHERE pool_name = '%{control:${pool_name}}' \
+ AND pool_key = '${pool_key}' \
+ AND framedipaddress = '%{DHCP-Requested-IP-Address}'"
+off_commit = "COMMIT"
+
diff --git a/raddb/mods-config/sql/ippool-dhcp/oracle/schema.sql b/raddb/mods-config/sql/ippool-dhcp/oracle/schema.sql
new file mode 100644
index 0000000..32d28bb
--- /dev/null
+++ b/raddb/mods-config/sql/ippool-dhcp/oracle/schema.sql
@@ -0,0 +1,28 @@
+CREATE TABLE dhcpstatus (
+ status_id INT PRIMARY KEY,
+ status VARCHAR(10) NOT NULL
+);
+
+INSERT INTO dhcpstatus (status_id, status) VALUES (1, 'dynamic');
+INSERT INTO dhcpstatus (status_id, status) VALUES (2, 'static');
+INSERT INTO dhcpstatus (status_id, status) VALUES (3, 'declined');
+INSERT INTO dhcpstatus (status_id, status) VALUES (4, 'disabled');
+
+CREATE SEQUENCE dhcpippool_seq START WITH 1 INCREMENT BY 1;
+
+CREATE TABLE dhcpippool (
+ id INT DEFAULT ON NULL dhcpippool_seq.NEXTVAL PRIMARY KEY,
+ pool_name VARCHAR(30) NOT NULL,
+ framedipaddress VARCHAR(15) NOT NULL,
+ pool_key VARCHAR(30) DEFAULT '',
+ gateway VARCHAR(15) DEFAULT '',
+ expiry_time timestamp(0) DEFAULT CURRENT_TIMESTAMP,
+ status_id INT DEFAULT 1,
+ counter INT DEFAULT 0,
+ FOREIGN KEY (status_id) REFERENCES dhcpstatus(status_id)
+);
+
+CREATE INDEX dhcpippool_poolname_expire ON dhcpippool (pool_name, expiry_time);
+CREATE INDEX dhcpippool_framedipaddress ON dhcpippool (framedipaddress);
+CREATE INDEX dhcpippool_poolname_poolkey_ipaddress ON dhcpippool (pool_name, pool_key, framedipaddress);
+
diff --git a/raddb/mods-config/sql/ippool-dhcp/postgresql/procedure.sql b/raddb/mods-config/sql/ippool-dhcp/postgresql/procedure.sql
new file mode 100644
index 0000000..379a349
--- /dev/null
+++ b/raddb/mods-config/sql/ippool-dhcp/postgresql/procedure.sql
@@ -0,0 +1,119 @@
+--
+-- A stored procedure to reallocate a user's previous address, otherwise
+-- provide a free address.
+--
+-- Using this SP reduces the usual set dialogue of queries to a single
+-- query:
+--
+-- START TRANSACTION; SELECT FOR UPDATE; UPDATE; COMMIT; -> SELECT sp()
+--
+-- The stored procedure is executed on an database instance within a single
+-- round trip which often leads to reduced deadlocking and significant
+-- performance improvements especially on multi-master clusters, perhaps even
+-- by an order of magnitude or more.
+--
+-- To use this stored procedure the corresponding queries.conf statements must
+-- be configured as follows:
+--
+-- allocate_begin = ""
+-- allocate_find = "\
+-- SELECT fr_dhcp_allocate_previous_or_new_framedipaddress( \
+-- '%{control:${pool_name}}', \
+-- '%{DHCP-Gateway-IP-Address}', \
+-- '${pool_key}', \
+-- ${lease_duration}, \
+-- '%{%{${req_attribute_name}}:-0.0.0.0}' \
+-- )"
+-- allocate_update = ""
+-- allocate_commit = ""
+--
+
+CREATE OR REPLACE FUNCTION fr_dhcp_allocate_previous_or_new_framedipaddress (
+ v_pool_name VARCHAR(64),
+ v_gateway VARCHAR(16),
+ v_pool_key VARCHAR(64),
+ v_lease_duration INT,
+ v_requested_address INET
+)
+RETURNS inet
+LANGUAGE plpgsql
+AS $$
+DECLARE
+ r_address INET;
+BEGIN
+
+ -- Reissue an existing IP address lease when re-authenticating a session
+ --
+ WITH ips AS (
+ SELECT framedipaddress FROM dhcpippool
+ WHERE pool_name = v_pool_name
+ AND pool_key = v_pool_key
+ AND expiry_time > NOW()
+ AND status IN ('dynamic', 'static')
+ LIMIT 1 FOR UPDATE SKIP LOCKED )
+ UPDATE dhcpippool
+ SET expiry_time = NOW() + v_lease_duration * interval '1 sec'
+ FROM ips WHERE dhcpippool.framedipaddress = ips.framedipaddress
+ RETURNING dhcpippool.framedipaddress INTO r_address;
+
+ -- Reissue an user's previous IP address, provided that the lease is
+ -- available (i.e. enable sticky IPs)
+ --
+ -- When using this SELECT you should delete the one above. You must also
+ -- set allocate_clear = "" in queries.conf to persist the associations
+ -- for expired leases.
+ --
+ -- WITH ips AS (
+ -- SELECT framedipaddress FROM dhcpippool
+ -- WHERE pool_name = v_pool_name
+ -- AND pool_key = v_pool_key
+ -- AND status IN ('dynamic', 'static')
+ -- LIMIT 1 FOR UPDATE SKIP LOCKED )
+ -- UPDATE dhcpippool
+ -- SET expiry_time = NOW + v_lease_duration * interval '1 sec'
+ -- FROM ips WHERE dhcpippool.framedipaddress = ips.framedipaddress
+ -- RETURNING dhcpippool.framedipaddress INTO r_address;
+
+ -- Issue the requested IP address if it is available
+ --
+ IF r_address IS NULL AND v_requested_address != '0.0.0.0' THEN
+ WITH ips AS (
+ SELECT framedipaddress FROM dhcpippool
+ WHERE pool_name = v_pool_name
+ AND framedipaddress = v_requested_address
+ AND status = 'dynamic'
+ AND ( pool_key = v_pool_key OR expiry_time < NOW() )
+ LIMIT 1 FOR UPDATE SKIP LOCKED )
+ UPDATE dhcpippool
+ SET pool_key = v_pool_key,
+ expiry_time = NOW() + v_lease_duration * interval '1 sec',
+ gateway = v_gateway
+ FROM ips WHERE dhcpippool.framedipaddress = ips.framedipaddress
+ RETURNING dhcpippool.framedipaddress INTO r_address;
+ END IF;
+
+ -- If we didn't reallocate a previous address then pick the least
+ -- recently used address from the pool which maximises the likelihood
+ -- of re-assigning the other addresses to their recent user
+ --
+ IF r_address IS NULL THEN
+ WITH ips AS (
+ SELECT framedipaddress FROM dhcpippool
+ WHERE pool_name = v_pool_name
+ AND expiry_time < NOW()
+ AND status = 'dynamic'
+ ORDER BY expiry_time
+ LIMIT 1 FOR UPDATE SKIP LOCKED )
+ UPDATE dhcpippool
+ SET pool_key = v_pool_key,
+ expiry_time = NOW() + v_lease_duration * interval '1 sec',
+ gateway = v_gateway
+ FROM ips WHERE dhcpippool.framedipaddress = ips.framedipaddress
+ RETURNING dhcpippool.framedipaddress INTO r_address;
+ END IF;
+
+ -- Return the address that we allocated
+ RETURN r_address;
+
+END
+$$;
diff --git a/raddb/mods-config/sql/ippool-dhcp/postgresql/queries.conf b/raddb/mods-config/sql/ippool-dhcp/postgresql/queries.conf
new file mode 100644
index 0000000..632fc70
--- /dev/null
+++ b/raddb/mods-config/sql/ippool-dhcp/postgresql/queries.conf
@@ -0,0 +1,291 @@
+# -*- text -*-
+#
+# ippool-dhcp/postgresql/queries.conf -- PostgreSQL queries for rlm_sqlippool
+#
+# $Id$
+
+# *****************
+# * DHCP DISCOVER *
+# *****************
+
+#
+# Use a stored procedure to find AND allocate the address. Read and customise
+# `procedure.sql` in this directory to determine the optimal configuration.
+#
+# This requires PostgreSQL >= 9.5 as SKIP LOCKED is used.
+#
+# The "NO LOAD BALANCE" comment is included here to indicate to a PgPool
+# system that this needs to be a write transaction. PgPool itself cannot
+# detect this from the statement alone. If you are using PgPool and do not
+# have this comment, the query may go to a read only server, and will fail.
+# This has no negative effect if you are not using PgPool.
+#
+allocate_begin = ""
+allocate_find = "\
+ /*NO LOAD BALANCE*/ \
+ SELECT fr_dhcp_allocate_previous_or_new_framedipaddress( \
+ '%{control:${pool_name}}', \
+ '%{DHCP-Gateway-IP-Address}', \
+ '${pool_key}', \
+ '${offer_duration}', \
+ '%{%{${req_attribute_name}}:-0.0.0.0}' \
+ )"
+allocate_update = ""
+allocate_commit = ""
+
+#
+# If stored procedures are not able to be used, the following queries can
+# be used.
+# Comment out all the above queries and choose the appropriate "allocate_find"
+# to match the desired outcome and also the version of "allocate_update" below.
+#
+
+#
+# This sequence of queries allocates an IP address from the Pool
+#
+#allocate_begin = "BEGIN"
+
+
+# Attempt to find the most recent existing IP address for the client
+#
+#allocate_existing = "\
+# SELECT framedipaddress FROM ${ippool_table} \
+# WHERE pool_name = '%{control:${pool_name}}' \
+# AND pool_key = '${pool_key}' \
+# AND status IN ('dynamic', 'static') \
+# ORDER BY expiry_time DESC \
+# LIMIT 1 \
+# FOR UPDATE"
+
+# The same query with SKIP LOCKED - requires PostgreSQL >= 9.5
+# allocate_existing = "\
+# SELECT framedipaddress FROM ${ippool_table} \
+# WHERE pool_name = '%{control:${pool_name}}' \
+# AND pool_key = '${pool_key}' \
+# AND status IN ('dynamic', 'static') \
+# ORDER BY expiry_time DESC \
+# LIMIT 1 \
+# FOR UPDATE SKIP LOCKED"
+
+
+#
+# Determine whether the requested IP address is available
+#
+#allocate_requested = "\
+# SELECT framedipaddress FROM ${ippool_table} \
+# WHERE pool_name = '%{control:${pool_name}}' \
+# AND framedipaddress = '%{%{${req_attribute_name}}:-0.0.0.0}' \
+# AND status = 'dynamic' \
+# AND expiry_time < 'now'::timestamp(0) \
+# FOR UPDATE"
+
+# The same query with SKIP LOCKED - requires PostgreSQL >= 9.5
+#allocate_requested = "\
+# SELECT framedipaddress FROM ${ippool_table} \
+# WHERE pool_name = '%{control:${pool_name}}' \
+# AND framedipaddress = '%{%{${req_attribute_name}}:-0.0.0.0}' \
+# AND status = 'dynamic' \
+# AND expiry_time < 'now'::timestamp(0) \
+# FOR UPDATE SKIP LOCKED"
+
+
+#
+# If the existing address can't be found this query will be run to
+# find a free address
+#
+#allocate_find = "\
+# SELECT framedipaddress FROM ${ippool_table} \
+# WHERE pool_name = '%{control:${pool_name}}' \
+# AND expiry_time < 'now'::timestamp(0) \
+# AND status = 'dynamic' \
+# ORDER BY expiry_time \
+# LIMIT 1 \
+# FOR UPDATE"
+
+# The same query with SKIP LOCKED - requires PostgreSQL >= 9.5
+#allocate_find = "\
+# SELECT framedipaddress FROM ${ippool_table} \
+# WHERE pool_name = '%{control:${pool_name}}' \
+# AND expiry_time < 'now'::timestamp(0) \
+# AND status = 'dynamic' \
+# ORDER BY expiry_time \
+# LIMIT 1 \
+# FOR UPDATE SKIP LOCKED"
+
+#
+# If you prefer to allocate a random IP address every time, use this query instead
+# Note: This is very slow if you have a lot of free IPs.
+# Use of either of these next two queries should have the allocate_begin line commented out
+# and allocate_update below un-commented.
+#
+#allocate_find = "\
+# SELECT framedipaddress FROM ${ippool_table} \
+# WHERE pool_name = '%{control:${pool_name}}' AND expiry_time < 'now'::timestamp(0) \
+# AND status = 'dynamic' \
+# ORDER BY RANDOM() \
+# LIMIT 1 \
+# FOR UPDATE"
+
+#
+# The above query again, but with SKIP LOCKED. This requires PostgreSQL >= 9.5.
+#
+#allocate_find = "\
+# SELECT framedipaddress FROM ${ippool_table} \
+# WHERE pool_name = '%{control:${pool_name}}' AND expiry_time < 'now'::timestamp(0) \
+# AND status = 'dynamic' \
+# ORDER BY RANDOM() \
+# LIMIT 1 \
+# FOR UPDATE SKIP LOCKED"
+
+#
+# This query marks the IP address handed out by "allocate-find" as used
+# for the period of "lease_duration" after which time it may be reused.
+#
+#allocate_update = "\
+# UPDATE ${ippool_table} \
+# SET \
+# gateway = '%{DHCP-Gateway-IP-Address}', \
+# pool_key = '${pool_key}', \
+# expiry_time = 'now'::timestamp(0) + '${offer_duration} second'::interval \
+# WHERE framedipaddress = '%I'"
+
+
+#
+# Alternatively, merge the matching of existing IP and free IP into a single query
+# This version does the update as well - so allocate_begin, allocate_update and
+# allocate_commit should be blank
+#
+#allocate_begin = ""
+#allocate_find = "\
+# WITH found AS ( \
+# WITH existing AS ( \
+# SELECT framedipaddress FROM ${ippool_table} \
+# WHERE pool_name = '%{control:${pool_name}}' \
+# AND pool_key = '${pool_key}' \
+# ORDER BY expiry_time DESC \
+# LIMIT 1 \
+# FOR UPDATE SKIP LOCKED \
+# ), requested AS ( \
+# SELECT framedipaddress FROM ${ippool_table} \
+# WHERE pool_name = '%{control:${pool_name}}' \
+# AND framedipaddress = '%{%{${req_attribute_name}}:-0.0.0.0}' \
+# AND status = 'dynamic' \
+# AND ( pool_key = '${pool_key}' OR expiry_time < 'now'::timestamp(0) ) \
+# FOR UPDATE SKIP LOCKED \
+# ), new AS ( \
+# SELECT framedipaddress FROM ${ippool_table} \
+# WHERE pool_name = '%{control:${pool_name}}' \
+# AND expiry_time < 'now'::timestamp(0) \
+# AND status = 'dynamic' \
+# ORDER BY expiry_time \
+# LIMIT 1 \
+# FOR UPDATE SKIP LOCKED \
+# ) \
+# SELECT framedipaddress, 1 AS o FROM existing \
+# UNION ALL \
+# SELECT framedipaddress, 2 AS o FROM requested \
+# UNION ALL \
+# SELECT framedipaddress, 3 AS o FROM new \
+# ORDER BY o LIMIT 1 \
+# ) \
+# UPDATE ${ippool_table} \
+# SET pool_key = '${pool_key}', \
+# expiry_time = 'now'::timestamp(0) + '${offer_duration} second'::interval, \
+# gateway = '%{DHCP-Gateway-IP-Address}' \
+# FROM found \
+# WHERE found.framedipaddress = ${ippool_table}.framedipaddress \
+# RETURNING found.framedipaddress"
+#allocate_update = ""
+#allocate_commit = ""
+
+
+#
+# If an IP could not be allocated, check to see whether the pool exists or not
+# This allows the module to differentiate between a full pool and no pool
+# Note: If you are not running redundant pool modules this query may be commented
+# out to save running this query every time an ip is not allocated.
+#
+pool_check = "\
+ SELECT id \
+ FROM ${ippool_table} \
+ WHERE pool_name='%{control:${pool_name}}' \
+ LIMIT 1"
+
+
+# ****************
+# * DHCP REQUEST *
+# ****************
+
+#
+# This query revokes any active offers for addresses that a client is not
+# requesting when a DHCP REQUEST packet arrives, i.e, each server (sharing the
+# same database) may have simultaneously offered a unique address.
+#
+start_update = "\
+ UPDATE ${ippool_table} \
+ SET \
+ gateway = '', \
+ pool_key = '', \
+ expiry_time = 'now'::timestamp(0) - '1 second'::interval \
+ WHERE pool_name = '%{control:${pool_name}}' \
+ AND pool_key = '${pool_key}' \
+ AND framedipaddress <> '%{DHCP-Requested-IP-Address}' \
+ AND expiry_time > 'now'::timestamp(0) \
+ AND status = 'dynamic'"
+
+#
+# This query extends an existing lease (or offer) when a DHCP REQUEST packet
+# arrives. This query must update a row when a lease is succesfully requested
+# - queries that update no rows will result in a "notfound" response to
+# the module which by default will give a DHCP-NAK reply. In this example
+# incrementing "counter" is used to achieve this.
+#
+alive_update = "\
+ UPDATE ${ippool_table} \
+ SET \
+ expiry_time = 'now'::timestamp(0) + '${lease_duration} second'::interval, \
+ counter = counter + 1 \
+ WHERE pool_name = '%{control:${pool_name}}' \
+ AND pool_key = '${pool_key}' \
+ AND framedipaddress = '%{%{DHCP-Requested-IP-Address}:-%{DHCP-Client-IP-Address}}'"
+
+
+# ****************
+# * DHCP RELEASE *
+# ****************
+
+#
+# This query frees an IP address when a DHCP RELEASE packet arrives
+#
+stop_clear = "\
+ UPDATE ${ippool_table} \
+ SET \
+ gateway = '', \
+ pool_key = '', \
+ expiry_time = 'now'::timestamp(0) - '1 second'::interval \
+ WHERE pool_name = '%{control:${pool_name}}' \
+ AND pool_key = '${pool_key}' \
+ AND framedipaddress = '%{DHCP-Client-IP-Address}' \
+ AND status = 'dynamic'"
+
+
+#
+# This query is not applicable to DHCP
+#
+on_clear = ""
+
+
+# ****************
+# * DHCP DECLINE *
+# ****************
+
+#
+# This query marks an IP address as declined when a DHCP DECLINE packet
+# arrives
+#
+off_clear = "\
+ UPDATE ${ippool_table} \
+ SET status = 'declined' \
+ WHERE pool_name = '%{control:${pool_name}}' \
+ AND pool_key = '${pool_key}' \
+ AND framedipaddress = '%{DHCP-Requested-IP-Address}'"
diff --git a/raddb/mods-config/sql/ippool-dhcp/postgresql/schema.sql b/raddb/mods-config/sql/ippool-dhcp/postgresql/schema.sql
new file mode 100644
index 0000000..af86889
--- /dev/null
+++ b/raddb/mods-config/sql/ippool-dhcp/postgresql/schema.sql
@@ -0,0 +1,23 @@
+--
+-- Table structure for table 'dhcpippool'
+--
+-- See also "procedure.sql" in this directory for
+-- a stored procedure that gives much faster response.
+--
+
+CREATE TYPE dhcp_status AS ENUM ('dynamic', 'static', 'declined', 'disabled');
+
+CREATE TABLE dhcpippool (
+ id BIGSERIAL PRIMARY KEY,
+ pool_name varchar(64) NOT NULL,
+ FramedIPAddress INET NOT NULL,
+ pool_key VARCHAR(64) NOT NULL default '0',
+ gateway VARCHAR(16) NOT NULL default '',
+ expiry_time TIMESTAMP(0) without time zone NOT NULL default NOW(),
+ status dhcp_status DEFAULT 'dynamic',
+ counter INT NOT NULL default 0
+);
+
+CREATE INDEX dhcpippool_poolname_expire ON dhcpippool USING btree (pool_name, expiry_time);
+CREATE INDEX dhcpippool_framedipaddress ON dhcpippool USING btree (framedipaddress);
+CREATE INDEX dhcpippool_poolname_poolkey_ipaddress ON dhcpippool USING btree (pool_name, pool_key, framedipaddress);
diff --git a/raddb/mods-config/sql/ippool-dhcp/sqlite/queries.conf b/raddb/mods-config/sql/ippool-dhcp/sqlite/queries.conf
new file mode 100644
index 0000000..d99e09b
--- /dev/null
+++ b/raddb/mods-config/sql/ippool-dhcp/sqlite/queries.conf
@@ -0,0 +1,236 @@
+# -*- text -*-
+#
+# ippool-dhcp/sqlite/queries.conf -- SQLite queries for rlm_sqlippool
+#
+# $Id$
+
+# *****************
+# * DHCP DISCOVER *
+# *****************
+
+#
+# SQLite does not implement SELECT FOR UPDATE which is normally used to place
+# an exclusive lock over rows to prevent the same address from being
+# concurrently selected for allocation to multiple users.
+#
+# The most granular read-blocking lock that SQLite has is an exclusive lock
+# over the database, so that's what we use. All locking in SQLite is performed
+# over the entire database and we perform a row update for any IP that we
+# allocate, requiring an exclusive lock. Taking the exclusive lock from the
+# start of the transaction (even if it were not required to guard the SELECT)
+# is actually quicker than if we deferred it causing SQLite to "upgrade" the
+# automatic shared lock for the transaction to an exclusive lock for the
+# subsequent UPDATE.
+#
+allocate_begin = "BEGIN EXCLUSIVE"
+allocate_commit = "COMMIT"
+
+#
+# Attempt to find the most recent existing IP address for the client
+#
+allocate_existing = "\
+ SELECT framedipaddress \
+ FROM ${ippool_table} \
+ JOIN dhcpstatus \
+ ON ${ippool_table}.status_id = dhcpstatus.status_id \
+ WHERE pool_name = '%{control:${pool_name}}' \
+ AND pool_key = '${pool_key}' \
+ AND status IN ('dynamic', 'static') \
+ ORDER BY expiry_time DESC \
+ LIMIT 1"
+
+#
+# Determine whether the requested IP address is available
+#
+allocate_requested = "\
+ SELECT framedipaddress \
+ FROM ${ippool_table} \
+ JOIN dhcpstatus \
+ ON ${ippool_table}.status_id = dhcpstatus.status_id \
+ WHERE pool_name = '%{control:${pool_name}}' \
+ AND framedipaddress = '%{%{${req_attribute_name}}:-0.0.0.0}' \
+ AND status = 'dynamic' \
+ AND expiry_time < datetime('now')"
+
+#
+# If the existing address can't be found this query will be run to
+# find a free address
+#
+allocate_find = "\
+ SELECT framedipaddress \
+ FROM ${ippool_table} \
+ JOIN dhcpstatus \
+ ON ${ippool_table}.status_id = dhcpstatus.status_id \
+ WHERE pool_name = '%{control:${pool_name}}' \
+ AND expiry_time < datetime('now') \
+ AND status = 'dynamic' \
+ ORDER BY expiry_time LIMIT 1"
+
+#
+# This series of queries allocates an IP address
+#
+# Either pull the most recent allocated IP for this client or the
+# oldest expired one. The first sub query returns the most recent
+# lease for the client (if there is one), the second returns the
+# oldest expired one.
+# Sorting the result by expiry_time DESC will return the client specific
+# IP if it exists, otherwise an expired one.
+#
+#allocate_find = "\
+# SELECT framedipaddress, 1 AS o \
+# FROM ( \
+# SELECT framedipaddress \
+# FROM ${ippool_table} \
+# JOIN dhcpstatus \
+# ON ${ippool_table}.status_id = dhcpstatus.status_id \
+# WHERE pool_name = '%{control:${pool_name}}' \
+# AND pool_key = '${pool_key}' \
+# AND status IN ('dynamic', 'static') \
+# ORDER BY expiry_time DESC \
+# LIMIT 1 \
+# ) UNION \
+# SELECT framedipaddress, 2 AS o \
+# FROM ( \
+# SELECT framedipaddress \
+# FROM ${ippool_table} \
+# JOIN dhcpstatus \
+# ON ${ippool_table}.status_id = dhcpstatus.status_id \
+# WHERE pool_name = '%{control:${pool_name}}' \
+# AND framedipaddress = '%{%{${req_attribute_name}}:-0.0.0.0}' \
+# AND status = 'dynamic' \
+# AND ( pool_key = '${pool_key}' OR expiry_time < datetime('now') ) \
+# ) UNION \
+# SELECT framedipaddress, 3 AS o \
+# FROM ( \
+# SELECT framedipaddress \
+# FROM ${ippool_table} \
+# JOIN dhcpstatus \
+# ON ${ippool_table}.status_id = dhcpstatus.status_id \
+# WHERE pool_name = '%{control:${pool_name}}' \
+# AND expiry_time < datetime('now') \
+# AND status = 'dynamic' \
+# ORDER BY expiry_time LIMIT 1 \
+# ) \
+# ORDER BY o \
+# LIMIT 1"
+
+#
+# If you prefer to allocate a random IP address every time, i
+# use this query instead
+# Note: This is very slow if you have a lot of free IPs.
+#
+
+#allocate_find = "\
+# SELECT framedipaddress \
+# FROM ${ippool_table} \
+# JOIN dhcpstatus \
+# ON ${ippool_table}.status_id = dhcpstatus.status_id \
+# WHERE pool_name = '%{control:${pool_name}}' \
+# AND expiry_time < datetime('now') \
+# AND status = 'dynamic' \
+# ORDER BY RAND() \
+
+
+#
+# If an IP could not be allocated, check to see if the pool exists or not
+# This allows the module to differentiate between a full pool and no pool
+# Note: If you are not running redundant pool modules this query may be
+# commented out to save running this query every time an ip is not allocated.
+#
+pool_check = "\
+ SELECT id \
+ FROM ${ippool_table} \
+ WHERE pool_name='%{control:${pool_name}}' \
+ LIMIT 1"
+
+#
+# This is the final IP Allocation query, which saves the allocated ip details
+#
+allocate_update = "\
+ UPDATE ${ippool_table} \
+ SET \
+ gateway = '%{DHCP-Gateway-IP-Address}', \
+ pool_key = '${pool_key}', \
+ expiry_time = datetime(strftime('%%s', 'now') + ${offer_duration}, 'unixepoch') \
+ WHERE framedipaddress = '%I'"
+
+
+# ****************
+# * DHCP REQUEST *
+# ****************
+
+#
+# This query revokes any active offers for addresses that a client is not
+# requesting when a DHCP REQUEST packet arrives
+#
+start_update = "\
+ UPDATE ${ippool_table} \
+ SET \
+ gateway = '', \
+ pool_key = '', \
+ expiry_time = datetime('now') \
+ WHERE pool_name = '%{control:${pool_name}}' \
+ AND pool_key = '${pool_key}' \
+ AND framedipaddress <> '%{DHCP-Requested-IP-Address}' \
+ AND expiry_time > datetime('now') \
+ AND ${ippool_table}.status_id IN \
+ (SELECT status_id FROM dhcpstatus WHERE status = 'dynamic')"
+
+#
+# This query extends an existing lease (or offer) when a DHCP REQUEST packet
+# arrives. This query must update a row when a lease is succesfully requested
+# - queries that update no rows will result in a "notfound" response to
+# the module which by default will give a DHCP-NAK reply. In this example
+# incrementing "counter" is used to achieve this.
+#
+alive_update = "\
+ UPDATE ${ippool_table} \
+ SET \
+ expiry_time = datetime(strftime('%%s', 'now') + ${lease_duration}, 'unixepoch'), \
+ counter = counter + 1 \
+ WHERE pool_name = '%{control:${pool_name}}' \
+ AND pool_key = '${pool_key}' \
+ AND framedipaddress = '%{%{DHCP-Requested-IP-Address}:-%{DHCP-Client-IP-Address}}'"
+
+
+# ****************
+# * DHCP RELEASE *
+# ****************
+
+#
+# This query frees an IP address when a DHCP RELEASE packet arrives
+#
+stop_clear = "\
+ UPDATE ${ippool_table} \
+ SET \
+ gateway = '', \
+ pool_key = '', \
+ expiry_time = datetime('now') \
+ WHERE pool_name = '%{control:${pool_name}}' \
+ AND pool_key = '${pool_key}' \
+ AND framedipaddress = '%{DHCP-Client-IP-Address}' \
+ AND ${ippool_table}.status_id IN \
+ (SELECT status_id FROM dhcpstatus WHERE status = 'dynamic')"
+
+
+#
+# This query is not applicable to DHCP
+#
+on_clear = ""
+
+
+# ****************
+# * DHCP DECLINE *
+# ****************
+
+#
+# This query marks an IP address as declined when a DHCP Decline
+# packet arrives
+#
+off_clear = "\
+ UPDATE ${ippool_table} \
+ SET status_id = (SELECT status_id FROM dhcpstatus WHERE status = 'declined') \
+ WHERE pool_name = '%{control:${pool_name}}' \
+ AND pool_key = '${pool_key}' \
+ AND framedipaddress = '%{DHCP-Requested-IP-Address}'"
+
diff --git a/raddb/mods-config/sql/ippool-dhcp/sqlite/schema.sql b/raddb/mods-config/sql/ippool-dhcp/sqlite/schema.sql
new file mode 100644
index 0000000..339d58d
--- /dev/null
+++ b/raddb/mods-config/sql/ippool-dhcp/sqlite/schema.sql
@@ -0,0 +1,25 @@
+--
+-- Table structure for table 'dhcpippool'
+--
+CREATE TABLE dhcpstatus (
+ status_id int PRIMARY KEY,
+ status varchar(10) NOT NULL
+);
+
+INSERT INTO dhcpstatus (status_id, status) VALUES (1, 'dynamic'), (2, 'static'), (3, 'declined'), (4, 'disabled');
+
+CREATE TABLE dhcpippool (
+ id int(11) PRIMARY KEY,
+ pool_name varchar(30) NOT NULL,
+ framedipaddress varchar(15) NOT NULL default '',
+ pool_key varchar(30) NOT NULL default '',
+ gateway varchar(15) NOT NULL default '',
+ expiry_time DATETIME NOT NULL default (DATETIME('now')),
+ status_id int NOT NULL default 1,
+ counter int NOT NULL default 0,
+ FOREIGN KEY(status_id) REFERENCES dhcpstatus(status_id)
+);
+
+CREATE INDEX dhcpippool_poolname_expire ON dhcpippool(pool_name, expiry_time);
+CREATE INDEX dhcpippool_framedipaddress ON dhcpippool(framedipaddress);
+CREATE INDEX dhcpippool_poolname_poolkey_ipaddress ON dhcpippool(pool_name, pool_key, framedipaddress);
diff --git a/raddb/mods-config/sql/ippool/mongo/queries.conf b/raddb/mods-config/sql/ippool/mongo/queries.conf
new file mode 100644
index 0000000..9d7d070
--- /dev/null
+++ b/raddb/mods-config/sql/ippool/mongo/queries.conf
@@ -0,0 +1,109 @@
+# -*- text -*-
+#
+# ippool/mongo/queries.conf -- Mongo queries for rlm_sqlippool
+#
+# $Id$
+
+#
+# The IP Pool queries expect a result like:
+#
+# {
+# pool_key: "bob"
+# pool_name: "my_pool"
+# expiry_time: xxx
+# value: "192.168.1.1"
+# }
+#
+# i.e. the results are in "value", and not "framed_ip_address".
+#
+# When using dynamic expansions such as "%{sql:... mongo query ...}",
+# Mongo uses a lot of curly brackets, {..}. Any closing braces have
+# to be escaped as %}. Sorry, that is a limitation of the FreeRADIUS
+# parser.
+#
+
+#
+# TBD
+#
+on_begin = ""
+off_begin = ""
+
+allocate_begin = ""
+
+#
+# This query allocates an IP address from the Pool
+#
+allocate_find = "db.mypool_collection.findAndModify( \
+ { \
+ 'query': {' \
+ '$and': [ \
+ { \
+ 'pool_name': '%{control:Pool-Name}' \
+ }, \
+ { \
+ 'nas_ip': '%{Nas-IP-Address}' \
+ }, \
+ { \
+ '$or': [ \
+ { \
+ 'calling_station_id': '%{Calling-Station-Id}' \
+ }, \
+ { \
+ 'locked': 0 \
+ } \
+ ] \
+ } \
+ ] \
+ }, \
+ 'update': { \
+ 'locked': 1', \
+ 'calling_station_id': '%{Calling-Station-Id'}' \
+ }, \
+ 'fields': { \
+ '_id': 0, 'framed_ip_address': 1 \
+ } \
+ })"
+
+allocate_update = ""
+
+allocate_clear = "db.mypool_collection.findAndModify( \
+ { \
+ 'query': { \
+ '$and': [ \
+ { \
+ 'pool_name': '%{Control:Pool-Name}' \
+ }, \
+ { \
+ 'nas_ip': '%{Nas-IP-Address}' \
+ }, \
+ { \
+ 'calling_station_id': '%{Calling-Station-Id}' \
+ }, \
+ { \
+ 'locked': 1 \
+ } \
+ ] \
+ }, \
+ 'update': { \
+ 'locked': 0, \
+ 'calling_station_id': '' \
+ } \
+ })"
+
+allocate_commit = ""
+
+start_begin = ""
+start_update = ""
+start_commit = ""
+
+stop_begin = ""
+stop_clear = ""
+stop_commit = ""
+
+alive_begin = ""
+alive_update = ""
+alive_commit = ""
+
+on_clear = ""
+off_clear = ""
+
diff --git a/raddb/mods-config/sql/ippool/mssql/procedure.sql b/raddb/mods-config/sql/ippool/mssql/procedure.sql
new file mode 100644
index 0000000..5c621fb
--- /dev/null
+++ b/raddb/mods-config/sql/ippool/mssql/procedure.sql
@@ -0,0 +1,137 @@
+--
+-- A stored procedure to reallocate a user's previous address, otherwise
+-- provide a free address.
+--
+-- Using this SP reduces the usual set dialogue of queries to a single
+-- query:
+--
+-- BEGIN TRAN; "SELECT FOR UPDATE"; UPDATE; COMMIT TRAN; -> EXEC sp
+--
+-- The stored procedure is executed on an database instance within a single
+-- round trip which often leads to reduced deadlocking and significant
+-- performance improvements especially on multi-master clusters, perhaps even
+-- by an order of magnitude or more.
+--
+-- To use this stored procedure the corresponding queries.conf statements must
+-- be configured as follows:
+--
+-- allocate_begin = ""
+-- allocate_find = "\
+-- EXEC fr_allocate_previous_or_new_framedipaddress \
+-- @v_pool_name = '%{control:${pool_name}}', \
+-- @v_username = '%{User-Name}', \
+-- @v_callingstationid = '%{Calling-Station-Id}', \
+-- @v_nasipaddress = '%{NAS-IP-Address}', \
+-- @v_pool_key = '${pool_key}', \
+-- @v_lease_duration = ${lease_duration} \
+-- "
+-- allocate_update = ""
+-- allocate_commit = ""
+--
+
+CREATE INDEX UserName_CallingStationId ON radippool(pool_name,UserName,CallingStationId)
+GO
+
+CREATE OR ALTER PROCEDURE fr_allocate_previous_or_new_framedipaddress
+ @v_pool_name VARCHAR(64),
+ @v_username VARCHAR(64),
+ @v_callingstationid VARCHAR(64),
+ @v_nasipaddress VARCHAR(15),
+ @v_pool_key VARCHAR(64),
+ @v_lease_duration INT
+AS
+ BEGIN
+
+ -- MS SQL lacks a "SELECT FOR UPDATE" statement, and its table
+ -- hints do not provide a direct means to implement the row-level
+ -- read lock needed to guarentee that concurrent queries do not
+ -- select the same Framed-IP-Address for allocation to distinct
+ -- users.
+ --
+ -- The "WITH cte AS ( SELECT ... ) UPDATE cte ... OUTPUT INTO"
+ -- patterns in this procedure body compensate by wrapping
+ -- the SELECT in a synthetic UPDATE which locks the row.
+
+ DECLARE @r_address_tab TABLE(id VARCHAR(15));
+ DECLARE @r_address VARCHAR(15);
+
+ BEGIN TRAN;
+
+ -- Reissue an existing IP address lease when re-authenticating a session
+ --
+ WITH cte AS (
+ SELECT TOP(1) FramedIPAddress
+ FROM radippool WITH (xlock rowlock readpast)
+ WHERE pool_name = @v_pool_name
+ AND expiry_time > CURRENT_TIMESTAMP
+ AND NASIPAddress = @v_nasipaddress AND pool_key = @v_pool_key
+ )
+ UPDATE cte
+ SET FramedIPAddress = FramedIPAddress
+ OUTPUT INSERTED.FramedIPAddress INTO @r_address_tab;
+ SELECT @r_address = id FROM @r_address_tab;
+
+ -- Reissue an user's previous IP address, provided that the lease is
+ -- available (i.e. enable sticky IPs)
+ --
+ -- When using this SELECT you should delete the one above. You must also
+ -- set allocate_clear = "" in queries.conf to persist the associations
+ -- for expired leases.
+ --
+ -- WITH cte AS (
+ -- SELECT TOP(1) FramedIPAddress
+ -- FROM radippool WITH (xlock rowlock readpast)
+ -- WHERE pool_name = @v_pool_name
+ -- AND NASIPAddress = @v_nasipaddress AND pool_key = @v_pool_key
+ -- )
+ -- UPDATE cte
+ -- SET FramedIPAddress = FramedIPAddress
+ -- OUTPUT INSERTED.FramedIPAddress INTO @r_address_tab;
+ -- SELECT @r_address = id FROM @r_address_tab;
+
+ -- If we didn't reallocate a previous address then pick the least
+ -- recently used address from the pool which maximises the likelihood
+ -- of re-assigning the other addresses to their recent user
+ --
+ IF @r_address IS NULL
+ BEGIN
+ WITH cte AS (
+ SELECT TOP(1) FramedIPAddress
+ FROM radippool WITH (xlock rowlock readpast)
+ WHERE pool_name = @v_pool_name
+ AND expiry_time < CURRENT_TIMESTAMP
+ ORDER BY
+ expiry_time
+ )
+ UPDATE cte
+ SET FramedIPAddress = FramedIPAddress
+ OUTPUT INSERTED.FramedIPAddress INTO @r_address_tab;
+ SELECT @r_address = id FROM @r_address_tab;
+ END
+
+ -- Return nothing if we failed to allocated an address
+ --
+ IF @r_address IS NULL
+ BEGIN
+ COMMIT TRAN;
+ RETURN;
+ END
+
+ -- Update the pool having allocated an IP address
+ --
+ UPDATE radippool
+ SET
+ NASIPAddress = @v_nasipaddress,
+ pool_key = @v_pool_key,
+ CallingStationId = @v_callingstationid,
+ UserName = @v_username,
+ expiry_time = DATEADD(SECOND,@v_lease_duration,CURRENT_TIMESTAMP)
+ WHERE framedipaddress = @r_address;
+
+ COMMIT TRAN;
+
+ -- Return the address that we allocated
+ SELECT @r_address;
+
+ END
+GO
diff --git a/raddb/mods-config/sql/ippool/mssql/queries.conf b/raddb/mods-config/sql/ippool/mssql/queries.conf
new file mode 100644
index 0000000..8105dcc
--- /dev/null
+++ b/raddb/mods-config/sql/ippool/mssql/queries.conf
@@ -0,0 +1,175 @@
+# -*- text -*-
+#
+# ippool/mssql/queries.conf -- MSSQL queries for rlm_sqlippool
+#
+# $Id$
+
+#
+# MSSQL-specific syntax - required if finding the address and updating
+# it are separate queries
+#
+#allocate_begin = "BEGIN TRAN"
+#allocate_commit = "COMMIT TRAN"
+
+allocate_begin = ""
+allocate_commit = ""
+
+#
+# This series of queries allocates an IP address
+#
+
+#
+# Attempt to allocate the address a client previously had. This is based on pool_key
+# and nasipaddress. Change the criteria if the identifier for "stickyness" is different.
+# If different criteria are used, check the indexes on the IP pool table to ensure the fields
+# are appropriately indexed. To disable stickyness comment out this query.
+#
+allocate_existing = "\
+ WITH cte AS ( \
+ SELECT TOP(1) FramedIPAddress, CallingStationId, UserName, expiry_time \
+ FROM ${ippool_table} WITH (xlock rowlock readpast) \
+ WHERE pool_name = '%{control:${pool_name}}' \
+ AND NASIPAddress = '%{NAS-IP-Address}' AND pool_key = '${pool_key}' \
+ ORDER BY expiry_time DESC \
+ ) \
+ UPDATE cte \
+ SET \
+ CallingStationId = '%{Calling-Station-Id}', \
+ UserName = '%{User-Name}', expiry_time = DATEADD(SECOND,${lease_duration},CURRENT_TIMESTAMP) \
+ OUTPUT INSERTED.FramedIPAddress"
+
+#
+# Find a free IP address from the pool, choosing the oldest expired one.
+#
+allocate_find = "\
+ WITH cte AS ( \
+ SELECT TOP(1) FramedIPAddress, NASIPAddress, pool_key, \
+ CallingStationId, UserName, expiry_time \
+ FROM ${ippool_table} WITH (xlock rowlock readpast) \
+ WHERE pool_name = '%{control:${pool_name}}' \
+ AND expiry_time < CURRENT_TIMESTAMP \
+ ORDER BY expiry_time \
+ ) \
+ UPDATE cte \
+ SET \
+ NASIPAddress = '%{NAS-IP-Address}', pool_key = '${pool_key}', \
+ CallingStationId = '%{Calling-Station-Id}', \
+ UserName = '%{User-Name}', expiry_time = DATEADD(SECOND,${lease_duration},CURRENT_TIMESTAMP) \
+ OUTPUT INSERTED.FramedIPAddress"
+
+#
+# If you prefer to allocate a random IP address every time, use this query instead.
+# Note: This is very slow if you have a lot of free IPs.
+#
+#allocate_find = "\
+# WITH cte AS ( \
+# SELECT TOP(1) FramedIPAddress, NASIPAddress, pool_key, \
+# CallingStationId, UserName, expiry_time \
+# FROM ${ippool_table} \
+# WHERE pool_name = '%{control:${pool_name}}' \
+# AND expiry_time < CURRENT_TIMESTAMP \
+# ORDER BY newid() \
+# ) \
+# UPDATE cte WITH (rowlock, readpast) \
+# SET \
+# NASIPAddress = '%{NAS-IP-Address}', pool_key = '${pool_key}', \
+# CallingStationId = '%{Calling-Station-Id}', \
+# UserName = '%{User-Name}', expiry_time = DATEADD(SECOND,${lease_duration},CURRENT_TIMESTAMP) \
+# OUTPUT INSERTED.FramedIPAddress"
+
+#
+# If an IP could not be allocated, check to see if the pool exists or not
+# This allows the module to differentiate between a full pool and no pool
+# Note: If you are not running redundant pool modules this query may be
+# commented out to save running this query every time an ip is not allocated.
+#
+pool_check = "\
+ SELECT TOP(1) id \
+ FROM ${ippool_table} \
+ WHERE pool_name='%{control:${pool_name}}'"
+
+#
+# This is the final IP Allocation query, which saves the allocated ip details.
+# Only needed if allocate_existing / allocate_find do not also update the pool.
+#
+#allocate_update = "\
+# UPDATE ${ippool_table} \
+# SET \
+# NASIPAddress = '%{NAS-IP-Address}', pool_key = '${pool_key}', \
+# CallingStationId = '%{Calling-Station-Id}', \
+# UserName = '%{User-Name}', expiry_time = DATEADD(SECOND,${lease_duration},CURRENT_TIMESTAMP) \
+# WHERE FramedIPAddress = '%I'"
+
+#
+# Use a stored procedure to find AND allocate the address. Read and customise
+# `procedure.sql` in this directory to determine the optimal configuration.
+#
+#allocate_begin = ""
+#allocate_find = "\
+# EXEC fr_allocate_previous_or_new_framedipaddress \
+# @v_pool_name = '%{control:${pool_name}}', \
+# @v_username = '%{User-Name}', \
+# @v_callingstationid = '%{Calling-Station-Id}', \
+# @v_nasipaddress = '%{NAS-IP-Address}', \
+# @v_pool_key = '${pool_key}', \
+# @v_lease_duration = ${lease_duration} \
+# "
+#allocate_update = ""
+#allocate_commit = ""
+
+#
+# This series of queries frees an IP number when an accounting START record arrives.
+#
+start_update = "\
+ UPDATE ${ippool_table} \
+ SET \
+ expiry_time = DATEADD(SECOND,${lease_duration},CURRENT_TIMESTAMP) \
+ WHERE NASIPAddress = '%{NAS-IP-Address}' \
+ AND pool_key = '${pool_key}' \
+ AND UserName = '%{User-Name}' \
+ AND CallingStationId = '%{Calling-Station-Id}' \
+ AND FramedIPAddress = '%{${attribute_name}}'"
+
+#
+# Expire an IP when an accounting STOP record arrives
+#
+stop_clear = "\
+ UPDATE ${ippool_table} \
+ SET \
+ expiry_time = CURRENT_TIMESTAMP \
+ WHERE NASIPAddress = '%{%{Nas-IP-Address}:-%{Nas-IPv6-Address}}' \
+ AND pool_key = '${pool_key}' \
+ AND UserName = '%{User-Name}' \
+ AND CallingStationId = '%{Calling-Station-Id}' \
+ AND FramedIPAddress = '%{${attribute_name}}'"
+
+#
+# Update the expiry time for an IP when an accounting ALIVE record arrives
+#
+alive_update = "\
+ UPDATE ${ippool_table} \
+ SET \
+ expiry_time = DATEADD(SECOND,${lease_duration},CURRENT_TIMESTAMP) \
+ WHERE NASIPAddress = '%{%{Nas-IP-Address}:-%{Nas-IPv6-Address}}' \
+ AND pool_key = '${pool_key}' \
+ AND UserName = '%{User-Name}' \
+ AND CallingStationId = '%{Calling-Station-Id}' \
+ AND FramedIPAddress = '%{${attribute_name}}'"
+
+#
+# Expires all IPs allocated to a NAS when an accounting ON record arrives
+#
+on_clear = "\
+ UPDATE ${ippool_table} \
+ SET \
+ expiry_time = CURRENT_TIMESTAMP \
+ WHERE NASIPAddress = '%{%{Nas-IP-Address}:-%{Nas-IPv6-Address}}'"
+
+#
+# Expires all IPs allocated to a NAS when an accounting OFF record arrives
+#
+off_clear = "\
+ UPDATE ${ippool_table} \
+ SET \
+ expiry_time = CURRENT_TIMESTAMP \
+ WHERE NASIPAddress = '%{%{Nas-IP-Address}:-%{Nas-IPv6-Address}}'"
diff --git a/raddb/mods-config/sql/ippool/mssql/schema.sql b/raddb/mods-config/sql/ippool/mssql/schema.sql
new file mode 100644
index 0000000..d4bff44
--- /dev/null
+++ b/raddb/mods-config/sql/ippool/mssql/schema.sql
@@ -0,0 +1,25 @@
+--
+-- Table structure for table 'radippool'
+--
+CREATE TABLE radippool (
+ id int IDENTITY (1,1) NOT NULL,
+ pool_name varchar(30) NOT NULL,
+ FramedIPAddress varchar(15) NOT NULL default '',
+ NASIPAddress varchar(15) NOT NULL default '',
+ CalledStationId VARCHAR(32) NOT NULL default '',
+ CallingStationId VARCHAR(30) NOT NULL default '',
+ expiry_time DATETIME NOT NULL default CURRENT_TIMESTAMP,
+ UserName varchar(64) NOT NULL default '',
+ pool_key varchar(30) NOT NULL default '',
+ PRIMARY KEY (id)
+)
+GO
+
+CREATE INDEX poolname_expire ON radippool(pool_name, expiry_time)
+GO
+
+CREATE INDEX FramedIPAddress ON radippool(FramedIPAddress)
+GO
+
+CREATE INDEX NASIPAddress_poolkey_FramedIPAddress ON radippool(NASIPAddress, pool_key, FramedIPAddress)
+GO
diff --git a/raddb/mods-config/sql/ippool/mysql/procedure-no-skip-locked.sql b/raddb/mods-config/sql/ippool/mysql/procedure-no-skip-locked.sql
new file mode 100644
index 0000000..1c88446
--- /dev/null
+++ b/raddb/mods-config/sql/ippool/mysql/procedure-no-skip-locked.sql
@@ -0,0 +1,149 @@
+--
+-- A stored procedure to reallocate a user's previous address, otherwise
+-- provide a free address.
+--
+-- NOTE: This version of the SP is intended for MySQL variants that do not
+-- support the SKIP LOCKED pragma, i.e. MariaDB and versions of MySQL
+-- prior to 8.0. It should be a lot faster than using the default SP
+-- without the SKIP LOCKED pragma under highly concurrent workloads
+-- and not result in thread starvation.
+--
+-- It is however a *useful hack* which should not be used if SKIP
+-- LOCKED is available.
+--
+-- WARNING: This query uses server-local, "user locks" (GET_LOCK and
+-- RELEASE_LOCK), without the need for a transaction, to emulate
+-- row locking with locked-row skipping. User locks are not
+-- supported on clusters such as Galera and MaxScale.
+--
+-- Using this SP reduces the usual set dialogue of queries to a single
+-- query:
+--
+-- START TRANSACTION; SELECT FOR UPDATE; UPDATE; COMMIT; -> CALL sp()
+--
+-- The stored procedure is executed within a single round trip which often
+-- leads to reduced deadlocking and significant performance improvements.
+--
+-- To use this stored procedure the corresponding queries.conf statements must
+-- be configured as follows:
+--
+-- allocate_begin = ""
+-- allocate_find = "\
+-- CALL fr_allocate_previous_or_new_framedipaddress( \
+-- '%{control:${pool_name}}', \
+-- '%{User-Name}', \
+-- '%{Calling-Station-Id}', \
+-- '%{NAS-IP-Address}', \
+-- '${pool_key}', \
+-- ${lease_duration} \
+-- )"
+-- allocate_update = ""
+-- allocate_commit = ""
+--
+
+CREATE INDEX poolname_username_callingstationid ON radippool(pool_name,username,callingstationid);
+
+DELIMITER $$
+
+DROP PROCEDURE IF EXISTS fr_allocate_previous_or_new_framedipaddress;
+CREATE PROCEDURE fr_allocate_previous_or_new_framedipaddress (
+ IN v_pool_name VARCHAR(64),
+ IN v_username VARCHAR(64),
+ IN v_callingstationid VARCHAR(64),
+ IN v_nasipaddress VARCHAR(15),
+ IN v_pool_key VARCHAR(64),
+ IN v_lease_duration INT
+)
+SQL SECURITY INVOKER
+proc:BEGIN
+ DECLARE r_address VARCHAR(15);
+
+ -- Reissue an existing IP address lease when re-authenticating a session
+ --
+ SELECT framedipaddress INTO r_address
+ FROM radippool
+ WHERE pool_name = v_pool_name
+ AND expiry_time > NOW()
+ AND nasipaddress = v_nasipaddress
+ AND pool_key = v_pool_key
+ LIMIT 1;
+
+ -- Reissue an user's previous IP address, provided that the lease is
+ -- available (i.e. enable sticky IPs)
+ --
+ -- When using this SELECT you should delete the one above. You must also
+ -- set allocate_clear = "" in queries.conf to persist the associations
+ -- for expired leases.
+ --
+ -- SELECT framedipaddress INTO r_address
+ -- FROM radippool
+ -- WHERE pool_name = v_pool_name
+ -- AND nasipaddress = v_nasipaddress
+ -- AND pool_key = v_pool_key
+ -- LIMIT 1;
+
+ IF r_address IS NOT NULL THEN
+ UPDATE radippool
+ SET
+ nasipaddress = v_nasipaddress,
+ pool_key = v_pool_key,
+ callingstationid = v_callingstationid,
+ username = v_username,
+ expiry_time = NOW() + INTERVAL v_lease_duration SECOND
+ WHERE
+ framedipaddress = r_address;
+ SELECT r_address;
+ LEAVE proc;
+ END IF;
+
+ REPEAT
+
+ -- If we didn't reallocate a previous address then pick the least
+ -- recently used address from the pool which maximises the likelihood
+ -- of re-assigning the other addresses to their recent user
+ --
+ SELECT framedipaddress INTO r_address
+ FROM radippool
+ WHERE pool_name = v_pool_name
+ AND expiry_time < NOW()
+ --
+ -- WHERE ... GET_LOCK(...,0) = 1 is a poor man's SKIP LOCKED that simulates
+ -- a row-level lock using a "user lock" that allows the locked "rows" to be
+ -- skipped. After the user lock is acquired and the SELECT retired it does
+ -- not mean that the entirety of the WHERE clause is still true: Another
+ -- thread may have updated the expiry time and released the lock after we
+ -- checked the expiry_time but before we acquired the lock since SQL is free
+ -- to reorder the WHERE condition. Therefore we must recheck the condition
+ -- in the UPDATE statement below to detect this race.
+ --
+ AND GET_LOCK(CONCAT('radippool_', framedipaddress), 0) = 1
+ LIMIT 1;
+
+ IF r_address IS NULL THEN
+ DO RELEASE_LOCK(CONCAT('radippool_', r_address));
+ LEAVE proc;
+ END IF;
+
+ UPDATE radippool
+ SET
+ nasipaddress = v_nasipaddress,
+ pool_key = v_pool_key,
+ callingstationid = v_callingstationid,
+ username = v_username,
+ expiry_time = NOW() + INTERVAL v_lease_duration SECOND
+ WHERE
+ framedipaddress = r_address
+ --
+ -- Here we re-evaluate the original condition for selecting the address
+ -- to detect a race, in which case we try again...
+ --
+ AND expiry_time<NOW();
+
+ UNTIL ROW_COUNT() <> 0 END REPEAT;
+
+ DO RELEASE_LOCK(CONCAT('radippool_', r_address));
+ SELECT r_address;
+
+END$$
+
+DELIMITER ;
diff --git a/raddb/mods-config/sql/ippool/mysql/procedure.sql b/raddb/mods-config/sql/ippool/mysql/procedure.sql
new file mode 100644
index 0000000..2a52566
--- /dev/null
+++ b/raddb/mods-config/sql/ippool/mysql/procedure.sql
@@ -0,0 +1,139 @@
+--
+-- A stored procedure to reallocate a user's previous address, otherwise
+-- provide a free address.
+--
+-- Using this SP reduces the usual set dialogue of queries to a single
+-- query:
+--
+-- START TRANSACTION; SELECT FOR UPDATE; UPDATE; COMMIT; -> CALL sp()
+--
+-- The stored procedure is executed on an database instance within a single
+-- round trip which often leads to reduced deadlocking and significant
+-- performance improvements especially on multi-master clusters, perhaps even
+-- by an order of magnitude or more.
+--
+-- To use this stored procedure the corresponding queries.conf statements must
+-- be configured as follows:
+--
+-- allocate_begin = ""
+-- allocate_find = "\
+-- CALL fr_allocate_previous_or_new_framedipaddress( \
+-- '%{control:${pool_name}}', \
+-- '%{User-Name}', \
+-- '%{Calling-Station-Id}', \
+-- '%{Called-Station-Id}', \
+-- '%{NAS-IP-Address}', \
+-- '${pool_key}', \
+-- ${lease_duration} \
+-- )"
+-- allocate_update = ""
+-- allocate_commit = ""
+--
+
+CREATE INDEX poolname_username_callingstationid ON radippool(pool_name,username,callingstationid);
+
+DELIMITER $$
+
+DROP PROCEDURE IF EXISTS fr_allocate_previous_or_new_framedipaddress;
+CREATE PROCEDURE fr_allocate_previous_or_new_framedipaddress (
+ IN v_pool_name VARCHAR(64),
+ IN v_username VARCHAR(64),
+ IN v_callingstationid VARCHAR(64),
+ IN v_calledstationid VARCHAR(64),
+ IN v_nasipaddress VARCHAR(15),
+ IN v_pool_key VARCHAR(64),
+ IN v_lease_duration INT
+)
+SQL SECURITY INVOKER
+proc:BEGIN
+ DECLARE r_address VARCHAR(15);
+
+ DECLARE EXIT HANDLER FOR SQLEXCEPTION
+ BEGIN
+ ROLLBACK;
+ RESIGNAL;
+ END;
+
+ SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
+
+ START TRANSACTION;
+
+ -- Reissue an existing IP address lease when re-authenticating a session
+ --
+ SELECT framedipaddress INTO r_address
+ FROM radippool
+ WHERE pool_name = v_pool_name
+ AND expiry_time > NOW()
+ AND nasipaddress = v_nasipaddress
+ AND pool_key = v_pool_key
+ LIMIT 1
+ FOR UPDATE;
+-- FOR UPDATE SKIP LOCKED; -- Better performance, but limited support
+
+ -- NOTE: You should enable SKIP LOCKED here (as well as any other
+ -- instances) if your database server supports it. If it is not
+ -- supported and you are not running a multi-master cluster (e.g.
+ -- Galera or MaxScale) then you should instead consider using the
+ -- SP in procedure-no-skip-locked.sql which will be faster and
+ -- less likely to result in thread starvation under highly
+ -- concurrent load.
+
+ -- Reissue an user's previous IP address, provided that the lease is
+ -- available (i.e. enable sticky IPs)
+ --
+ -- When using this SELECT you should delete the one above. You must also
+ -- set allocate_clear = "" in queries.conf to persist the associations
+ -- for expired leases.
+ --
+ -- SELECT framedipaddress INTO r_address
+ -- FROM radippool
+ -- WHERE pool_name = v_pool_name
+ -- AND nasipaddress = v_nasipaddress
+ -- AND pool_key = v_pool_key
+ -- LIMIT 1
+ -- FOR UPDATE;
+ -- -- FOR UPDATE SKIP LOCKED; -- Better performance, but limited support
+
+ -- If we didn't reallocate a previous address then pick the least
+ -- recently used address from the pool which maximises the likelihood
+ -- of re-assigning the other addresses to their recent user
+ --
+ IF r_address IS NULL THEN
+ SELECT framedipaddress INTO r_address
+ FROM radippool
+ WHERE pool_name = v_pool_name
+ AND expiry_time < NOW()
+ ORDER BY
+ expiry_time
+ LIMIT 1
+ FOR UPDATE;
+-- FOR UPDATE SKIP LOCKED; -- Better performance, but limited support
+ END IF;
+
+ -- Return nothing if we failed to allocated an address
+ --
+ IF r_address IS NULL THEN
+ COMMIT;
+ LEAVE proc;
+ END IF;
+
+ -- Update the pool having allocated an IP address
+ --
+ UPDATE radippool
+ SET
+ nasipaddress = v_nasipaddress,
+ pool_key = v_pool_key,
+ callingstationid = v_callingstationid,
+ calledstationid = v_calledstationid,
+ username = v_username,
+ expiry_time = NOW() + INTERVAL v_lease_duration SECOND
+ WHERE framedipaddress = r_address;
+
+ COMMIT;
+
+ -- Return the address that we allocated
+ SELECT r_address;
+
+END$$
+
+DELIMITER ;
diff --git a/raddb/mods-config/sql/ippool/mysql/queries.conf b/raddb/mods-config/sql/ippool/mysql/queries.conf
new file mode 100644
index 0000000..c421020
--- /dev/null
+++ b/raddb/mods-config/sql/ippool/mysql/queries.conf
@@ -0,0 +1,156 @@
+# -*- text -*-
+#
+# ippool/mysql/queries.conf -- MySQL queries for rlm_sqlippool
+#
+# $Id$
+
+
+# Using SKIP LOCKED speeds up selection queries
+# However, it requires MySQL >= 8.0.1 or MariaDB >= 10.6.
+# Uncomment the following if you are running a suitable
+# version of MySQL
+#
+#skip_locked = "SKIP LOCKED"
+skip_locked = ""
+
+#
+# This series of queries allocates an IP address
+#
+
+#
+# Attempt to allocate the address a client previously had. This is based on pool_key
+# and nasipaddress. Change the criteria if the identifier for "stickyness" is different.
+# If different criteria are used, check the indexes on the IP pool table to ensure the fields
+# are appropriately indexed. To disable stickyness comment out this query.
+#
+allocate_existing = "\
+ SELECT framedipaddress FROM ${ippool_table} \
+ WHERE pool_name = '%{control:${pool_name}}' \
+ AND nasipaddress = '%{NAS-IP-Address}' AND pool_key = '${pool_key}' \
+ ORDER BY expiry_time DESC \
+ LIMIT 1 \
+ FOR UPDATE ${skip_locked}"
+
+#
+# Find a free IP address from the pool, choosing the oldest expired one.
+#
+allocate_find = "\
+ SELECT framedipaddress FROM ${ippool_table} \
+ WHERE pool_name = '%{control:${pool_name}}' \
+ AND expiry_time < NOW() \
+ ORDER BY expiry_time \
+ LIMIT 1 \
+ FOR UPDATE ${skip_locked}"
+
+#
+# If you prefer to allocate a random IP address every time, use this query instead.
+# Note: This is very slow if you have a lot of free IPs.
+#
+#allocate_find = "\
+# SELECT framedipaddress FROM ${ippool_table} \
+# WHERE pool_name = '%{control:${pool_name}}' \
+# AND expiry_time < NOW() \
+# ORDER BY \
+# RAND() \
+# LIMIT 1 \
+# FOR UPDATE ${skip_locked}"
+
+#
+# If an IP could not be allocated, check to see if the pool exists or not
+# This allows the module to differentiate between a full pool and no pool
+# Note: If you are not running redundant pool modules this query may be
+# commented out to save running this query every time an ip is not allocated.
+#
+pool_check = "\
+ SELECT id \
+ FROM ${ippool_table} \
+ WHERE pool_name='%{control:${pool_name}}' \
+ LIMIT 1"
+
+#
+# This is the final IP Allocation query, which saves the allocated ip details.
+#
+allocate_update = "\
+ UPDATE ${ippool_table} \
+ SET \
+ nasipaddress = '%{NAS-IP-Address}', pool_key = '${pool_key}', \
+ callingstationid = '%{Calling-Station-Id}', \
+ username = '%{User-Name}', expiry_time = NOW() + INTERVAL ${lease_duration} SECOND \
+ WHERE framedipaddress = '%I'"
+
+#
+# Use a stored procedure to find AND allocate the address. Read and customise
+# `procedure.sql` in this directory to determine the optimal configuration.
+#
+#allocate_begin = ""
+#allocate_find = "\
+# CALL fr_allocate_previous_or_new_framedipaddress( \
+# '%{control:${pool_name}}', \
+# '%{User-Name}', \
+# '%{Calling-Station-Id}', \
+# '%{Called-Station-Id}', \
+# '%{NAS-IP-Address}', \
+# '${pool_key}', \
+# ${lease_duration} \
+# )"
+#allocate_update = ""
+#allocate_commit = ""
+
+#
+# This series of queries frees an IP number when an accounting START record arrives.
+#
+start_update = "\
+ UPDATE ${ippool_table} \
+ SET \
+ expiry_time = NOW() + INTERVAL ${lease_duration} SECOND \
+ WHERE nasipaddress = '%{NAS-IP-Address}' \
+ AND pool_key = '${pool_key}' \
+ AND username = '%{User-Name}' \
+ AND callingstationid = '%{Calling-Station-Id}' \
+ AND framedipaddress = '%{${attribute_name}}'"
+
+#
+# This query expires an IP number when an accounting STOP record arrives.
+#
+stop_clear = "\
+ UPDATE ${ippool_table} \
+ SET \
+ expiry_time = NOW() \
+ WHERE nasipaddress = '%{%{Nas-IP-Address}:-%{Nas-IPv6-Address}}' \
+ AND pool_key = '${pool_key}' \
+ AND username = '%{User-Name}' \
+ AND callingstationid = '%{Calling-Station-Id}' \
+ AND framedipaddress = '%{${attribute_name}}'"
+
+#
+# This series of queries frees an IP number when an accounting ALIVE record arrives.
+#
+alive_update = "\
+ UPDATE ${ippool_table} \
+ SET \
+ expiry_time = NOW() + INTERVAL ${lease_duration} SECOND \
+ WHERE nasipaddress = '%{%{Nas-IP-Address}:-%{Nas-IPv6-Address}}' \
+ AND pool_key = '${pool_key}' \
+ AND username = '%{User-Name}' \
+ AND callingstationid = '%{Calling-Station-Id}' \
+ AND framedipaddress = '%{${attribute_name}}'"
+
+#
+# This series of queries expires the IP numbers allocate to a
+# NAS when an accounting ON record arrives
+#
+on_clear = "\
+ UPDATE ${ippool_table} \
+ SET \
+ expiry_time = NOW() \
+ WHERE nasipaddress = '%{%{Nas-IP-Address}:-%{Nas-IPv6-Address}}'"
+
+#
+# This series of queries expires the IP numbers allocate to a
+# NAS when an accounting OFF record arrives
+#
+off_clear = "\
+ UPDATE ${ippool_table} \
+ SET \
+ expiry_time = NOW() \
+ WHERE nasipaddress = '%{%{Nas-IP-Address}:-%{Nas-IPv6-Address}}'"
diff --git a/raddb/mods-config/sql/ippool/mysql/schema.sql b/raddb/mods-config/sql/ippool/mysql/schema.sql
new file mode 100644
index 0000000..f79d1b1
--- /dev/null
+++ b/raddb/mods-config/sql/ippool/mysql/schema.sql
@@ -0,0 +1,18 @@
+#
+# Table structure for table 'radippool'
+#
+CREATE TABLE IF NOT EXISTS radippool (
+ id int(11) unsigned NOT NULL auto_increment,
+ pool_name varchar(30) NOT NULL,
+ framedipaddress varchar(15) NOT NULL default '',
+ nasipaddress varchar(15) NOT NULL default '',
+ calledstationid VARCHAR(30) NOT NULL default '',
+ callingstationid VARCHAR(30) NOT NULL default '',
+ expiry_time DATETIME NOT NULL default NOW(),
+ username varchar(64) NOT NULL default '',
+ pool_key varchar(30) NOT NULL default '',
+ PRIMARY KEY (id),
+ KEY radippool_poolname_expire (pool_name, expiry_time),
+ KEY framedipaddress (framedipaddress),
+ KEY radippool_nasip_poolkey_ipaddress (nasipaddress, pool_key, framedipaddress)
+) ENGINE=InnoDB;
diff --git a/raddb/mods-config/sql/ippool/oracle/procedure.sql b/raddb/mods-config/sql/ippool/oracle/procedure.sql
new file mode 100644
index 0000000..e483236
--- /dev/null
+++ b/raddb/mods-config/sql/ippool/oracle/procedure.sql
@@ -0,0 +1,129 @@
+--
+-- A stored procedure to reallocate a user's previous address, otherwise
+-- provide a free address.
+--
+-- Using this SP reduces the usual set dialogue of queries to a single
+-- query:
+--
+-- BEGIN; SELECT FOR UPDATE; UPDATE; COMMIT; -> SELECT sp() FROM dual
+--
+-- The stored procedure is executed on an database instance within a single
+-- round trip which often leads to reduced deadlocking and significant
+-- performance improvements especially on multi-master clusters, perhaps even
+-- by an order of magnitude or more.
+--
+-- To use this stored procedure the corresponding queries.conf statements must
+-- be configured as follows:
+--
+-- allocate_begin = ""
+-- allocate_find = "\
+-- SELECT fr_allocate_previous_or_new_framedipaddress( \
+-- '%{control:${pool_name}}', \
+-- '%{User-Name}', \
+-- '%{%{Calling-Station-Id}:-0}', \
+-- '%{NAS-IP-Address}', \
+-- '${pool_key}', \
+-- ${lease_duration} \
+-- ) FROM dual"
+-- allocate_update = ""
+-- allocate_commit = ""
+--
+
+CREATE OR REPLACE FUNCTION fr_allocate_previous_or_new_framedipaddress (
+ v_pool_name IN VARCHAR2,
+ v_username IN VARCHAR2,
+ v_callingstationid IN VARCHAR2,
+ v_nasipaddress IN VARCHAR2,
+ v_pool_key IN VARCHAR2,
+ v_lease_duration IN INTEGER
+)
+RETURN varchar2 IS
+ PRAGMA AUTONOMOUS_TRANSACTION;
+ r_address varchar2(15);
+BEGIN
+
+ -- Reissue an existing IP address lease when re-authenticating a session
+ --
+ BEGIN
+ SELECT framedipaddress INTO r_address FROM radippool WHERE id IN (
+ SELECT id FROM (
+ SELECT *
+ FROM radippool
+ WHERE pool_name = v_pool_name
+ AND expiry_time > current_timestamp
+ AND username = v_username
+ AND callingstationid = v_callingstationid
+ ) WHERE ROWNUM <= 1
+ ) FOR UPDATE SKIP LOCKED;
+ EXCEPTION
+ WHEN NO_DATA_FOUND THEN
+ r_address := NULL;
+ END;
+
+ -- Reissue an user's previous IP address, provided that the lease is
+ -- available (i.e. enable sticky IPs)
+ --
+ -- When using this SELECT you should delete the one above. You must also
+ -- set allocate_clear = "" in queries.conf to persist the associations
+ -- for expired leases.
+ --
+ -- BEGIN
+ -- SELECT framedipaddress INTO r_address FROM radippool WHERE id IN (
+ -- SELECT id FROM (
+ -- SELECT *
+ -- FROM radippool
+ -- WHERE pool_name = v_pool_name
+ -- AND username = v_username
+ -- AND callingstationid = v_callingstationid
+ -- ) WHERE ROWNUM <= 1
+ -- ) FOR UPDATE SKIP LOCKED;
+ -- EXCEPTION
+ -- WHEN NO_DATA_FOUND THEN
+ -- r_address := NULL;
+ -- END;
+
+ -- If we didn't reallocate a previous address then pick the least
+ -- recently used address from the pool which maximises the likelihood
+ -- of re-assigning the other addresses to their recent user
+ --
+ IF r_address IS NULL THEN
+ BEGIN
+ SELECT framedipaddress INTO r_address FROM radippool WHERE id IN (
+ SELECT id FROM (
+ SELECT *
+ FROM radippool
+ WHERE pool_name = v_pool_name
+ AND expiry_time < CURRENT_TIMESTAMP
+ ORDER BY expiry_time
+ ) WHERE ROWNUM <= 1
+ ) FOR UPDATE SKIP LOCKED;
+ EXCEPTION
+ WHEN NO_DATA_FOUND THEN
+ r_address := NULL;
+ END;
+ END IF;
+
+ -- Return nothing if we failed to allocated an address
+ --
+ IF r_address IS NULL THEN
+ COMMIT;
+ RETURN r_address;
+ END IF;
+
+ -- Update the pool having allocated an IP address
+ --
+ UPDATE radippool
+ SET
+ nasipaddress = v_nasipaddress,
+ pool_key = v_pool_key,
+ callingstationid = v_callingstationid,
+ username = v_username,
+ expiry_time = CURRENT_TIMESTAMP + v_lease_duration * INTERVAL '1' SECOND(1)
+ WHERE framedipaddress = r_address;
+
+ -- Return the address that we allocated
+ COMMIT;
+ RETURN r_address;
+
+END;
+/
diff --git a/raddb/mods-config/sql/ippool/oracle/queries.conf b/raddb/mods-config/sql/ippool/oracle/queries.conf
new file mode 100644
index 0000000..1a64b28
--- /dev/null
+++ b/raddb/mods-config/sql/ippool/oracle/queries.conf
@@ -0,0 +1,172 @@
+# -*- text -*-
+#
+# ippool/oracle/queries.conf -- Oracle queries for rlm_sqlippool
+#
+# $Id$
+
+# Using SKIP LOCKED speeds up selection queries
+# However, it requires Oracle > 11g. It MAY work in 9i and 10g
+# but is not documented. Uncomment the following if you are
+# running a suitable version of Oracle
+#
+#skip_locked = "SKIP LOCKED"
+skip_locked = ""
+
+allocate_begin = "commit"
+start_begin = "commit"
+alive_begin = "commit"
+stop_begin = "commit"
+on_begin = "commit"
+off_begin = "commit"
+
+#
+# Attempt to allocate the address a client previously had. This is based on pool_key
+# and nasipaddress. Change the criteria if the identifier for "stickyness" is different.
+# If different criteria are used, check the indexes on the IP pool table to ensure the fields
+# are appropriately indexed. To disable stickyness comment out this query.
+#
+allocate_existing = "\
+ SELECT framedipaddress FROM ${ippool_table} WHERE id IN ( \
+ SELECT id FROM ( \
+ SELECT * \
+ FROM ${ippool_table} \
+ WHERE pool_name = '%{control:${pool_name}}' \
+ AND nasipaddress = '%{NAS-IP-Address}' AND pool_key = '${pool_key}' \
+ ) \
+ ORDER BY expiry_time DESC \
+ ) WHERE ROWNUM <= 1 \
+ ) FOR UPDATE ${skip_locked}"
+
+#
+# Find a free IP address from the pool, choosing the oldest expired one.
+#
+allocate_find = "\
+ SELECT framedipaddress FROM ${ippool_table} WHERE id IN ( \
+ SELECT id FROM ( \
+ SELECT * \
+ FROM ${ippool_table} \
+ WHERE pool_name = '%{control:${pool_name}}' \
+ AND expiry_time < current_timestamp \
+ ) \
+ ORDER BY expiry_time \
+ ) WHERE ROWNUM <= 1 \
+ ) FOR UPDATE ${skip_locked}"
+
+#
+# If you prefer to allocate a random IP address every time, use this query instead
+# Note: This is very slow if you have a lot of free IPs.
+#
+#allocate_find = "\
+# SELECT framedipaddress FROM ${ippool_table} WHERE id IN ( \
+# SELECT id FROM ( \
+# SELECT * \
+# FROM ${ippool_table} \
+# WHERE pool_name = '%{control:${pool_name}}' \
+# AND expiry_time < current_timestamp \
+# ORDER BY DBMS_RANDOM.VALUE \
+# ) WHERE ROWNUM <= 1 \
+# ) FOR UPDATE ${skip_locked}"
+
+#
+# If an IP could not be allocated, check to see whether the pool exists or not
+# This allows the module to differentiate between a full pool and no pool
+# Note: If you are not running redundant pool modules this query may be commented
+# out to save running this query every time an ip is not allocated.
+#
+pool_check = "\
+ SELECT id \
+ FROM (\
+ SELECT id \
+ FROM ${ippool_table} \
+ WHERE pool_name='%{control:${pool_name}}'\
+ ) \
+ WHERE ROWNUM = 1"
+
+#
+# This query marks the IP address handed out by "allocate-find" as used
+# for the period of "lease_duration" after which time it may be reused.
+#
+allocate_update = "\
+ UPDATE ${ippool_table} \
+ SET \
+ nasipaddress = '%{NAS-IP-Address}', \
+ pool_key = '${pool_key}', \
+ callingstationid = '%{%{Calling-Station-Id}:-0}', \
+ username = '%{SQL-User-Name}', \
+ expiry_time = current_timestamp + INTERVAL '${lease_duration}' second(1) \
+ WHERE framedipaddress = '%I'"
+
+#
+# Use a stored procedure to find AND allocate the address. Read and customise
+# `procedure.sql` in this directory to determine the optimal configuration.
+#
+#allocate_begin = ""
+#allocate_find = "\
+# SELECT fr_allocate_previous_or_new_framedipaddress( \
+# '%{control:${pool_name}}', \
+# '%{SQL-User-Name}', \
+# '%{%{Calling-Station-Id}:-0}', \
+# '%{NAS-IP-Address}', \
+# '${pool_key}', \
+# '${lease_duration}' \
+# )"
+#allocate_update = ""
+#allocate_commit = ""
+
+#
+# This query extends an IP address lease by "lease_duration" when an accounting
+# START record arrives
+#
+start_update = "\
+ UPDATE ${ippool_table} \
+ SET \
+ expiry_time = current_timestamp + INTERVAL '${lease_duration}' second(1) \
+ WHERE nasipaddress = '%{NAS-IP-Address}' \
+ AND pool_key = '${pool_key}'"
+
+#
+# This query expires an IP address when an accounting STOP record arrives
+#
+stop_clear = "\
+ UPDATE ${ippool_table} \
+ SET \
+ expiry_time = current_timestamp - INTERVAL '1' second(1) \
+ WHERE nasipaddress = '%{%{Nas-IP-Address}:-%{Nas-IPv6-Address}}' \
+ AND pool_key = '${pool_key}' \
+ AND username = '%{SQL-User-Name}' \
+ AND callingstationid = '%{%{Calling-Station-Id}:-0}' \
+ AND framedipaddress = '%{${attribute_name}}'"
+
+#
+# This query extends an IP address lease by "lease_duration" when an accounting
+# ALIVE record arrives
+#
+alive_update = "\
+ UPDATE ${ippool_table} \
+ SET \
+ expiry_time = current_timestamp + INTERVAL '${lease_duration}' second(1) \
+ WHERE nasipaddress = '%{%{Nas-IP-Address}:-%{Nas-IPv6-Address}}' \
+ AND pool_key = '${pool_key}' \
+ AND framedipaddress = '%{${attribute_name}}' \
+ AND username = '%{SQL-User-Name}' \
+ AND callingstationid = '%{%{Calling-Station-Id}:-0}'"
+
+#
+# This query expires all IP addresses allocated to a NAS when an
+# accounting ON record arrives from that NAS
+#
+on_clear = "\
+ UPDATE ${ippool_table} \
+ SET \
+ expiry_time = current_timestamp - INTERVAL '1' second(1) \
+ WHERE nasipaddress = '%{%{Nas-IP-Address}:-%{Nas-IPv6-Address}}'"
+
+#
+# This query expires all IP addresses allocated to a NAS when an
+# accounting OFF record arrives from that NAS
+#
+off_clear = "\
+ UPDATE ${ippool_table} \
+ SET \
+ expiry_time = current_timestamp - INTERVAL '1' second(1) \
+ WHERE nasipaddress = '%{%{Nas-IP-Address}:-%{Nas-IPv6-Address}}'"
diff --git a/raddb/mods-config/sql/ippool/oracle/schema.sql b/raddb/mods-config/sql/ippool/oracle/schema.sql
new file mode 100644
index 0000000..adf1419
--- /dev/null
+++ b/raddb/mods-config/sql/ippool/oracle/schema.sql
@@ -0,0 +1,27 @@
+CREATE TABLE radippool (
+ id INT PRIMARY KEY,
+ pool_name VARCHAR(30) NOT NULL,
+ framedipaddress VARCHAR(15) NOT NULL,
+ nasipaddress VARCHAR(15) NOT NULL,
+ pool_key VARCHAR(30) DEFAULT '',
+ CalledStationId VARCHAR(64) DEFAULT '',
+ CallingStationId VARCHAR(64) DEFAULT '',
+ expiry_time timestamp(0) DEFAULT CURRENT_TIMESTAMP,
+ username VARCHAR(64) DEFAULT ''
+);
+
+CREATE INDEX radippool_poolname_expire ON radippool (pool_name, expiry_time);
+CREATE INDEX radippool_framedipaddress ON radippool (framedipaddress);
+CREATE INDEX radippool_nasip_poolkey_ipaddress ON radippool (nasipaddress, pool_key, framedipaddress);
+
+CREATE SEQUENCE radippool_seq START WITH 1 INCREMENT BY 1;
+
+CREATE OR REPLACE TRIGGER radippool_serialnumber
+ BEFORE INSERT OR UPDATE OF id ON radippool
+ FOR EACH ROW
+ BEGIN
+ if ( :new.id = 0 or :new.id is null ) then
+ SELECT radippool_seq.nextval into :new.id from dual;
+ end if;
+ END;
+/
diff --git a/raddb/mods-config/sql/ippool/postgresql/procedure.sql b/raddb/mods-config/sql/ippool/postgresql/procedure.sql
new file mode 100644
index 0000000..b1d580c
--- /dev/null
+++ b/raddb/mods-config/sql/ippool/postgresql/procedure.sql
@@ -0,0 +1,111 @@
+--
+-- A stored procedure to reallocate a user's previous address, otherwise
+-- provide a free address.
+--
+-- Using this SP reduces the usual set dialogue of queries to a single
+-- query:
+--
+-- START TRANSACTION; SELECT FOR UPDATE; UPDATE; COMMIT; -> SELECT sp()
+--
+-- The stored procedure is executed on an database instance within a single
+-- round trip which often leads to reduced deadlocking and significant
+-- performance improvements especially on multi-master clusters, perhaps even
+-- by an order of magnitude or more.
+--
+-- To use this stored procedure the corresponding queries.conf statements must
+-- be configured as follows:
+--
+-- allocate_begin = ""
+-- allocate_find = "\
+-- SELECT fr_allocate_previous_or_new_framedipaddress( \
+-- '%{control:${pool_name}}', \
+-- '%{User-Name}', \
+-- '%{Calling-Station-Id}', \
+-- '%{NAS-IP-Address}', \
+-- '${pool_key}', \
+-- ${lease_duration} \
+-- )"
+-- allocate_update = ""
+-- allocate_commit = ""
+--
+
+CREATE INDEX radippool_poolname_username_callingstationid ON radippool(pool_name,username,callingstationid);
+
+CREATE OR REPLACE FUNCTION fr_allocate_previous_or_new_framedipaddress (
+ v_pool_name VARCHAR(64),
+ v_username VARCHAR(64),
+ v_callingstationid VARCHAR(64),
+ v_nasipaddress VARCHAR(16),
+ v_pool_key VARCHAR(64),
+ v_lease_duration INT
+)
+RETURNS inet
+LANGUAGE plpgsql
+AS $$
+DECLARE
+ r_address inet;
+BEGIN
+
+ -- Reissue an existing IP address lease when re-authenticating a session
+ --
+ SELECT framedipaddress INTO r_address
+ FROM radippool
+ WHERE pool_name = v_pool_name
+ AND expiry_time > NOW()
+ AND username = v_username
+ AND callingstationid = v_callingstationid
+ LIMIT 1
+ FOR UPDATE SKIP LOCKED;
+
+ -- Reissue an user's previous IP address, provided that the lease is
+ -- available (i.e. enable sticky IPs)
+ --
+ -- When using this SELECT you should delete the one above. You must also
+ -- set allocate_clear = "" in queries.conf to persist the associations
+ -- for expired leases.
+ --
+ -- SELECT framedipaddress INTO r_address
+ -- FROM radippool
+ -- WHERE pool_name = v_pool_name
+ -- AND username = v_username
+ -- AND callingstationid = v_callingstationid
+ -- LIMIT 1
+ -- FOR UPDATE SKIP LOCKED;
+
+ -- If we didn't reallocate a previous address then pick the least
+ -- recently used address from the pool which maximises the likelihood
+ -- of re-assigning the other addresses to their recent user
+ --
+ IF r_address IS NULL THEN
+ SELECT framedipaddress INTO r_address
+ FROM radippool
+ WHERE pool_name = v_pool_name
+ AND expiry_time < NOW()
+ ORDER BY
+ expiry_time
+ LIMIT 1
+ FOR UPDATE SKIP LOCKED;
+ END IF;
+
+ -- Return nothing if we failed to allocated an address
+ --
+ IF r_address IS NULL THEN
+ RETURN r_address;
+ END IF;
+
+ -- Update the pool having allocated an IP address
+ --
+ UPDATE radippool
+ SET
+ nasipaddress = v_nasipaddress,
+ pool_key = v_pool_key,
+ callingstationid = v_callingstationid,
+ username = v_username,
+ expiry_time = NOW() + v_lease_duration * interval '1 sec'
+ WHERE framedipaddress = r_address;
+
+ -- Return the address that we allocated
+ RETURN r_address;
+
+END
+$$;
diff --git a/raddb/mods-config/sql/ippool/postgresql/queries.conf b/raddb/mods-config/sql/ippool/postgresql/queries.conf
new file mode 100644
index 0000000..ce6f355
--- /dev/null
+++ b/raddb/mods-config/sql/ippool/postgresql/queries.conf
@@ -0,0 +1,207 @@
+# -*- text -*-
+#
+# ippool/postgresql/queries.conf -- PostgreSQL queries for rlm_sqlippool
+#
+# $Id$
+
+
+# Using SKIP LOCKED speeds up selection queries
+# However, it requires PostgreSQL >= 9.5 Uncomment the
+# following if you are running a suitable version of PostgreSQL
+#
+#skip_locked = "SKIP LOCKED"
+skip_locked = ""
+
+#
+# This series of queries allocates an IP address
+#
+
+#
+# The suggested queries locate IPs and update them in one query
+# so no need for transaction wrappers
+#
+allocate_begin = ""
+allocate_commit = ""
+
+#
+# Attempt to allocate the address a client previously had. This is based on pool_key
+# and nasipaddress. Change the criteria if the identifier for "stickyness" is different.
+# If different criteria are used, check the indexes on the IP pool table to ensure the fields
+# are appropriately indexed. To disable stickyness comment out this query.
+#
+allocate_existing = "\
+ WITH cte AS ( \
+ SELECT framedipaddress FROM ${ippool_table} \
+ WHERE pool_name = '%{control:${pool_name}}' \
+ AND nasipaddress = '%{NAS-IP-Address}' AND pool_key = '${pool_key}' \
+ ORDER BY expiry_time DESC \
+ LIMIT 1 \
+ FOR UPDATE ${skip_locked} \
+ ) \
+ UPDATE ${ippool_table} \
+ SET \
+ nasipaddress = '%{NAS-IP-Address}', \
+ pool_key = '${pool_key}', \
+ callingstationid = '%{Calling-Station-Id}', \
+ username = '%{SQL-User-Name}', \
+ expiry_time = 'now'::timestamp(0) + '${lease_duration} second'::interval \
+ FROM cte WHERE cte.framedipaddress = ${ippool_table}.framedipaddress \
+ RETURNING cte.framedipaddress"
+
+#
+# Find a free IP address from the pool, choosing the oldest expired one.
+#
+allocate_find = "\
+ WITH cte AS ( \
+ SELECT framedipaddress FROM ${ippool_table} \
+ WHERE pool_name = '%{control:${pool_name}}' \
+ AND expiry_time < 'now'::timestamp(0) \
+ ORDER BY expiry_time \
+ LIMIT 1 \
+ FOR UPDATE ${skip_locked} \
+ ) \
+ UPDATE ${ippool_table} \
+ SET \
+ nasipaddress = '%{NAS-IP-Address}', \
+ pool_key = '${pool_key}', \
+ callingstationid = '%{Calling-Station-Id}', \
+ username = '%{SQL-User-Name}', \
+ expiry_time = 'now'::timestamp(0) + '${lease_duration} second'::interval \
+ FROM cte WHERE cte.framedipaddress = ${ippool_table}.framedipaddress \
+ RETURNING cte.framedipaddress"
+
+#
+# If you prefer to allocate a random IP address every time, use this query instead
+# Note: This is very slow if you have a lot of free IPs.
+#
+#allocate_find = "\
+# WITH cte AS ( \
+# SELECT framedipaddress FROM ${ippool_table} \
+# WHERE pool_name = '%{control:${pool_name}}' \
+# AND expiry_time < 'now'::timestamp(0) \
+# ORDER BY RANDOM() \
+# LIMIT 1 \
+# FOR UPDATE ${skip_locked} \
+# ) \
+# UPDATE ${ippool_table} \
+# SET \
+# nasipaddress = '%{NAS-IP-Address}', \
+# pool_key = '${pool_key}', \
+# callingstationid = '%{Calling-Station-Id}', \
+# username = '%{SQL-User-Name}', \
+# expiry_time = 'now'::timestamp(0) + '${lease_duration} second'::interval \
+# FROM cte WHERE cte.framedipaddress = ${ippool_table}.framedipaddress \
+# RETURNING cte.framedipaddress"
+
+#
+# If an IP could not be allocated, check to see whether the pool exists or not
+# This allows the module to differentiate between a full pool and no pool
+# Note: If you are not running redundant pool modules this query may be commented
+# out to save running this query every time an ip is not allocated.
+#
+pool_check = "\
+ SELECT id \
+ FROM ${ippool_table} \
+ WHERE pool_name='%{control:${pool_name}}' \
+ LIMIT 1"
+
+#
+# This query marks the IP address handed out by "allocate-find" as used
+# for the period of "lease_duration" after which time it may be reused.
+# This is only needed if the allocate_existing / allocate_find queries
+# do not update the pool
+#
+#allocate_update = "\
+# UPDATE ${ippool_table} \
+# SET \
+# nasipaddress = '%{NAS-IP-Address}', \
+# pool_key = '${pool_key}', \
+# callingstationid = '%{Calling-Station-Id}', \
+# username = '%{SQL-User-Name}', \
+# expiry_time = 'now'::timestamp(0) + '${lease_duration} second'::interval \
+# WHERE framedipaddress = '%I'"
+
+#
+# Use a stored procedure to find AND allocate the address. Read and customise
+# `procedure.sql` in this directory to determine the optimal configuration.
+#
+# This requires PostgreSQL >= 9.5 as SKIP LOCKED is used.
+#
+# The "NO LOAD BALANCE" comment is included here to indicate to a PgPool
+# system that this needs to be a write transaction. PgPool itself cannot
+# detect this from the statement alone. If you are using PgPool and do not
+# have this comment, the query may go to a read only server, and will fail.
+# This has no negative effect if you are not using PgPool.
+#
+#allocate_begin = ""
+#allocate_find = "\
+# /*NO LOAD BALANCE*/ \
+# SELECT fr_allocate_previous_or_new_framedipaddress( \
+# '%{control:${pool_name}}', \
+# '%{SQL-User-Name}', \
+# '%{Calling-Station-Id}', \
+# '%{NAS-IP-Address}', \
+# '${pool_key}', \
+# '${lease_duration}' \
+# )"
+#allocate_update = ""
+#allocate_commit = ""
+
+#
+# This query extends an IP address lease by "lease_duration" when an accounting
+# START record arrives
+#
+start_update = "\
+ UPDATE ${ippool_table} \
+ SET \
+ expiry_time = 'now'::timestamp(0) + '${lease_duration} second'::interval \
+ WHERE nasipaddress = '%{NAS-IP-Address}' \
+ AND pool_key = '${pool_key}'"
+
+#
+# This query expires an IP address when an accounting
+# STOP record arrives
+#
+stop_clear = "\
+ UPDATE ${ippool_table} \
+ SET \
+ expiry_time = 'now'::timestamp(0) - '1 second'::interval \
+ WHERE nasipaddress = '%{%{Nas-IP-Address}:-%{Nas-IPv6-Address}}' \
+ AND pool_key = '${pool_key}' \
+ AND username = '%{SQL-User-Name}' \
+ AND callingstationid = '%{Calling-Station-Id}' \
+ AND framedipaddress = '%{${attribute_name}}'"
+
+#
+# This query extends an IP address lease by "lease_duration" when an accounting
+# ALIVE record arrives
+#
+alive_update = "\
+ UPDATE ${ippool_table} \
+ SET \
+ expiry_time = 'now'::timestamp(0) + '${lease_duration} seconds'::interval \
+ WHERE nasipaddress = '%{%{Nas-IP-Address}:-%{Nas-IPv6-Address}}' \
+ AND pool_key = '${pool_key}' \
+ AND framedipaddress = '%{${attribute_name}}' \
+ AND username = '%{SQL-User-Name}' \
+ AND callingstationid = '%{Calling-Station-Id}'"
+
+#
+# This query expires all IP addresses allocated to a NAS when an
+# accounting ON record arrives from that NAS
+#
+on_clear = "\
+ UPDATE ${ippool_table} \
+ SET \
+ expiry_time = 'now'::timestamp(0) - '1 second'::interval \
+ WHERE nasipaddress = '%{%{Nas-IP-Address}:-%{Nas-IPv6-Address}}'"
+
+#
+# This query expires all IP addresses allocated to a NAS when an
+# accounting OFF record arrives from that NAS
+#
+off_clear = "\
+ UPDATE ${ippool_table} \
+ SET \
+ expiry_time = 'now'::timestamp(0) - '1 second'::interval \
+ WHERE nasipaddress = '%{%{Nas-IP-Address}:-%{Nas-IPv6-Address}}'"
diff --git a/raddb/mods-config/sql/ippool/postgresql/schema.sql b/raddb/mods-config/sql/ippool/postgresql/schema.sql
new file mode 100644
index 0000000..1ef57b7
--- /dev/null
+++ b/raddb/mods-config/sql/ippool/postgresql/schema.sql
@@ -0,0 +1,22 @@
+--
+-- Table structure for table 'radippool'
+--
+-- See also "procedure.sql" in this directory for additional
+-- indices and a stored procedure that is much faster.
+--
+
+CREATE TABLE radippool (
+ id BIGSERIAL PRIMARY KEY,
+ pool_name text NOT NULL,
+ FramedIPAddress INET NOT NULL,
+ NASIPAddress text NOT NULL default '',
+ pool_key text NOT NULL default '',
+ CalledStationId text NOT NULL default '',
+ CallingStationId text NOT NULL default ''::text,
+ expiry_time TIMESTAMP(0) without time zone NOT NULL default NOW(),
+ username text DEFAULT ''::text
+);
+
+CREATE INDEX radippool_poolname_expire ON radippool USING btree (pool_name, expiry_time);
+CREATE INDEX radippool_framedipaddress ON radippool USING btree (framedipaddress);
+CREATE INDEX radippool_nasip_poolkey_ipaddress ON radippool USING btree (nasipaddress, pool_key, framedipaddress);
diff --git a/raddb/mods-config/sql/ippool/sqlite/queries.conf b/raddb/mods-config/sql/ippool/sqlite/queries.conf
new file mode 100644
index 0000000..46ce58e
--- /dev/null
+++ b/raddb/mods-config/sql/ippool/sqlite/queries.conf
@@ -0,0 +1,148 @@
+# -*- text -*-
+#
+# ippool/sqlite/queries.conf -- SQLite queries for rlm_sqlippool
+#
+# $Id$
+
+#
+# SQLite does not implement SELECT FOR UPDATE which is normally used to place
+# an exclusive lock over rows to prevent the same address from being
+# concurrently selected for allocation to multiple users.
+#
+# The most granular read-blocking lock that SQLite has is an exclusive lock
+# over the database, so that's what we use. All locking in SQLite is performed
+# over the entire database and we perform a row update for any IP that we
+# allocate, requiring an exclusive lock. Taking the exclusive lock from the
+# start of the transaction (even if it were not required to guard the SELECT)
+# is actually quicker than if we deferred it causing SQLite to "upgrade" the
+# automatic shared lock for the transaction to an exclusive lock for the
+# subsequent UPDATE.
+#
+allocate_begin = "BEGIN EXCLUSIVE"
+allocate_commit = "COMMIT"
+
+#
+# This series of queries allocates an IP address
+#
+
+#
+# Attempt to allocate the address a client previously had. This is based on pool_key
+# and nasipaddress. Change the criteria if the identifier for "stickyness" is different.
+# If different criteria are used, check the indexes on the IP pool table to ensure the fields
+# are appropriately indexed. To disable stickyness comment out this query.
+#
+allocate_existing = "\
+ SELECT framedipaddress \
+ FROM ${ippool_table} \
+ WHERE pool_name = '%{control:${pool_name}}' \
+ AND nasipaddress = '%{NAS-IP-Address}' AND pool_key = '${pool_key}' \
+ ORDER BY expiry_time DESC \
+ LIMIT 1"
+
+#
+# Find a free IP address from the pool, choosing the oldest expired one.
+#
+allocate_find = "\
+ SELECT framedipaddress \
+ FROM ${ippool_table} \
+ WHERE pool_name = '%{control:${pool_name}}' \
+ expiry_time < datetime('now') \
+ ORDER BY expiry_time \
+ LIMIT 1"
+
+#
+# If you prefer to allocate a random IP address every time, i
+# use this query instead
+# Note: This is very slow if you have a lot of free IPs.
+#
+
+#allocate_find = "\
+# SELECT framedipaddress \
+# FROM ${ippool_table} \
+# WHERE pool_name = '%{control:${pool_name}}' \
+# AND expiry_time IS NULL \
+# ORDER BY RAND() \
+# LIMIT 1"
+
+#
+# If an IP could not be allocated, check to see if the pool exists or not
+# This allows the module to differentiate between a full pool and no pool
+# Note: If you are not running redundant pool modules this query may be
+# commented out to save running this query every time an ip is not allocated.
+#
+pool_check = "\
+ SELECT id \
+ FROM ${ippool_table} \
+ WHERE pool_name='%{control:${pool_name}}' \
+ LIMIT 1"
+
+#
+# This is the final IP Allocation query, which saves the allocated ip details
+#
+allocate_update = "\
+ UPDATE ${ippool_table} \
+ SET \
+ nasipaddress = '%{NAS-IP-Address}', \
+ pool_key = '${pool_key}', \
+ callingstationid = '%{Calling-Station-Id}', \
+ username = '%{User-Name}', \
+ expiry_time = datetime(strftime('%%s', 'now') + ${lease_duration}, 'unixepoch') \
+ WHERE framedipaddress = '%I'"
+
+#
+# Extend an IP expiry time when an accounting START record arrives
+#
+start_update = "\
+ UPDATE ${ippool_table} \
+ SET \
+ expiry_time = datetime(strftime('%%s', 'now') + ${lease_duration}, 'unixepoch') \
+ WHERE nasipaddress = '%{NAS-IP-Address}' \
+ AND pool_key = '${pool_key}' \
+ AND username = '%{User-Name}' \
+ AND callingstationid = '%{Calling-Station-Id}' \
+ AND framedipaddress = '%{${attribute_name}}'"
+
+#
+# Expire an IP when an accounting STOP record arrives
+#
+stop_clear = "\
+ UPDATE ${ippool_table} \
+ SET \
+ expiry_time = datetime('now') \
+ WHERE nasipaddress = '%{%{Nas-IP-Address}:-%{Nas-IPv6-Address}}' \
+ AND pool_key = '${pool_key}' \
+ AND username = '%{User-Name}' \
+ AND callingstationid = '%{Calling-Station-Id}' \
+ AND framedipaddress = '%{${attribute_name}}'"
+
+#
+# Update the expiry time for an IP when an accounting ALIVE record arrives
+#
+alive_update = "\
+ UPDATE ${ippool_table} \
+ SET \
+ expiry_time = datetime(strftime('%%s', 'now') + ${lease_duration}, 'unixepoch') \
+ WHERE nasipaddress = '%{%{Nas-IP-Address}:-%{Nas-IPv6-Address}}' \
+ AND pool_key = '${pool_key}' \
+ AND username = '%{User-Name}' \
+ AND callingstationid = '%{Calling-Station-Id}' \
+ AND framedipaddress = '%{${attribute_name}}'"
+
+#
+# Expires all IPs allocated to a NAS when an accounting ON record arrives
+#
+on_clear = "\
+ UPDATE ${ippool_table} \
+ SET \
+ expiry_time = datetime('now') \
+ WHERE nasipaddress = '%{%{Nas-IP-Address}:-%{Nas-IPv6-Address}}'"
+
+#
+# Expires all IPs allocated to a NAS when an accounting OFF record arrives
+#
+off_clear = "\
+ UPDATE ${ippool_table} \
+ SET \
+ expiry_time = datetime('now') \
+ WHERE nasipaddress = '%{%{Nas-IP-Address}:-%{Nas-IPv6-Address}}'"
+
diff --git a/raddb/mods-config/sql/ippool/sqlite/schema.sql b/raddb/mods-config/sql/ippool/sqlite/schema.sql
new file mode 100644
index 0000000..b020c62
--- /dev/null
+++ b/raddb/mods-config/sql/ippool/sqlite/schema.sql
@@ -0,0 +1,18 @@
+--
+-- Table structure for table 'radippool'
+--
+CREATE TABLE radippool (
+ id int(11) PRIMARY KEY,
+ pool_name varchar(30) NOT NULL,
+ framedipaddress varchar(15) NOT NULL default '',
+ nasipaddress varchar(15) NOT NULL default '',
+ calledstationid VARCHAR(30) NOT NULL default '',
+ callingstationid VARCHAR(30) NOT NULL default '',
+ expiry_time DATETIME NOT NULL default (DATETIME('now')),
+ username varchar(64) NOT NULL default '',
+ pool_key varchar(30) NOT NULL default ''
+);
+
+CREATE INDEX radippool_poolname_expire ON radippool(pool_name, expiry_time);
+CREATE INDEX radippool_framedipaddress ON radippool(framedipaddress);
+CREATE INDEX radippool_nasip_poolkey_ipaddress ON radippool(nasipaddress, pool_key, framedipaddress);
diff --git a/raddb/mods-config/sql/main/mongo/queries.conf b/raddb/mods-config/sql/main/mongo/queries.conf
new file mode 100644
index 0000000..732e1e8
--- /dev/null
+++ b/raddb/mods-config/sql/main/mongo/queries.conf
@@ -0,0 +1,289 @@
+# -*- text -*-
+#
+# main/mongo/queries.conf -- Mongo configuration queries
+#
+# Note that as Mongo is a "schemaless" database, there is no
+# default schema.
+#
+# Note also that the Mongo driver is a work in progress. If it works
+# for you, great. If the queries do not work, please send a patch.
+# But the FreeRADIUS team are not experts in Mongo, and cannot help
+# with creating Mongo queries.
+#
+# $Id$
+
+#######################################################################
+# Query config: Username
+#######################################################################
+# This is the username that will get substituted, escaped, and added
+# as attribute 'SQL-User-Name'. '%{SQL-User-Name}' should be used
+# below everywhere a username substitution is needed so you you can
+# be sure the username passed from the client is escaped properly.
+#
+# Uncomment the next line, if you want the sql_user_name to mean:
+#
+# Use Stripped-User-Name, if it's there.
+# Else use User-Name, if it's there,
+# Else use hard-coded string "none" as the user name.
+#
+#sql_user_name = "%{%{Stripped-User-Name}:-%{%{User-Name}:-none}}"
+
+sql_user_name = "%{User-Name}"
+
+#######################################################################
+# Authorization Queries
+#######################################################################
+# These queries compare the check items for the user
+# in ${authcheck_table} and setup the reply items in
+# ${authreply_table}. You can use any query/tables
+# you want, but the return data for each row MUST
+# be in the following order:
+#
+# 0. Row ID (currently unused)
+# 1. UserName/GroupName
+# 2. Item Attr Name
+# 3. Item Attr Value
+# 4. Item Attr Operation
+#######################################################################
+
+#
+# Aggregate query that return like for SQL standard N rows with columns <id>,<username>,<attribute>,<value>,<op>
+#
+# Example of Result:
+#
+# { "id" : 0, "username": "bob", "attribute" : "User-Name", "Value" : "pippo", "op" : "==" }
+# { "id" : 0, "username": "bob", "attribute" : "ClearText-Password", "value" : "pwd1", "op" : ":=" }
+# { "id" : 0, "username": "bob", "attribute" : "Cache-TTL", "value" : 1000, "op" : ":=" }
+#
+authorize_check_query = "db.${authcheck_table}.aggregate([ \
+ { \
+ '$match': { \
+ 'calling_station_id': '%{Calling-Station-id}', \
+ 'auth_blocked': 'false' \
+ } \
+ }, \
+ { \
+ '$addFields': { \
+ 'attributes.User-Name': '$usr', \
+ 'attributes.ClearText-Password': '$pwd', \
+ 'attributes.Cache-TTL': '$ttlcache', \
+ 'attributes.Enable-Roaming': '$roaming', \
+ 'attributes.Pool-Name': '$pool_name' \
+ } \
+ }, \
+ { \
+ '$project': { \
+ 'calling_station_id': 1, \
+ 'attributes': { \
+ '$objectToArray': '$attributes' \
+ } \
+ } \
+ }, \
+ { \
+ '$unwind': '$attributes' \
+ }, \
+ { \
+ '$project': { \
+ '_id': 0, \
+ 'username': '', \
+ 'attribute': '$attributes.k', \
+ 'value': '$attributes.v', \
+ 'op': ':=' \
+ } \
+ } \
+])" \
+
+# TBD: fill in things here
+authorize_reply_query = ""
+
+##################################################################
+
+#
+# TBD: fill in things here
+#
+#authorize_group_check_query = ""
+#authorize_group_reply_query = ""
+
+#######################################################################
+# Group Membership Queries
+#######################################################################
+# group_membership_query - Check user group membership
+#######################################################################
+
+#
+# TBD: Fill in things here.
+#
+#group_membership_query = ""
+
+
+#######################################################################
+# Accounting and Post-Auth Queries
+#######################################################################
+# These queries insert/update accounting and authentication records.
+# The query to use is determined by the value of 'reference'.
+# This value is used as a configuration path and should resolve to one
+# or more 'query's. If reference points to multiple queries, and a query
+# fails, the next query is executed.
+#
+# Behaviour is identical to the old 1.x/2.x module, except we can now
+# fail between N queries, and query selection can be based on any
+# combination of attributes, or custom 'Acct-Status-Type' values.
+#######################################################################
+
+accounting {
+ reference = "%{tolower:type.%{Acct-Status-Type}.query}"
+
+ type {
+
+ start {
+ query = "db.connections.findAndModify({ \
+ 'query': { \
+ 'calling_station_id': '%{Calling-Station-Id}', \
+ 'pgw_node': '%{NAS-Identifier}', \
+ 'acct_session_id': '%{Acct-Session-Id}', \
+ }, \
+ 'update': { \
+ '$set': { \
+ 'update_date': { '$date': { '$numberLong': '%{expr: (%l * 1000) + (%M / 1000)}' } }, \
+ 'ip': '%{Framed-IP-Address}', \
+ 'start_time': '%{Packet-Original-Timestamp}', \
+ }, \
+ '$push': { \
+ 'events_data': { \
+ 'event_id': '%{sha256:%{tolower:%{Calling-Station-Id}', \
+ 'event_type': 'Accounting-Start', \
+ 'event_time': '%{Packet-Original-Timestamp}', \
+ 'creation_date': { '$date': { '$numberLong': '%{expr: (%l * 1000) + (%M / 1000)}' } } \
+ } \
+ }, \
+ '$setOnInsert': { \
+ 'pool_name': '%{Control:Pool-Name}', \
+ 'ip': '%{Framed-IP-Address}', \
+ 'closed': false, \
+ 'update_counter': 0, \
+ 'creation_date': { '$date': { '$numberLong': '%{expr: (%l * 1000) + (%M / 1000)}' } } \
+ } \
+ }, \
+ 'upsert': true \
+ })"
+
+ query = "db.simultaneous_connections.findAndModify({ \
+ 'query': { \
+ 'pool_name': '%{Control:Pool-Name}' \
+ }, \
+ 'update': { \
+ '$inc': { \
+ 'conns_counter': 1 \
+ } \
+ '$setOnInsert': { \
+ 'pool_name': '%{Control:Pool-Name}', \
+ 'conns_counter': 1 \
+ }, \
+ }, \
+ 'upsert': true \
+ })"
+ # End Start
+ }
+
+ interim-update {
+ query = "db.connections.findAndModify({ \
+ 'query': { \
+ 'calling_station_id': '%{Calling-Station-Id}', \
+ 'pgw_node': '%{NAS-Identifier}', \
+ 'acct_session_id': '%{Acct-Session-Id}' \
+ }, \
+ 'update': { \
+ '$set': { \
+ 'update_date': { '$date': { '$numberLong': '%{expr: (%l * 1000) + (%M / 1000)}' } }, \
+ 'last_upd_interim': '%{Packet-Original-Timestamp}' \
+ }, \
+ '$inc': { \
+ 'update_counter': 1 \
+ }, \
+ '$push': { \
+ 'events_data': { \
+ 'event_id': '%{sha256:%{tolower:%{Calling-Station-Id}', \
+ 'event_type': 'Accounting-Interim-Update', \
+ 'event_time': '%{Packet-Original-Timestamp}', \
+ 'creation_date': { '$date': { '$numberLong': '%{expr: (%l * 1000) + (%M / 1000)}' } } \
+ } \
+ }, \
+ '$setOnInsert': { \
+ 'pool_name': '%{Control:Pool-Name}', \
+ 'ip': '%{Framed-IP-Address}', \
+ 'closed': false, \
+ 'creation_date': { '$date': { '$numberLong': '%{expr: (%l * 1000) + (%M / 1000)}' } } \
+ } \
+ },
+ 'upsert': true \
+ })"
+ # End Interim-Update
+ }
+
+ stop {
+ query = "db.connections.findAndModify({ \
+ 'query': { \
+ 'calling_station_id': '%{Calling-Station-Id}', \
+ 'pgw_node': '%{NAS-Identifier}', \
+ 'acct_session_id': '%{Acct-Session-Id}' \
+ }, \
+ 'update': { \
+ '$set': { \
+ 'update_date': { '$date': { '$numberLong': '%{expr: (%l * 1000) + (%M / 1000)}' } }, \
+ 'stop_time': '%{Packet-Original-Timestamp}', \
+ 'closed': true \
+ }, \
+ '$push': { \
+ 'events_data': { \
+ 'event_id': '%{sha256:%{tolower:%{Calling-Station-Id}', \
+ 'event_type': 'Accounting-Stop', \
+ 'event_time': '%{Packet-Original-Timestamp}', \
+ 'creation_date': { '$date': { '$numberLong': '%{expr: (%l * 1000) + (%M / 1000)}' } } \
+ } \
+ }, \
+ '$setOnInsert': { \
+ 'pool_name': '%{Control:Pool-Name}', \
+ 'ip': '%{Framed-IP-Address}', \
+ 'update_counter': 0, \
+ 'creation_date': { '$date': { '$numberLong': '%{expr: (%l * 1000) + (%M / 1000)}' } } \
+ } \
+ }, \
+ 'upsert': true \
+ })"
+
+ # End Stop
+ }
+
+ }
+}
+
+
+#######################################################################
+# Authentication Logging Queries
+#######################################################################
+# postauth_query - Insert some info after authentication
+#######################################################################
+
+post-auth {
+ query = "db.post_auth.findAndModify({ \
+ 'query': { \
+ 'calling_station_id': '%{Calling-Station-Id}', \
+ 'nas_ip': '%{NAS-Identifier}' \
+ }, \
+ 'update': { \
+ '$set': { \
+ 'update_date': { '$date': { '$numberLong': '%{expr: (%l * 1000) + (%M / 1000)}' } }, \
+ 'last_event_ts': '%{Packet-Original-Timestamp}' \
+ }, \
+ '$inc': { \
+ 'reject_counter': 1 \
+ }, \
+ '$setOnInsert': { \
+ 'calling_station_id': '%{Calling-Station-Id}', \
+ 'nas_ip': '%{NAS-Identifier}', \
+ 'creation_date': { '$date': { '$numberLong': '%{expr: (%l * 1000) + (%M / 1000)}' } } \
+ } \
+ }, \
+ 'upsert': true \
+ })"
+}
diff --git a/raddb/mods-config/sql/main/mssql/process-radacct.sql b/raddb/mods-config/sql/main/mssql/process-radacct.sql
new file mode 100644
index 0000000..01129b6
--- /dev/null
+++ b/raddb/mods-config/sql/main/mssql/process-radacct.sql
@@ -0,0 +1,161 @@
+# -*- text -*-
+#
+# main/mssql/process-radacct.sql -- Schema extensions for processing radacct entries
+#
+# $Id$
+
+-- ---------------------------------
+-- - Per-user data usage over time -
+-- ---------------------------------
+--
+-- An extension to the standard schema to hold per-user data usage statistics
+-- for arbitrary periods.
+--
+-- The data_usage_by_period table is populated by periodically calling the
+-- fr_new_data_usage_period stored procedure.
+--
+-- This table can be queried in various ways to produce reports of aggregate
+-- data use over time. For example, if the fr_new_data_usage_period SP is
+-- invoked one per day just after midnight, to produce usage data with daily
+-- granularity, then a reasonably accurate monthly bandwidth summary for a
+-- given user could be obtained with:
+--
+-- SELECT
+-- FORMAT(period_start, 'yyyy-MMMM') AS month,
+-- SUM(acctinputoctets)/1000/1000/1000 AS GB_in,
+-- SUM(acctoutputoctets)/1000/1000/1000 AS GB_out
+-- FROM
+-- data_usage_by_period
+-- WHERE
+-- username='bob' AND
+-- period_end <> 0
+-- GROUP BY
+-- FORMAT(period_start, 'yyyy-MMMM');
+--
+-- +----------------+----------+-----------+
+-- | month | GB_in | GB_out |
+-- +----------------+----------+-----------+
+-- | 2019-July | 5.782279 | 50.545664 |
+-- | 2019-August | 4.230543 | 48.523096 |
+-- | 2019-September | 4.847360 | 48.631835 |
+-- | 2019-October | 6.456763 | 51.686231 |
+-- | 2019-November | 6.362537 | 52.385710 |
+-- | 2019-December | 4.301524 | 50.762240 |
+-- | 2020-January | 5.436280 | 49.067775 |
+-- +----------------+----------+-----------+
+--
+CREATE TABLE data_usage_by_period (
+ username VARCHAR(64) NOT NULL,
+ period_start DATETIME NOT NULL,
+ period_end DATETIME NOT NULL,
+ acctinputoctets NUMERIC(19),
+ acctoutputoctets NUMERIC(19),
+ PRIMARY KEY (username, period_start)
+);
+GO
+
+CREATE INDEX idx_data_usage_by_period_period_end ON data_usage_by_period(period_end);
+GO
+
+--
+-- Stored procedure that when run with some arbitrary frequency, say
+-- once per day by cron, will process the recent radacct entries to extract
+-- time-windowed data containing acct{input,output}octets ("data usage") per
+-- username, per period.
+--
+-- Each invocation will create new rows in the data_usage_by_period tables
+-- containing the data used by each user since the procedure was last invoked.
+-- The intervals do not need to be identical but care should be taken to
+-- ensure that the start/end of each period aligns well with any intended
+-- reporting intervals.
+--
+-- It can be invoked by running:
+--
+-- EXEC fr_new_data_usage_period;
+--
+--
+CREATE OR ALTER PROCEDURE fr_new_data_usage_period
+AS
+BEGIN
+
+ DECLARE @v_start DATETIME;
+ DECLARE @v_end DATETIME;
+
+ SELECT @v_start = COALESCE(DATEADD(ss, 1, MAX(period_end)), CAST('1970-01-01' AS DATETIME)) FROM data_usage_by_period;
+ SELECT @v_end = CAST(CURRENT_TIMESTAMP AS DATETIME2(0));
+
+ BEGIN TRAN;
+
+ --
+ -- Add the data usage for the sessions that were active in the current
+ -- period to the table. Include all sessions that finished since the start
+ -- of this period as well as those still ongoing.
+ --
+ MERGE INTO data_usage_by_period d
+ USING (
+ SELECT
+ username,
+ @v_start AS period_start,
+ @v_end AS period_end,
+ SUM(acctinputoctets) AS acctinputoctets,
+ SUM(acctoutputoctets) AS acctoutputoctets
+ FROM ((
+ SELECT
+ username, acctinputoctets, acctoutputoctets
+ FROM
+ radacct
+ WHERE
+ acctstoptime > @v_start
+ ) UNION ALL (
+ SELECT
+ username, acctinputoctets, acctoutputoctets
+ FROM
+ radacct
+ WHERE
+ acctstoptime=0
+ )) a
+ GROUP BY
+ username
+ ) s
+ ON ( d.username = s.username AND d.period_start = s.period_start )
+ WHEN MATCHED THEN
+ UPDATE SET
+ acctinputoctets = d.acctinputoctets + s.acctinputoctets,
+ acctoutputoctets = d.acctoutputoctets + s.acctoutputoctets,
+ period_end = @v_end
+ WHEN NOT MATCHED THEN
+ INSERT
+ (username, period_start, period_end, acctinputoctets, acctoutputoctets)
+ VALUES
+ (s.username, s.period_start, s.period_end, s.acctinputoctets, s.acctoutputoctets);
+
+ --
+ -- Create an open-ended "next period" for all ongoing sessions and carry a
+ -- negative value of their data usage to avoid double-accounting when we
+ -- process the next period. Their current data usage has already been
+ -- allocated to the current and possibly previous periods.
+ --
+ -- MSSQL doesn't allow a DATETIME to be NULL so we use "0" (1900-01-01) to
+ -- indicate the open-ended interval.
+ --
+ INSERT INTO data_usage_by_period (username, period_start, period_end, acctinputoctets, acctoutputoctets)
+ SELECT *
+ FROM (
+ SELECT
+ username,
+ DATEADD(ss,1,@v_end) AS period_start,
+ 0 AS period_end,
+ 0 - SUM(acctinputoctets) AS acctinputoctets,
+ 0 - SUM(acctoutputoctets) AS acctoutputoctets
+ FROM
+ radacct
+ WHERE
+ acctstoptime=0
+ GROUP BY
+ username
+ ) s;
+
+ COMMIT;
+
+END
+GO
diff --git a/raddb/mods-config/sql/main/mssql/queries.conf b/raddb/mods-config/sql/main/mssql/queries.conf
new file mode 100644
index 0000000..1978463
--- /dev/null
+++ b/raddb/mods-config/sql/main/mssql/queries.conf
@@ -0,0 +1,617 @@
+# -*- text -*-
+#
+# main/mssql/queries.conf -- MSSQL configuration for default schema (schema.sql)
+#
+# $Id$
+
+# Safe characters list for sql queries. Everything else is replaced
+# with their mime-encoded equivalents.
+# The default list should be ok
+#safe_characters = "@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_: /"
+
+#######################################################################
+# Query config: Username
+#######################################################################
+# This is the username that will get substituted, escaped, and added
+# as attribute 'SQL-User-Name'. '%{SQL-User-Name}' should be used
+# below everywhere a username substitution is needed so you you can
+# be sure the username passed from the client is escaped properly.
+#
+# Uncomment the next line, if you want the sql_user_name to mean:
+#
+# Use Stripped-User-Name, if it's there.
+# Else use User-Name, if it's there,
+# Else use hard-coded string "none" as the user name.
+#sql_user_name = "%{%{Stripped-User-Name}:-%{%{User-Name}:-none}}"
+#
+sql_user_name = "%{User-Name}"
+
+#######################################################################
+# Query config: Event-Timestamp
+#######################################################################
+# event_timestamp_epoch is the basis for the time inserted into
+# accounting records. Typically this will be the Event-Timestamp of the
+# accounting request, which is usually provided by a NAS.
+#
+# Uncomment the next line, if you want the timestamp to be based on the
+# request reception time recorded by this server, for example if you
+# distrust the provided Event-Timestamp.
+#event_timestamp_epoch = "%l"
+
+event_timestamp_epoch = "%{%{integer:Event-Timestamp}:-%l}"
+
+# event_timestamp is the SQL snippet for converting an epoch timestamp
+# to an SQL date.
+
+event_timestamp = "DATEADD(SS, ${event_timestamp_epoch}, '19700101')"
+
+#######################################################################
+# Query config: Class attribute
+#######################################################################
+#
+# 3.0.22 and later have a "class" column in the accounting table.
+#
+# However, we do NOT want to break existing configurations by adding
+# the Class attribute to the default queries. If we did that, then
+# systems using newer versions of the server would fail, because
+# there is no "class" column in their accounting tables.
+#
+# The solution to that is the following "class" subsection. If your
+# database has a "class" column for the various tables, then you can
+# uncomment the configuration items here. The queries below will
+# then automatically insert the Class attribute into radacct,
+# radpostauth, etc.
+#
+class {
+ #
+ # Delete the '#' character from each of the configuration
+ # items in this section. This change puts the Class
+ # attribute into the various tables. Leave the double-quoted
+ # string there, as the value for the configuration item.
+ #
+ # See also policy.d/accounting, and the "insert_acct_class"
+ # policy. You will need to list (or uncomment)
+ # "insert_acct_class" in the "post-auth" section in order to
+ # create a Class attribute.
+ #
+ column_name = # ", class"
+ packet_xlat = # ", '%{Class}'"
+ reply_xlat = # ", '%{reply:Class}'"
+}
+
+#######################################################################
+# Authorization Queries
+#######################################################################
+# These queries compare the check items for the user
+# in ${authcheck_table} and setup the reply items in
+# ${authreply_table}. You can use any query/tables
+# you want, but the return data for each row MUST
+# be in the following order:
+#
+# 0. Row ID (currently unused)
+# 1. UserName/GroupName
+# 2. Item Attr Name
+# 3. Item Attr Value
+# 4. Item Attr Operation
+#######################################################################
+# Query for case sensitive usernames was removed. Please contact with me,
+# if you know analog of STRCMP functions for MS SQL.
+
+authorize_check_query = "\
+ SELECT id, UserName, Attribute, Value, op \
+ FROM ${authcheck_table} \
+ WHERE Username = '%{SQL-User-Name}' \
+ ORDER BY id"
+
+authorize_reply_query = "\
+ SELECT id, UserName, Attribute, Value, op \
+ FROM ${authreply_table} \
+ WHERE Username = '%{SQL-User-Name}' \
+ ORDER BY id"
+
+authorize_group_check_query = "\
+ SELECT \
+ ${groupcheck_table}.id,${groupcheck_table}.GroupName, \
+ ${groupcheck_table}.Attribute,${groupcheck_table}.Value, \
+ ${groupcheck_table}.op \
+ FROM ${groupcheck_table},${usergroup_table} \
+ WHERE ${usergroup_table}.Username = '%{SQL-User-Name}' \
+ AND ${usergroup_table}.GroupName = ${groupcheck_table}.GroupName \
+ ORDER BY ${groupcheck_table}.id"
+
+authorize_group_reply_query = "\
+ SELECT \
+ ${groupreply_table}.id, ${groupreply_table}.GroupName, \
+ ${groupreply_table}.Attribute,${groupreply_table}.Value, \
+ ${groupreply_table}.op \
+ FROM ${groupreply_table},${usergroup_table} \
+ WHERE ${usergroup_table}.Username = '%{SQL-User-Name}' \
+ AND ${usergroup_table}.GroupName = ${groupreply_table}.GroupName \
+ ORDER BY ${groupreply_table}.id"
+
+group_membership_query = "\
+ SELECT groupname \
+ FROM ${usergroup_table} \
+ WHERE username = '%{SQL-User-Name}' \
+ ORDER BY priority"
+
+#######################################################################
+# Simultaneous Use Checking Queries
+#######################################################################
+# simul_count_query - query for the number of current connections
+# - If this is not defined, no simultaneous use checking
+# - will be performed by this module instance
+# simul_verify_query - query to return details of current connections
+# for verification
+# - Leave blank or commented out to disable verification step
+# - Note that the returned field order should not be changed.
+#######################################################################
+
+simul_count_query = "\
+ SELECT COUNT(*) \
+ FROM ${acct_table1} \
+ WHERE UserName = '%{SQL-User-Name}' \
+ AND AcctStopTime = 0"
+
+simul_verify_query = "\
+ SELECT \
+ RadAcctId, AcctSessionId, UserName, NASIPAddress, NASPortId, FramedIPAddress, \
+ CallingStationId, FramedProtocol \
+ FROM ${acct_table1} \
+ WHERE UserName = '%{SQL-User-Name}' \
+ AND AcctStopTime = 0"
+
+#######################################################################
+# Accounting and Post-Auth Queries
+#######################################################################
+# These queries insert/update accounting and authentication records.
+# The query to use is determined by the value of 'reference'.
+# This value is used as a configuration path and should resolve to one
+# or more 'query's. If reference points to multiple queries, and a query
+# fails, the next query is executed.
+#
+# Behaviour is identical to the old 1.x/2.x module, except we can now
+# fail between N queries, and query selection can be based on any
+# combination of attributes, or custom 'Acct-Status-Type' values.
+#######################################################################
+accounting {
+ reference = "%{tolower:type.%{%{Acct-Status-Type}:-%{Request-Processing-Stage}}.query}"
+
+ # Write SQL queries to a logfile. This is potentially useful for bulk inserts
+ # when used with the rlm_sql_null driver.
+# logfile = ${logdir}/accounting.sql
+
+ type {
+ accounting-on {
+ query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ AcctStopTime=${....event_timestamp}, \
+ AcctSessionTime=${....event_timestamp_epoch} - \
+ DATEDIFF(SS, '1970-01-01', AcctStartTime), \
+ AcctTerminateCause='%{%{Acct-Terminate-Cause}:-NAS-Reboot}', \
+ AcctStopDelay = %{%{Acct-Delay-Time}:-0} \
+ WHERE AcctStopTime = 0 \
+ AND NASIPAddress = '%{NAS-IP-Address}' \
+ AND AcctStartTime <= ${....event_timestamp}"
+ }
+
+ accounting-off {
+ query = "${..accounting-on.query}"
+ }
+
+ #
+ # Implement the "sql_session_start" policy.
+ # See raddb/policy.d/accounting for more details.
+ #
+ # You also need to fix the other queries as
+ # documented below. Look for "sql_session_start".
+ #
+ post-auth {
+ query = "\
+ INSERT INTO ${....acct_table1} \
+ INSERT INTO ${....acct_table1} ( \
+ AcctSessionId, \
+ AcctUniqueId, \
+ UserName, \
+ Realm, \
+ NASIPAddress, \
+ NASPortId, \
+ NASPortType, \
+ AcctStartTime, \
+ AcctSessionTime, \
+ AcctUpdateTime, \
+ AcctAuthentic, \
+ ConnectInfo_start, \
+ ConnectInfo_stop, \
+ AcctInputOctets, \
+ AcctOutputOctets, \
+ CalledStationId, \
+ CallingStationId, \
+ AcctTerminateCause, \
+ ServiceType, \
+ FramedProtocol, \
+ FramedIPAddress, \
+ FramedIPv6Address, \
+ FramedIPv6Prefix, \
+ FramedInterfaceId, \
+ DelegatedIPv6Prefix \
+ ${....class.column_name}) \
+ VALUES(\
+ '%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{%{NAS-IPv6-Address}:-%{NAS-IP-Address}}', \
+ '%{%{NAS-Port-ID}:-%{NAS-Port}}', \
+ '%{NAS-Port-Type}', \
+ ${....event_timestamp}, \
+ ${....event_timestamp}, \
+ 0, \
+ '', \
+ '%{Connect-Info}', \
+ '', \
+ 0, \
+ 0, \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '', \
+ '%{Service-Type}', \
+ '', \
+ '', \
+ '', \
+ '', \
+ '', \
+ '' \
+ ${....class.packet_xlat})"
+
+ query = "\
+ UPDATE ${....acct_table1} SET \
+ AcctStartTime = '%S', \
+ ConnectInfo_start = '%{Connect-Info}', \
+ AcctSessionId = '%{Acct-Session-Id}' \
+ WHERE UserName = '%{SQL-User-Name}' \
+ AND NASIPAddress = '%{%{NAS-IPv6-Address}:-%{NAS-IP-Address}}' \
+ AND NASPortId = '%{%{NAS-Port-ID}:-%{NAS-Port}}' \
+ AND NASPortType = '%{NAS-Port-Type}' \
+ AND AcctStopTime = 0"
+ }
+
+ start {
+ query = "\
+ INSERT INTO ${....acct_table1} ( \
+ AcctSessionId, \
+ AcctUniqueId, \
+ UserName, \
+ Realm, \
+ NASIPAddress, \
+ NASPortId, \
+ NASPortType, \
+ AcctStartTime, \
+ AcctUpdateTime, \
+ AcctSessionTime, \
+ AcctAuthentic, \
+ ConnectInfo_start, \
+ ConnectInfo_stop, \
+ AcctInputOctets, \
+ AcctOutputOctets, \
+ CalledStationId, \
+ CallingStationId, \
+ AcctTerminateCause, \
+ ServiceType, \
+ FramedProtocol, \
+ FramedIPAddress, \
+ FramedIPv6Address, \
+ FramedIPv6Prefix, \
+ FramedInterfaceId, \
+ DelegatedIPv6Prefix, \
+ AcctStartDelay, \
+ AcctStopDelay \
+ ${....class.column_name}) \
+ VALUES(\
+ '%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{NAS-IP-Address}', \
+ '%{%{NAS-Port-ID}:-%{NAS-Port}}', \
+ '%{NAS-Port-Type}', \
+ ${....event_timestamp}, \
+ ${....event_timestamp}, \
+ '0', \
+ '%{Acct-Authentic}', \
+ '%{Connect-Info}', \
+ '', \
+ '0', \
+ '0', \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ '%{Framed-IP-Address}', \
+ '%{Framed-IPv6-Address}', \
+ '%{Framed-IPv6-Prefix}', \
+ '%{Framed-Interface-Id}', \
+ '%{Delegated-IPv6-Prefix}', \
+ '%{Acct-Delay-Time}', \
+ '0' \
+ ${....class.packet_xlat})"
+
+ #
+ # When using "sql_session_start", you should comment out
+ # the previous query, and enable this one.
+ #
+ # Just change the previous query to "-query",
+ # and this one to "query". The previous one
+ # will be ignored, and this one will be
+ # enabled.
+ #
+ -query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ AcctSessionId = '%{Acct-Session-Id}', \
+ AcctUniqueId = '%{Acct-Unique-Session-Id}', \
+ AcctAuthentic = '%{Acct-Authentic}', \
+ ConnectInfo_start = '%{Connect-Info}', \
+ ServiceType = '%{Service-Type}', \
+ FramedProtocol = '%{Framed-Protocol}', \
+ FramedIpAddress = '%{Framed-IP-Address}', \
+ FramedIpv6Address = '%{Framed-IPv6-Address}', \
+ FramedIpv6Prefix = '%{Framed-IPv6-Prefix}', \
+ FramedInterfaceId = '%{Framed-Interface-Id}', \
+ DelegatedIpv6Prefix = '%{Delegated-IPv6-Prefix}', \
+ AcctStartTime = ${....event_timestamp}, \
+ AcctUpdateTime = ${....event_timestamp} \
+ WHERE UserName = '%{SQL-User-Name}' \
+ AND NASIPAddress = '%{%{NAS-IPv6-Address}:-%{NAS-IP-Address}}' \
+ AND NASPortId = '%{%{NAS-Port-ID}:-%{NAS-Port}}' \
+ AND NASPortType = '%{NAS-Port-Type}' \
+ AND AcctStopTime = 0"
+
+ query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ AcctStartTime = ${....event_timestamp}, \
+ AcctUpdateTime = ${....event_timestamp }, \
+ AcctStartDelay = '%{%{Acct-Delay-Time}:-0}', \
+ ConnectInfo_start = '%{Connect-Info}' \
+ WHERE AcctUniqueId = '%{Acct-Unique-Session-ID}' \
+ AND AcctStopTime = 0"
+ }
+
+ interim-update {
+ query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ AcctInterval = DATEDIFF(second, CASE WHEN AcctUpdateTime > 0 THEN AcctUpdateTime ELSE AcctStartTime END, ${....event_timestamp}), \
+ AcctUpdateTime = ${....event_timestamp}, \
+ AcctSessionTime = '%{Acct-Session-Time}', \
+ AcctInputOctets = convert(bigint, '%{%{Acct-Input-Gigawords}:-0}' * POWER(2.0, 32)) | '%{%{Acct-Input-Octets}:-0}', \
+ AcctOutputOctets = convert(bigint, '%{%{Acct-Output-Gigawords}:-0}' * POWER(2.0, 32)) | '%{%{Acct-Output-Octets}:-0}', \
+ FramedIPAddress = '%{Framed-IP-Address}', \
+ FramedIPv6Address = '%{Framed-IPv6-Address}', \
+ FramedIPv6Prefix = '%{Framed-IPv6-Prefix}', \
+ FramedInterfaceId = '%{Framed-Interface-Id}', \
+ DelegatedIPv6Prefix = '%{Delegated-IPv6-Prefix}' \
+ WHERE AcctUniqueId = '%{Acct-Unique-Session-ID}' \
+ AND AcctStopTime = 0"
+
+ query = "\
+ INSERT INTO ${....acct_table1} ( \
+ AcctSessionId, \
+ AcctUniqueId, \
+ UserName, \
+ Realm, \
+ NASIPAddress, \
+ NASPortId, \
+ NASPortType, \
+ AcctStartTime, \
+ AcctUpdateTime, \
+ AcctSessionTime, \
+ AcctAuthentic, \
+ ConnectInfo_start, \
+ AcctInputOctets, \
+ AcctOutputOctets, \
+ CalledStationId, \
+ CallingStationId, \
+ ServiceType, \
+ FramedProtocol, \
+ FramedIPAddress, \
+ FramedIPv6Address, \
+ FramedIPv6Prefix, \
+ FramedInterfaceId, \
+ DelegatedIPv6Prefix, \
+ AcctStartDelay \
+ ${....class.column_name}) \
+ VALUES(\
+ '%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{NAS-IP-Address}', \
+ '%{%{NAS-Port-ID}:-%{NAS-Port}}', \
+ '%{NAS-Port-Type}', \
+ ${....event_timestamp}, \
+ ${....event_timestamp}, \
+ '%{Acct-Session-Time}', \
+ '%{Acct-Authentic}', \
+ '', \
+ '%{Acct-Input-Octets}', \
+ '%{Acct-Output-Octets}', \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ '%{Framed-IP-Address}', \
+ '%{Framed-IPv6-Address}', \
+ '%{Framed-IPv6-Prefix}', \
+ '%{Framed-Interface-Id}', \
+ '%{Delegated-IPv6-Prefix}', \
+ '0' \
+ ${....class.packet_xlat})"
+
+ #
+ # When using "sql_session_start", you should comment out
+ # the previous query, and enable this one.
+ #
+ # Just change the previous query to "-query",
+ # and this one to "query". The previous one
+ # will be ignored, and this one will be
+ # enabled.
+ #
+ -query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ AcctSessionId = '%{Acct-Session-Id}', \
+ AcctUniqueId = '%{Acct-Unique-Session-Id}', \
+ AcctAuthentic = '%{Acct-Authentic}', \
+ ConnectInfo_start = '%{Connect-Info}', \
+ ServiceType = '%{Service-Type}', \
+ FramedProtocol = '%{Framed-Protocol}', \
+ FramedIPAddress = '%{Framed-IP-Address}', \
+ FramedIPv6Address = '%{Framed-IPv6-Address}', \
+ FramedIPv6Prefix = '%{Framed-IPv6-Prefix}', \
+ FramedInterfaceId = '%{Framed-Interface-Id}', \
+ DelegatedIPv6Prefix = '%{Delegated-IPv6-Prefix}', \
+ AcctInputOctets = convert(bigint, '%{%{Acct-Input-Gigawords}:-0}' * POWER(2.0, 32)) | '%{%{Acct-Input-Octets}:-0}', \
+ AcctOutputOctets = convert(bigint, '%{%{Acct-Output-Gigawords}:-0}' * POWER(2.0, 32)) | '%{%{Acct-Output-Octets}:-0}' \
+ WHERE UserName = '%{SQL-User-Name}' \
+ AND NASIPAddress = '%{%{NAS-IPv6-Address}:-%{NAS-IP-Address}}' \
+ AND NASPortId = '%{%{NAS-Port-ID}:-%{NAS-Port}}' \
+ AND NASPortType = '%{NAS-Port-Type}' \
+ AND AcctStopTime = 0"
+ }
+
+ stop {
+ query = "\
+ UPDATE ${....acct_table2} \
+ SET \
+ AcctStopTime = ${....event_timestamp}, \
+ AcctSessionTime = '%{Acct-Session-Time}', \
+ AcctInputOctets = convert(bigint, '%{%{Acct-Input-Gigawords}:-0}' * POWER(2.0, 32)) | '%{%{Acct-Input-Octets}:-0}', \
+ AcctOutputOctets = convert(bigint, '%{%{Acct-Output-Gigawords}:-0}' * POWER(2.0, 32)) | '%{%{Acct-Output-Octets}:-0}', \
+ AcctTerminateCause = '%{Acct-Terminate-Cause}', \
+ AcctStopDelay = '%{%{Acct-Delay-Time}:-0}', \
+ ConnectInfo_stop = '%{Connect-Info}' \
+ WHERE AcctUniqueId = '%{Acct-Unique-Session-ID}' \
+ AND AcctStopTime = 0"
+
+ query = "\
+ INSERT into ${....acct_table2} (\
+ AcctSessionId, \
+ AcctUniqueId, \
+ UserName, \
+ Realm, \
+ NASIPAddress, \
+ NASPortID, \
+ NASPortType, \
+ AcctStopTime, \
+ AcctSessionTime, \
+ AcctAuthentic, \
+ ConnectInfo_start, \
+ ConnectInfo_stop, \
+ AcctInputOctets, \
+ AcctOutputOctets, \
+ CalledStationId, \
+ CallingStationId, \
+ AcctTerminateCause, \
+ ServiceType, \
+ FramedProtocol, \
+ FramedIPAddress, \
+ FramedIPv6Address, \
+ FramedIPv6Prefix, \
+ FramedInterfaceId, \
+ DelegatedIPv6Prefix, \
+ AcctStartDelay, \
+ AcctStopDelay \
+ ${....class.column_name}) \
+ VALUES(\
+ '%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{NAS-IP-Address}', \
+ '%{%{NAS-Port-ID}:-%{NAS-Port}}', \
+ '%{NAS-Port-Type}', \
+ ${....event_timestamp}, \
+ '%{Acct-Session-Time}', \
+ '%{Acct-Authentic}', \
+ '', \
+ '%{Connect-Info}', \
+ convert(bigint, '%{%{Acct-Input-Gigawords}:-0}' * POWER(2.0, 32)) | '%{%{Acct-Input-Octets}:-0}', \
+ convert(bigint, '%{%{Acct-Output-Gigawords}:-0}' * POWER(2.0, 32)) | '%{%{Acct-Output-Octets}:-0}', \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '%{Acct-Terminate-Cause}', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ '%{Framed-IP-Address}', \
+ '%{Framed-IPv6-Address}', \
+ '%{Framed-IPv6-Prefix}', \
+ '%{Framed-Interface-Id}', \
+ '%{Delegated-IPv6-Prefix}', \
+ '0', \
+ '%{%{Acct-Delay-Time}:-0}' \
+ ${....class.packet_xlat})"
+
+ #
+ # When using "sql_session_start", you should comment out
+ # the previous query, and enable this one.
+ #
+ # Just change the previous query to "-query",
+ # and this one to "query". The previous one
+ # will be ignored, and this one will be
+ # enabled.
+ #
+ -query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ AcctSessionId = '%{Acct-Session-Id}', \
+ AcctUniqueId = '%{Acct-Unique-Session-Id}', \
+ AcctAuthentic = '%{Acct-Authentic}', \
+ ConnectInfo_start = '%{Connect-Info}', \
+ ServiceType = '%{Service-Type}', \
+ FramedProtocol = '%{Framed-Protocol}', \
+ FramedIPAddress = '%{Framed-IP-Address}', \
+ FramedIPv6Address = '%{Framed-IPv6-Address}', \
+ FramedIPv6Prefix = '%{Framed-IPv6-Prefix}', \
+ FramedInterfaceId = '%{Framed-Interface-Id}', \
+ DelegatedIPv6Prefix = '%{Delegated-IPv6-Prefix}', \
+ AcctStopTime = '%S', \
+ AcctSessionTime = %{Acct-Session-Time}, \
+ AcctInputOctets = convert(bigint, '%{%{Acct-Input-Gigawords}:-0}' * POWER(2.0, 32)) | '%{%{Acct-Input-Octets}:-0}', \
+ AcctOutputOctets = convert(bigint, '%{%{Acct-Output-Gigawords}:-0}' * POWER(2.0, 32)) | '%{%{Acct-Output-Octets}:-0}', \
+ AcctTerminateCause = '%{Acct-Terminate-Cause}', \
+ ConnectInfo_stop = '%{Connect-Info}' \
+ WHERE UserName = '%{SQL-User-Name}' \
+ AND NASIPAddress = '%{%{NAS-IPv6-Address}:-%{NAS-IP-Address}}' \
+ AND NASPortId = '%{%{NAS-Port-ID}:-%{NAS-Port}}' \
+ AND NASPortType = '%{NAS-Port-Type}' \
+ AND AcctStopTime = 0"
+ }
+
+ #
+ # No Acct-Status-Type == ignore the packet
+ #
+ accounting {
+ query = "SELECT true"
+ }
+ }
+}
+
+post-auth {
+ # Write SQL queries to a logfile. This is potentially useful for bulk inserts
+ # when used with the rlm_sql_null driver.
+# logfile = ${logdir}/post-auth.sql
+
+ query = "\
+ INSERT INTO ${..postauth_table} \
+ (userName, pass, reply, authdate ${..class.column_name}) \
+ VALUES(\
+ '%{User-Name}', \
+ '%{%{User-Password}:-CHAP-PASSWORD}', \
+ '%{reply:Packet-Type}', \
+ '%S.%{expr:%M / 1000}' \
+ ${..class.reply_xlat})"
+}
diff --git a/raddb/mods-config/sql/main/mssql/schema.sql b/raddb/mods-config/sql/main/mssql/schema.sql
new file mode 100644
index 0000000..7f6d633
--- /dev/null
+++ b/raddb/mods-config/sql/main/mssql/schema.sql
@@ -0,0 +1,302 @@
+-- $Id$d$
+--
+-- schela.sql rlm_sql - FreeRADIUS SQL Module
+--
+-- Database schema for MSSQL rlm_sql module
+--
+-- To load:
+-- isql -S db_ip_addr -d db_name -U db_login -P db_passwd -i db_mssql.sql
+--
+-- Based on: db_mysql.sql (Mike Machado <mike@innercite.com>)
+--
+-- Dmitri Ageev <d_ageev@ortcc.ru>
+--
+
+
+--
+-- Table structure for table 'radacct'
+--
+
+CREATE TABLE [radacct] (
+ [RadAcctId] [numeric](21, 0) IDENTITY (1, 1) NOT NULL,
+ [AcctSessionId] [varchar] (64) NOT NULL,
+ [AcctUniqueId] [varchar] (32) NOT NULL,
+ [UserName] [varchar] (64) NOT NULL,
+ [GroupName] [varchar] (64) NOT NULL,
+ [Realm] [varchar] (64) NOT NULL,
+ [NASIPAddress] [varchar] (15) NOT NULL,
+ [NASPortId] [varchar] (32) NULL,
+ [NASPortType] [varchar] (32) NULL,
+ [AcctStartTime] [datetime] NOT NULL,
+ [AcctUpdateTime] [datetime] NOT NULL,
+ [AcctStopTime] [datetime] NOT NULL,
+ [AcctInterval] [bigint] NULL,
+ [AcctSessionTime] [bigint] NULL,
+ [AcctAuthentic] [varchar] (32) NULL,
+ [ConnectInfo_start] [varchar] (128) NULL,
+ [ConnectInfo_stop] [varchar] (128) NULL,
+ [AcctInputOctets] [bigint] NULL,
+ [AcctOutputOctets] [bigint] NULL,
+ [CalledStationId] [varchar] (50) NOT NULL,
+ [CallingStationId] [varchar] (50) NOT NULL,
+ [AcctTerminateCause] [varchar] (32) NOT NULL,
+ [ServiceType] [varchar] (32) NULL,
+ [FramedProtocol] [varchar] (32) NULL,
+ [FramedIPAddress] [varchar] (15) NOT NULL,
+ [FramedIPv6Address] [varchar] (45) NOT NULL,
+ [FramedIPv6Prefix] [varchar] (45) NOT NULL,
+ [FramedInterfaceId] [varchar] (44) NOT NULL,
+ [DelegatedIPv6Prefix] [varchar] (45) NOT NULL,
+ [AcctStartDelay] [int] NULL,
+ [AcctStopDelay] [int] NULL,
+ [Class] [varchar] (64) NULL
+) ON [PRIMARY]
+GO
+
+ALTER TABLE [radacct] WITH NOCHECK ADD
+ CONSTRAINT [DF_radacct_GroupName] DEFAULT ('') FOR [GroupName],
+ CONSTRAINT [DF_radacct_AcctSessionId] DEFAULT ('') FOR [AcctSessionId],
+ CONSTRAINT [DF_radacct_AcctUniqueId] DEFAULT ('') FOR [AcctUniqueId],
+ CONSTRAINT [DF_radacct_UserName] DEFAULT ('') FOR [UserName],
+ CONSTRAINT [DF_radacct_Realm] DEFAULT ('') FOR [Realm],
+ CONSTRAINT [DF_radacct_NASIPAddress] DEFAULT ('') FOR [NASIPAddress],
+ CONSTRAINT [DF_radacct_NASPortId] DEFAULT (null) FOR [NASPortId],
+ CONSTRAINT [DF_radacct_NASPortType] DEFAULT (null) FOR [NASPortType],
+ CONSTRAINT [DF_radacct_AcctStartTime] DEFAULT ('1900-01-01 00:00:00') FOR [AcctStartTime],
+ CONSTRAINT [DF_radacct_AcctUpdateTime] DEFAULT ('1900-01-01 00:00:00') FOR [AcctUpdateTime],
+ CONSTRAINT [DF_radacct_AcctStopTime] DEFAULT ('1900-01-01 00:00:00') FOR [AcctStopTime],
+ CONSTRAINT [DF_radacct_AcctSessionTime] DEFAULT (null) FOR [AcctSessionTime],
+ CONSTRAINT [DF_radacct_AcctAuthentic] DEFAULT (null) FOR [AcctAuthentic],
+ CONSTRAINT [DF_radacct_ConnectInfo_start] DEFAULT (null) FOR [ConnectInfo_start],
+ CONSTRAINT [DF_radacct_ConnectInfo_stop] DEFAULT (null) FOR [ConnectInfo_stop],
+ CONSTRAINT [DF_radacct_AcctInputOctets] DEFAULT (null) FOR [AcctInputOctets],
+ CONSTRAINT [DF_radacct_AcctOutputOctets] DEFAULT (null) FOR [AcctOutputOctets],
+ CONSTRAINT [DF_radacct_CalledStationId] DEFAULT ('') FOR [CalledStationId],
+ CONSTRAINT [DF_radacct_CallingStationId] DEFAULT ('') FOR [CallingStationId],
+ CONSTRAINT [DF_radacct_AcctTerminateCause] DEFAULT ('') FOR [AcctTerminateCause],
+ CONSTRAINT [DF_radacct_ServiceType] DEFAULT (null) FOR [ServiceType],
+ CONSTRAINT [DF_radacct_FramedProtocol] DEFAULT (null) FOR [FramedProtocol],
+ CONSTRAINT [DF_radacct_FramedIPAddress] DEFAULT ('') FOR [FramedIPAddress],
+ CONSTRAINT [DF_radacct_FramedIPv6Address] DEFAULT ('') FOR [FramedIPv6Address],
+ CONSTRAINT [DF_radacct_FramedIPv6Prefix] DEFAULT ('') FOR [FramedIPv6Prefix],
+ CONSTRAINT [DF_radacct_FramedInterfaceId] DEFAULT ('') FOR [FramedInterfaceId],
+ CONSTRAINT [DF_radacct_DelegatedIPv6Prefix] DEFAULT ('') FOR [DelegatedIPv6Prefix],
+ CONSTRAINT [DF_radacct_AcctStartDelay] DEFAULT (null) FOR [AcctStartDelay],
+ CONSTRAINT [DF_radacct_AcctStopDelay] DEFAULT (null) FOR [AcctStopDelay],
+ CONSTRAINT [DF_radacct_Class] DEFAULT (null) FOR [Class],
+ CONSTRAINT [PK_radacct] PRIMARY KEY NONCLUSTERED
+ (
+ [RadAcctId]
+ ) ON [PRIMARY]
+GO
+
+CREATE INDEX [UserName] ON [radacct]([UserName]) ON [PRIMARY]
+GO
+
+CREATE INDEX [FramedIPAddress] ON [radacct]([FramedIPAddress]) ON [PRIMARY]
+GO
+
+CREATE INDEX [FramedIPv6Address] ON [radacct]([FramedIPv6Address]) ON [PRIMARY]
+GO
+
+CREATE INDEX [FramedIPv6Prefix] ON [radacct]([FramedIPv6Prefix]) ON [PRIMARY]
+GO
+
+CREATE INDEX [FramedInterfaceId] ON [radacct]([FramedInterfaceId]) ON [PRIMARY]
+GO
+
+CREATE INDEX [DelegatedIPv6Prefix] ON [radacct]([DelegatedIPv6Prefix]) ON [PRIMARY]
+GO
+
+CREATE INDEX [AcctSessionId] ON [radacct]([AcctSessionId]) ON [PRIMARY]
+GO
+
+CREATE UNIQUE INDEX [AcctUniqueId] ON [radacct]([AcctUniqueId]) ON [PRIMARY]
+GO
+
+CREATE INDEX [AcctStartTime] ON [radacct]([AcctStartTime]) ON [PRIMARY]
+GO
+
+CREATE INDEX [AcctStopTime] ON [radacct]([AcctStopTime]) ON [PRIMARY]
+GO
+
+CREATE INDEX [NASIPAddress] ON [radacct]([NASIPAddress]) ON [PRIMARY]
+GO
+
+CREATE INDEX [Class] ON [radacct]([Class]) ON [PRIMARY]
+GO
+
+/* For use by onoff */
+CREATE INDEX [RadacctBulkClose] ON [radacct]([NASIPAddress],[AcctStartTime]) WHERE [AcctStopTime] IS NULL ON [PRIMARY]
+GO
+
+
+--
+-- Table structure for table 'radacct'
+--
+
+CREATE TABLE [radcheck] (
+ [id] [int] IDENTITY (1, 1) NOT NULL ,
+ [UserName] [varchar] (64) NOT NULL ,
+ [Attribute] [varchar] (32) NOT NULL ,
+ [Value] [varchar] (253) NOT NULL ,
+ [op] [char] (2) NULL
+) ON [PRIMARY]
+GO
+
+ALTER TABLE [radcheck] WITH NOCHECK ADD
+ CONSTRAINT [DF_radcheck_UserName] DEFAULT ('') FOR [UserName],
+ CONSTRAINT [DF_radcheck_Attribute] DEFAULT ('') FOR [Attribute],
+ CONSTRAINT [DF_radcheck_Value] DEFAULT ('') FOR [Value],
+ CONSTRAINT [DF_radcheck_op] DEFAULT (null) FOR [op],
+ CONSTRAINT [PK_radcheck] PRIMARY KEY NONCLUSTERED
+ (
+ [id]
+ ) ON [PRIMARY]
+GO
+
+CREATE INDEX [UserName] ON [radcheck]([UserName]) ON [PRIMARY]
+GO
+
+
+--
+-- Table structure for table 'radacct'
+--
+
+CREATE TABLE [radgroupcheck] (
+ [id] [int] IDENTITY (1, 1) NOT NULL ,
+ [GroupName] [varchar] (64) NOT NULL ,
+ [Attribute] [varchar] (32) NOT NULL ,
+ [Value] [varchar] (253) NOT NULL ,
+ [op] [char] (2) NULL
+) ON [PRIMARY]
+GO
+
+ALTER TABLE [radgroupcheck] WITH NOCHECK ADD
+ CONSTRAINT [DF_radgroupcheck_GroupName] DEFAULT ('') FOR [GroupName],
+ CONSTRAINT [DF_radgroupcheck_Attribute] DEFAULT ('') FOR [Attribute],
+ CONSTRAINT [DF_radgroupcheck_Value] DEFAULT ('') FOR [Value],
+ CONSTRAINT [DF_radgroupcheck_op] DEFAULT (null) FOR [op],
+ CONSTRAINT [PK_radgroupcheck] PRIMARY KEY NONCLUSTERED
+ (
+ [id]
+ ) ON [PRIMARY]
+GO
+
+CREATE INDEX [GroupName] ON [radgroupcheck]([GroupName]) ON [PRIMARY]
+GO
+
+
+--
+-- Table structure for table 'radacct'
+--
+
+CREATE TABLE [radgroupreply] (
+ [id] [int] IDENTITY (1, 1) NOT NULL ,
+ [GroupName] [varchar] (64) NOT NULL ,
+ [Attribute] [varchar] (32) NOT NULL ,
+ [Value] [varchar] (253) NOT NULL ,
+ [op] [char] (2) NULL ,
+ [prio] [int] NOT NULL
+) ON [PRIMARY]
+GO
+
+ALTER TABLE [radgroupreply] WITH NOCHECK ADD
+ CONSTRAINT [DF_radgroupreply_GroupName] DEFAULT ('') FOR [GroupName],
+ CONSTRAINT [DF_radgroupreply_Attribute] DEFAULT ('') FOR [Attribute],
+ CONSTRAINT [DF_radgroupreply_Value] DEFAULT ('') FOR [Value],
+ CONSTRAINT [DF_radgroupreply_op] DEFAULT (null) FOR [op],
+ CONSTRAINT [DF_radgroupreply_prio] DEFAULT (0) FOR [prio],
+ CONSTRAINT [PK_radgroupreply] PRIMARY KEY NONCLUSTERED
+ (
+ [id]
+ ) ON [PRIMARY]
+GO
+
+CREATE INDEX [GroupName] ON [radgroupreply]([GroupName]) ON [PRIMARY]
+GO
+
+
+--
+-- Table structure for table 'radacct'
+--
+
+CREATE TABLE [radreply] (
+ [id] [int] IDENTITY (1, 1) NOT NULL ,
+ [UserName] [varchar] (64) NOT NULL ,
+ [Attribute] [varchar] (32) NOT NULL ,
+ [Value] [varchar] (253) NOT NULL ,
+ [op] [char] (2) NULL
+) ON [PRIMARY]
+GO
+
+ALTER TABLE [radreply] WITH NOCHECK ADD
+ CONSTRAINT [DF_radreply_UserName] DEFAULT ('') FOR [UserName],
+ CONSTRAINT [DF_radreply_Attribute] DEFAULT ('') FOR [Attribute],
+ CONSTRAINT [DF_radreply_Value] DEFAULT ('') FOR [Value],
+ CONSTRAINT [DF_radreply_op] DEFAULT (null) FOR [op],
+ CONSTRAINT [PK_radreply] PRIMARY KEY NONCLUSTERED
+ (
+ [id]
+ ) ON [PRIMARY]
+GO
+
+CREATE INDEX [UserName] ON [radreply]([UserName]) ON [PRIMARY]
+GO
+
+
+--
+-- Table structure for table 'radacct'
+--
+
+CREATE TABLE [radusergroup] (
+ [id] [int] IDENTITY (1, 1) NOT NULL ,
+ [UserName] [varchar] (64) NOT NULL ,
+ [GroupName] [varchar] (64) NULL ,
+ [Priority] [int] NULL
+) ON [PRIMARY]
+GO
+
+ALTER TABLE [radusergroup] WITH NOCHECK ADD
+ CONSTRAINT [DF_radusergroup_UserName] DEFAULT ('') FOR [UserName],
+ CONSTRAINT [DF_radusergroup_GroupName] DEFAULT ('') FOR [GroupName],
+ CONSTRAINT [PK_radusergroup] PRIMARY KEY NONCLUSTERED
+ (
+ [id]
+ ) ON [PRIMARY]
+GO
+
+CREATE INDEX [UserName] ON [radusergroup]([UserName]) ON [PRIMARY]
+GO
+
+
+--
+-- Table structure for table 'radacct'
+--
+
+CREATE TABLE [radpostauth] (
+ [id] [int] IDENTITY (1, 1) NOT NULL ,
+ [userName] [varchar] (64) NOT NULL ,
+ [pass] [varchar] (64) NOT NULL ,
+ [reply] [varchar] (32) NOT NULL ,
+ [authdate] [datetime] NOT NULL,
+ [Class] [varchar] (64) NULL
+)
+GO
+
+CREATE INDEX [userName] ON [radpostauth]([userName]) ON [PRIMARY]
+GO
+
+CREATE INDEX [Class] ON [radpostauth]([Class]) ON [PRIMARY]
+GO
+
+ALTER TABLE [radpostauth] WITH NOCHECK ADD
+ CONSTRAINT [DF_radpostauth_userName] DEFAULT ('') FOR [userName],
+ CONSTRAINT [DF_radpostauth_pass] DEFAULT ('') FOR [pass],
+ CONSTRAINT [DF_radpostauth_reply] DEFAULT ('') FOR [reply],
+ CONSTRAINT [DF_radpostauth_authdate] DEFAULT (getdate()) FOR [authdate],
+ CONSTRAINT [PK_radpostauth] PRIMARY KEY NONCLUSTERED
+ (
+ [id]
+ ) ON [PRIMARY]
+GO
diff --git a/raddb/mods-config/sql/main/mysql/extras/wimax/queries.conf b/raddb/mods-config/sql/main/mysql/extras/wimax/queries.conf
new file mode 100644
index 0000000..2694230
--- /dev/null
+++ b/raddb/mods-config/sql/main/mysql/extras/wimax/queries.conf
@@ -0,0 +1,40 @@
+# -*- text -*-
+##
+## wimax.conf -- MySQL configuration for WiMAX keying
+##
+## $Id$
+
+# Safe characters list for sql queries. Everything else is replaced
+# with their mime-encoded equivalents.
+# The default list should be ok
+#safe_characters = "@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_: /"
+
+#######################################################################
+# Query config: Username
+#######################################################################
+# This is the username that will get substituted, escaped, and added
+# as attribute 'SQL-User-Name'. '%{SQL-User-Name}' should be used below
+# everywhere a username substitution is needed so you you can be sure
+# the username passed from the client is escaped properly.
+#
+# Uncomment the next line, if you want the sql_user_name to mean:
+#
+# Use Stripped-User-Name, if it's there.
+# Else use User-Name, if it's there,
+# Else use hard-coded string "DEFAULT" as the user name.
+#sql_user_name = "%{%{Stripped-User-Name}:-%{%{User-Name}:-DEFAULT}}"
+#
+sql_user_name = "%{User-Name}"
+
+#######################################################################
+# Logging of WiMAX SPI -> key mappings
+#######################################################################
+# postauth_query - Insert some info after authentication
+#######################################################################
+
+postauth_query = "INSERT INTO wimax \
+ (username, authdate, spi, mipkey, lifetime) \
+ VALUES ( \
+ '%{User-Name}', '%S' \
+ '%{%{reply:WiMAX-MN-hHA-MIP4-SPI}:-%{reply:WiMAX-MN-hHA-MIP6-SPI}}', \
+ '%{%{reply:WiMAX-MN-hHA-MIP4-Key}:-%{reply:WiMAX-MN-hHA-MIP6-Key}}', '%{%{reply:Session-Timeout}:-86400}' )"
diff --git a/raddb/mods-config/sql/main/mysql/extras/wimax/schema.sql b/raddb/mods-config/sql/main/mysql/extras/wimax/schema.sql
new file mode 100644
index 0000000..e32224a
--- /dev/null
+++ b/raddb/mods-config/sql/main/mysql/extras/wimax/schema.sql
@@ -0,0 +1,16 @@
+#
+# WiMAX Table structure for table 'wimax',
+# which replaces the "radpostauth" table.
+#
+
+CREATE TABLE wimax (
+ id int(11) NOT NULL auto_increment,
+ username varchar(64) NOT NULL default '',
+ authdate timestamp NOT NULL,
+ spi varchar(16) NOT NULL default '',
+ mipkey varchar(400) NOT NULL default '',
+ lifetime int(12) default NULL,
+ PRIMARY KEY (id),
+ KEY username (username),
+ KEY spi (spi)
+) ;
diff --git a/raddb/mods-config/sql/main/mysql/process-radacct.sql b/raddb/mods-config/sql/main/mysql/process-radacct.sql
new file mode 100644
index 0000000..8902338
--- /dev/null
+++ b/raddb/mods-config/sql/main/mysql/process-radacct.sql
@@ -0,0 +1,289 @@
+# -*- text -*-
+#
+# main/mysql/process-radacct.sql -- Schema extensions for processing radacct entries
+#
+# $Id$
+
+-- ---------------------------------
+-- - Per-user data usage over time -
+-- ---------------------------------
+--
+-- An extension to the standard schema to hold per-user data usage statistics
+-- for arbitrary periods.
+--
+-- The data_usage_by_period table is populated by periodically calling the
+-- fr_new_data_usage_period stored procedure.
+--
+-- This table can be queried in various ways to produce reports of aggregate
+-- data use over time. For example, if the fr_new_data_usage_period SP is
+-- invoked one per day just after midnight, to produce usage data with daily
+-- granularity, then a reasonably accurate monthly bandwidth summary for a
+-- given user could be obtained with:
+--
+-- SELECT
+-- DATE_FORMAT(period_start, '%Y-%M') AS month,
+-- SUM(acctinputoctets)/1000/1000/1000 AS GB_in,
+-- SUM(acctoutputoctets)/1000/1000/1000 AS GB_out
+-- FROM
+-- data_usage_by_period
+-- WHERE
+-- username='bob' AND
+-- period_end IS NOT NULL
+-- GROUP BY
+-- YEAR(period_start), MONTH(period_start);
+--
+-- +----------------+----------------+-----------------+
+-- | month | GB_in | GB_out |
+-- +----------------+----------------+-----------------+
+-- | 2019-July | 5.782279230000 | 50.545664820000 |
+-- | 2019-August | 4.230543340000 | 48.523096420000 |
+-- | 2019-September | 4.847360590000 | 48.631835480000 |
+-- | 2019-October | 6.456763250000 | 51.686231930000 |
+-- | 2019-November | 6.362537730000 | 52.385710570000 |
+-- | 2019-December | 4.301524440000 | 50.762240270000 |
+-- | 2020-January | 5.436280540000 | 49.067775280000 |
+-- +----------------+----------------+-----------------+
+-- 7 rows in set (0.000 sec)
+--
+CREATE TABLE data_usage_by_period (
+ username VARCHAR(64),
+ period_start DATETIME,
+ period_end DATETIME,
+ acctinputoctets BIGINT(20),
+ acctoutputoctets BIGINT(20),
+ PRIMARY KEY (username,period_start)
+);
+CREATE INDEX idx_data_usage_by_period_period_start ON data_usage_by_period (period_start);
+CREATE INDEX idx_data_usage_by_period_period_end ON data_usage_by_period (period_end);
+
+
+--
+-- Stored procedure that when run with some arbitrary frequency, say
+-- once per day by cron, will process the recent radacct entries to extract
+-- time-windowed data containing acct{input,output}octets ("data usage") per
+-- username, per period.
+--
+-- Each invocation will create new rows in the data_usage_by_period tables
+-- containing the data used by each user since the procedure was last invoked.
+-- The intervals do not need to be identical but care should be taken to
+-- ensure that the start/end of each period aligns well with any intended
+-- reporting intervals.
+--
+-- It can be invoked by running:
+--
+-- CALL fr_new_data_usage_period();
+--
+--
+DELIMITER $$
+
+DROP PROCEDURE IF EXISTS fr_new_data_usage_period;
+CREATE PROCEDURE fr_new_data_usage_period ()
+SQL SECURITY INVOKER
+BEGIN
+
+ DECLARE v_start DATETIME;
+ DECLARE v_end DATETIME;
+
+ DECLARE EXIT HANDLER FOR SQLEXCEPTION
+ BEGIN
+ ROLLBACK;
+ RESIGNAL;
+ END;
+
+ SELECT IFNULL(DATE_ADD(MAX(period_end), INTERVAL 1 SECOND), FROM_UNIXTIME(0)) INTO v_start FROM data_usage_by_period;
+ SELECT NOW() INTO v_end;
+
+ START TRANSACTION;
+
+ --
+ -- Add the data usage for the sessions that were active in the current
+ -- period to the table. Include all sessions that finished since the start
+ -- of this period as well as those still ongoing.
+ --
+ INSERT INTO data_usage_by_period (username, period_start, period_end, acctinputoctets, acctoutputoctets)
+ SELECT *
+ FROM (
+ SELECT
+ username,
+ v_start,
+ v_end,
+ SUM(acctinputoctets) AS acctinputoctets,
+ SUM(acctoutputoctets) AS acctoutputoctets
+ FROM ((
+ SELECT
+ username, acctinputoctets, acctoutputoctets
+ FROM
+ radacct
+ WHERE
+ acctstoptime > v_start
+ ) UNION ALL (
+ SELECT
+ username, acctinputoctets, acctoutputoctets
+ FROM
+ radacct
+ WHERE
+ acctstoptime IS NULL
+ )) AS a
+ GROUP BY
+ username
+ ) AS s
+ ON DUPLICATE KEY UPDATE
+ acctinputoctets = data_usage_by_period.acctinputoctets + s.acctinputoctets,
+ acctoutputoctets = data_usage_by_period.acctoutputoctets + s.acctoutputoctets,
+ period_end = v_end;
+
+ --
+ -- Create an open-ended "next period" for all ongoing sessions and carry a
+ -- negative value of their data usage to avoid double-accounting when we
+ -- process the next period. Their current data usage has already been
+ -- allocated to the current and possibly previous periods.
+ --
+ INSERT INTO data_usage_by_period (username, period_start, period_end, acctinputoctets, acctoutputoctets)
+ SELECT *
+ FROM (
+ SELECT
+ username,
+ DATE_ADD(v_end, INTERVAL 1 SECOND),
+ NULL,
+ 0 - SUM(acctinputoctets),
+ 0 - SUM(acctoutputoctets)
+ FROM
+ radacct
+ WHERE
+ acctstoptime IS NULL
+ GROUP BY
+ username
+ ) AS s;
+
+ COMMIT;
+
+END$$
+
+DELIMITER ;
+
+
+-- ------------------------------------------------------
+-- - "Lightweight" Accounting-On/Off strategy resources -
+-- ------------------------------------------------------
+--
+-- The following resources are for use only when the "lightweight"
+-- Accounting-On/Off strategy is enabled in queries.conf.
+--
+-- Instead of bulk closing the radacct sessions belonging to a reloaded NAS,
+-- this strategy leaves them open and records the NAS reload time in the
+-- nasreload table.
+--
+-- Where applicable, the onus is on the administator to:
+--
+-- * Consider the nas reload times when deriving a list of
+-- active/inactive sessions, and when determining the duration of sessions
+-- interrupted by a NAS reload. (Refer to the view below.)
+--
+-- * Close the affected sessions out of band. (Refer to the SP below.)
+--
+--
+-- The radacct_with_reloads view presents the radacct table with two additional
+-- columns: acctstoptime_with_reloads and acctsessiontime_with_reloads
+--
+-- Where the session isn't closed (acctstoptime IS NULL), yet it started before
+-- the last reload of the NAS (radacct.acctstarttime < nasreload.reloadtime),
+-- the derived columns are set based on the reload time of the NAS (effectively
+-- the point in time that the session was interrupted.)
+--
+CREATE VIEW radacct_with_reloads AS
+SELECT
+ a.*,
+ COALESCE(a.acctstoptime,
+ IF(a.acctstarttime < n.reloadtime, n.reloadtime, NULL)
+ ) AS acctstoptime_with_reloads,
+ COALESCE(a.acctsessiontime,
+ IF(a.acctstoptime IS NULL AND a.acctstarttime < n.reloadtime,
+ UNIX_TIMESTAMP(n.reloadtime) - UNIX_TIMESTAMP(a.acctstarttime), NULL)
+ ) AS acctsessiontime_with_reloads
+FROM radacct a
+LEFT OUTER JOIN nasreload n USING (nasipaddress);
+
+
+--
+-- It may be desirable to periodically "close" radacct sessions belonging to a
+-- reloaded NAS, replicating the "bulk close" Accounting-On/Off behaviour,
+-- just not in real time.
+--
+-- The fr_radacct_close_after_reload SP will set radacct.acctstoptime to
+-- nasreload.reloadtime, calculate the corresponding radacct.acctsessiontime,
+-- and set acctterminatecause to "NAS reboot" for interrupted sessions. It
+-- does so in batches, which avoids long-lived locks on the affected rows.
+--
+-- It can be invoked as follows:
+--
+-- CALL fr_radacct_close_after_reload();
+--
+-- Note: This SP walks radacct in strides of v_batch_size. It will typically
+-- skip closed and ongoing sessions at a rate significantly faster than
+-- 100,000 rows per second and process batched updates faster than 20,000
+-- orphaned sessions per second. If this isn't fast enough then you should
+-- really consider using a custom schema that includes partitioning by
+-- nasipaddress or acct{start,stop}time.
+--
+DELIMITER $$
+
+DROP PROCEDURE IF EXISTS fr_radacct_close_after_reload;
+CREATE PROCEDURE fr_radacct_close_after_reload ()
+SQL SECURITY INVOKER
+BEGIN
+
+ DECLARE v_a BIGINT(21);
+ DECLARE v_z BIGINT(21);
+ DECLARE v_updated BIGINT(21) DEFAULT 0;
+ DECLARE v_last_report DATETIME DEFAULT 0;
+ DECLARE v_last BOOLEAN DEFAULT FALSE;
+ DECLARE v_batch_size INT(12);
+
+ --
+ -- This works for many circumstances
+ --
+ SET v_batch_size = 2500;
+
+ SELECT MIN(radacctid) INTO v_a FROM radacct WHERE acctstoptime IS NULL;
+
+ update_loop: LOOP
+
+ SET v_z = NULL;
+ SELECT radacctid INTO v_z FROM radacct WHERE radacctid > v_a ORDER BY radacctid LIMIT v_batch_size,1;
+
+ IF v_z IS NULL THEN
+ SELECT MAX(radacctid) INTO v_z FROM radacct;
+ SET v_last = TRUE;
+ END IF;
+
+ UPDATE radacct a INNER JOIN nasreload n USING (nasipaddress)
+ SET
+ acctstoptime = n.reloadtime,
+ acctsessiontime = UNIX_TIMESTAMP(n.reloadtime) - UNIX_TIMESTAMP(acctstarttime),
+ acctterminatecause = 'NAS reboot'
+ WHERE
+ radacctid BETWEEN v_a AND v_z
+ AND acctstoptime IS NULL
+ AND acctstarttime < n.reloadtime;
+
+ SET v_updated = v_updated + ROW_COUNT();
+
+ SET v_a = v_z + 1;
+
+ --
+ -- Periodically report how far we've got
+ --
+ IF v_last_report != NOW() OR v_last THEN
+ SELECT v_z AS latest_radacctid, v_updated AS sessions_closed;
+ SET v_last_report = NOW();
+ END IF;
+
+ IF v_last THEN
+ LEAVE update_loop;
+ END IF;
+
+ END LOOP;
+
+END$$
+
+DELIMITER ;
diff --git a/raddb/mods-config/sql/main/mysql/queries.conf b/raddb/mods-config/sql/main/mysql/queries.conf
new file mode 100644
index 0000000..e7c9782
--- /dev/null
+++ b/raddb/mods-config/sql/main/mysql/queries.conf
@@ -0,0 +1,694 @@
+# -*- text -*-
+#
+# main/mysql/queries.conf-- MySQL configuration for default schema (schema.sql)
+#
+# $Id$
+
+# Use the driver specific SQL escape method.
+#
+# If you enable this configuration item, the "safe_characters"
+# configuration is ignored. FreeRADIUS then uses the MySQL escape
+# functions to escape input strings. The only downside to making this
+# change is that the MySQL escaping method is not the same the one
+# used by FreeRADIUS. So characters which are NOT in the
+# "safe_characters" list will now be stored differently in the database.
+#
+#auto_escape = yes
+
+# Safe characters list for sql queries. Everything else is replaced
+# with their mime-encoded equivalents.
+# The default list should be ok
+# Using 'auto_escape' is preferred
+safe_characters = "@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_: /"
+
+#######################################################################
+# Connection config
+#######################################################################
+# The character set is not configurable. The default character set of
+# the mysql client library is used. To control the character set,
+# create/edit my.cnf (typically in /etc/mysql/my.cnf or /etc/my.cnf)
+# and enter
+# [client]
+# default-character-set = utf8
+#
+
+#######################################################################
+# Query config: Username
+#######################################################################
+# This is the username that will get substituted, escaped, and added
+# as attribute 'SQL-User-Name'. '%{SQL-User-Name}' should be used below
+# everywhere a username substitution is needed so you you can be sure
+# the username passed from the client is escaped properly.
+#
+# Uncomment the next line, if you want the sql_user_name to mean:
+#
+# Use Stripped-User-Name, if it's there.
+# Else use User-Name, if it's there,
+# Else use hard-coded string "DEFAULT" as the user name.
+#sql_user_name = "%{%{Stripped-User-Name}:-%{%{User-Name}:-DEFAULT}}"
+#
+sql_user_name = "%{User-Name}"
+
+#######################################################################
+# Query config: Event-Timestamp
+#######################################################################
+# event_timestamp_epoch is the basis for the time inserted into
+# accounting records. Typically this will be the Event-Timestamp of the
+# accounting request, which is usually provided by a NAS.
+#
+# Uncomment the next line, if you want the timestamp to be based on the
+# request reception time recorded by this server, for example if you
+# distrust the provided Event-Timestamp.
+#event_timestamp_epoch = "%l"
+
+event_timestamp_epoch = "%{%{integer:Event-Timestamp}:-%l}"
+
+# event_timestamp is the SQL snippet for converting an epoch timestamp
+# to an SQL date.
+
+event_timestamp = "FROM_UNIXTIME(${event_timestamp_epoch})"
+
+#######################################################################
+# Query config: Class attribute
+#######################################################################
+#
+# 3.0.22 and later have a "class" column in the accounting table.
+#
+# However, we do NOT want to break existing configurations by adding
+# the Class attribute to the default queries. If we did that, then
+# systems using newer versions of the server would fail, because
+# there is no "class" column in their accounting tables.
+#
+# The solution to that is the following "class" subsection. If your
+# database has a "class" column for the various tables, then you can
+# uncomment the configuration items here. The queries below will
+# then automatically insert the Class attribute into radacct,
+# radpostauth, etc.
+#
+class {
+ #
+ # Delete the '#' character from each of the configuration
+ # items in this section. This change puts the Class
+ # attribute into the various tables. Leave the double-quoted
+ # string there, as the value for the configuration item.
+ #
+ # See also policy.d/accounting, and the "insert_acct_class"
+ # policy. You will need to list (or uncomment)
+ # "insert_acct_class" in the "post-auth" section in order to
+ # create a Class attribute.
+ #
+ column_name = # ", class"
+ packet_xlat = # ", '%{Class}'"
+ reply_xlat = # ", '%{reply:Class}'"
+}
+
+#######################################################################
+# Default profile
+#######################################################################
+# This is the default profile. It is found in SQL by group membership.
+# That means that this profile must be a member of at least one group
+# which will contain the corresponding check and reply items.
+# This profile will be queried in the authorize section for every user.
+# The point is to assign all users a default profile without having to
+# manually add each one to a group that will contain the profile.
+# The SQL module will also honor the User-Profile attribute. This
+# attribute can be set anywhere in the authorize section (ie the users
+# file). It is found exactly as the default profile is found.
+# If it is set then it will *overwrite* the default profile setting.
+# The idea is to select profiles based on checks on the incoming packets,
+# not on user group membership. For example:
+# -- users file --
+# DEFAULT Service-Type == Outbound-User, User-Profile := "outbound"
+# DEFAULT Service-Type == Framed-User, User-Profile := "framed"
+#
+# By default the default_user_profile is not set
+#
+#default_user_profile = "DEFAULT"
+
+#######################################################################
+# NAS Query
+#######################################################################
+# This query retrieves the radius clients
+#
+# 0. Row ID (currently unused)
+# 1. Name (or IP address)
+# 2. Shortname
+# 3. Type
+# 4. Secret
+# 5. Server
+#######################################################################
+
+client_query = "\
+ SELECT id, nasname, shortname, type, secret, server \
+ FROM ${client_table}"
+
+#######################################################################
+# Authorization Queries
+#######################################################################
+# These queries compare the check items for the user
+# in ${authcheck_table} and setup the reply items in
+# ${authreply_table}. You can use any query/tables
+# you want, but the return data for each row MUST
+# be in the following order:
+#
+# 0. Row ID (currently unused)
+# 1. UserName/GroupName
+# 2. Item Attr Name
+# 3. Item Attr Value
+# 4. Item Attr Operation
+#######################################################################
+# Use these for case sensitive usernames.
+
+#authorize_check_query = "\
+# SELECT id, username, attribute, value, op \
+# FROM ${authcheck_table} \
+# WHERE username = BINARY '%{SQL-User-Name}' \
+# ORDER BY id"
+
+#authorize_reply_query = "\
+# SELECT id, username, attribute, value, op \
+# FROM ${authreply_table} \
+# WHERE username = BINARY '%{SQL-User-Name}' \
+# ORDER BY id"
+
+#
+# The default queries are case insensitive. (for compatibility with
+# older versions of FreeRADIUS)
+#
+authorize_check_query = "\
+ SELECT id, username, attribute, value, op \
+ FROM ${authcheck_table} \
+ WHERE username = '%{SQL-User-Name}' \
+ ORDER BY id"
+
+authorize_reply_query = "\
+ SELECT id, username, attribute, value, op \
+ FROM ${authreply_table} \
+ WHERE username = '%{SQL-User-Name}' \
+ ORDER BY id"
+
+#
+# Use these for case sensitive usernames.
+#
+#group_membership_query = "\
+# SELECT groupname \
+# FROM ${usergroup_table} \
+# WHERE username = BINARY '%{SQL-User-Name}' \
+# ORDER BY priority"
+
+group_membership_query = "\
+ SELECT groupname \
+ FROM ${usergroup_table} \
+ WHERE username = '%{SQL-User-Name}' \
+ ORDER BY priority"
+
+authorize_group_check_query = "\
+ SELECT id, groupname, attribute, \
+ Value, op \
+ FROM ${groupcheck_table} \
+ WHERE groupname = '%{${group_attribute}}' \
+ ORDER BY id"
+
+authorize_group_reply_query = "\
+ SELECT id, groupname, attribute, \
+ value, op \
+ FROM ${groupreply_table} \
+ WHERE groupname = '%{${group_attribute}}' \
+ ORDER BY id"
+
+#######################################################################
+# Simultaneous Use Checking Queries
+#######################################################################
+# simul_count_query - query for the number of current connections
+# - If this is not defined, no simultaneous use checking
+# - will be performed by this module instance
+# simul_verify_query - query to return details of current connections
+# for verification
+# - Leave blank or commented out to disable verification step
+# - Note that the returned field order should not be changed.
+#
+# Note: Sessions that started prior to the most recent reload of their NAS will
+# be correctly considered inactive, even if the radacct entry itself is not
+# marked as stopped.
+#
+#######################################################################
+
+simul_count_query = "\
+ SELECT COUNT(*) \
+ FROM ${acct_table1} a \
+ LEFT OUTER JOIN nasreload n USING (nasipaddress) \
+ WHERE username = '%{SQL-User-Name}' \
+ AND acctstoptime IS NULL \
+ AND (a.acctstarttime > n.reloadtime OR n.reloadtime IS NULL)"
+
+simul_verify_query = "\
+ SELECT \
+ radacctid, acctsessionid, username, nasipaddress, nasportid, framedipaddress, \
+ callingstationid, framedprotocol \
+ FROM ${acct_table1} a \
+ LEFT OUTER JOIN nasreload n USING (nasipaddress) \
+ WHERE username = '%{SQL-User-Name}' \
+ AND acctstoptime IS NULL \
+ AND (a.acctstarttime > n.reloadtime OR n.reloadtime IS NULL)"
+
+#######################################################################
+# Accounting and Post-Auth Queries
+#######################################################################
+# These queries insert/update accounting and authentication records.
+# The query to use is determined by the value of 'reference'.
+# This value is used as a configuration path and should resolve to one
+# or more 'query's. If reference points to multiple queries, and a query
+# fails, the next query is executed.
+#
+# Behaviour is identical to the old 1.x/2.x module, except we can now
+# fail between N queries, and query selection can be based on any
+# combination of attributes, or custom 'Acct-Status-Type' values.
+#######################################################################
+accounting {
+ reference = "%{tolower:type.%{%{Acct-Status-Type}:-%{Request-Processing-Stage}}.query}"
+
+ # Write SQL queries to a logfile. This is potentially useful for bulk inserts
+ # when used with the rlm_sql_null driver.
+# logfile = ${logdir}/accounting.sql
+
+ column_list = "\
+ acctsessionid, acctuniqueid, username, \
+ realm, nasipaddress, nasportid, \
+ nasporttype, acctstarttime, acctupdatetime, \
+ acctstoptime, acctsessiontime, acctauthentic, \
+ connectinfo_start, connectinfo_stop, acctinputoctets, \
+ acctoutputoctets, calledstationid, callingstationid, \
+ acctterminatecause, servicetype, framedprotocol, \
+ framedipaddress, framedipv6address, framedipv6prefix, \
+ framedinterfaceid, delegatedipv6prefix ${..class.column_name}"
+
+ type {
+ accounting-on {
+
+ #
+ # "Bulk update" Accounting-On/Off strategy.
+ #
+ # Immediately terminate all sessions associated with a
+ # given NAS.
+ #
+ # Note: If a large number of sessions require closing
+ # then the bulk update may be take a long time to run
+ # and lock an excessive number of rows. See the
+ # strategy below for an alternative approach that does
+ # not touch the radacct session data.
+ #
+ query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ acctstoptime = ${....event_timestamp}, \
+ acctsessiontime = '${....event_timestamp_epoch}' \
+ - UNIX_TIMESTAMP(acctstarttime), \
+ acctterminatecause = '%{%{Acct-Terminate-Cause}:-NAS-Reboot}' \
+ WHERE acctstoptime IS NULL \
+ AND nasipaddress = '%{NAS-IP-Address}' \
+ AND acctstarttime <= ${....event_timestamp}"
+
+ #
+ # "Lightweight" Accounting-On/Off strategy.
+ #
+ # Record the reload time of the NAS and let the
+ # administrator actually close the sessions in radacct
+ # out-of-band, if desired.
+ #
+ # Implementation advice, together with a stored
+ # procedure for closing sessions and a view showing
+ # the effective stop time of each session is provided
+ # in process-radacct.sql.
+ #
+ # To enable this strategy, just change the previous
+ # query to "-query", and this one to "query". The
+ # previous one will be ignored, and this one will be
+ # enabled.
+ #
+ -query = "\
+ INSERT INTO nasreload \
+ SET \
+ nasipaddress = '%{NAS-IP-Address}', \
+ reloadtime = ${....event_timestamp} \
+ ON DUPLICATE KEY UPDATE reloadtime = ${....event_timestamp}"
+
+ }
+
+ accounting-off {
+ query = "${..accounting-on.query}"
+ }
+
+ #
+ # Implement the "sql_session_start" policy.
+ # See raddb/policy.d/accounting for more details.
+ #
+ # You also need to fix the other queries as
+ # documented below. Look for "sql_session_start".
+ #
+ post-auth {
+ query = "\
+ INSERT INTO ${....acct_table1} \
+ (${...column_list}) \
+ VALUES(\
+ '%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{%{NAS-IPv6-Address}:-%{NAS-IP-Address}}', \
+ NULLIF('%{%{NAS-Port-ID}:-%{NAS-Port}}', ''), \
+ '%{NAS-Port-Type}', \
+ ${....event_timestamp}, \
+ ${....event_timestamp}, \
+ NULL, \
+ 0, \
+ '', \
+ '%{Connect-Info}', \
+ NULL, \
+ 0, \
+ 0, \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '', \
+ '%{Service-Type}', \
+ NULL, \
+ '', \
+ '', \
+ '', \
+ '', \
+ '' \
+ ${....class.packet_xlat})"
+
+ query = "\
+ UPDATE ${....acct_table1} SET \
+ AcctStartTime = ${....event_timestamp}, \
+ AcctUpdateTime = ${....event_timestamp}, \
+ ConnectInfo_start = '%{Connect-Info}', \
+ AcctSessionId = '%{Acct-Session-Id}' \
+ WHERE UserName = '%{SQL-User-Name}' \
+ AND NASIPAddress = '%{%{NAS-IPv6-Address}:-%{NAS-IP-Address}}' \
+ AND NASPortId = '%{%{NAS-Port-ID}:-%{NAS-Port}}' \
+ AND NASPortType = '%{NAS-Port-Type}' \
+ AND AcctStopTime IS NULL"
+ }
+
+ start {
+ #
+ # Insert a new record into the sessions table
+ #
+ query = "\
+ INSERT INTO ${....acct_table1} \
+ (${...column_list}) \
+ VALUES \
+ ('%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{NAS-IP-Address}', \
+ '%{%{NAS-Port-ID}:-%{NAS-Port}}', \
+ '%{NAS-Port-Type}', \
+ ${....event_timestamp}, \
+ ${....event_timestamp}, \
+ NULL, \
+ '0', \
+ '%{Acct-Authentic}', \
+ '%{Connect-Info}', \
+ '', \
+ '0', \
+ '0', \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ '%{Framed-IP-Address}', \
+ '%{Framed-IPv6-Address}', \
+ '%{Framed-IPv6-Prefix}', \
+ '%{Framed-Interface-Id}', \
+ '%{Delegated-IPv6-Prefix}' \
+ ${....class.packet_xlat})"
+
+ #
+ # When using "sql_session_start", you should comment out
+ # the previous query, and enable this one.
+ #
+ # Just change the previous query to "-query",
+ # and this one to "query". The previous one
+ # will be ignored, and this one will be
+ # enabled.
+ #
+ -query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ AcctSessionId = '%{Acct-Session-Id}', \
+ AcctUniqueId = '%{Acct-Unique-Session-Id}', \
+ AcctAuthentic = '%{Acct-Authentic}', \
+ ConnectInfo_start = '%{Connect-Info}', \
+ ServiceType = '%{Service-Type}', \
+ FramedProtocol = '%{Framed-Protocol}', \
+ framedipaddress = '%{Framed-IP-Address}', \
+ framedipv6address = '%{Framed-IPv6-Address}', \
+ framedipv6prefix = '%{Framed-IPv6-Prefix}', \
+ framedinterfaceid = '%{Framed-Interface-Id}', \
+ delegatedipv6prefix = '%{Delegated-IPv6-Prefix}', \
+ AcctStartTime = ${....event_timestamp}, \
+ AcctUpdateTime = ${....event_timestamp} \
+ WHERE UserName = '%{SQL-User-Name}' \
+ AND NASIPAddress = '%{%{NAS-IPv6-Address}:-%{NAS-IP-Address}}' \
+ AND NASPortId = '%{%{NAS-Port-ID}:-%{NAS-Port}}' \
+ AND NASPortType = '%{NAS-Port-Type}' \
+ AND AcctStopTime IS NULL"
+
+ #
+ # Key constraints prevented us from inserting a new session,
+ # use the alternate query to update an existing session.
+ #
+ query = "\
+ UPDATE ${....acct_table1} SET \
+ acctstarttime = ${....event_timestamp}, \
+ acctupdatetime = ${....event_timestamp}, \
+ connectinfo_start = '%{Connect-Info}' \
+ WHERE AcctUniqueId = '%{Acct-Unique-Session-Id}'"
+
+ }
+
+ interim-update {
+ #
+ # Update an existing session and calculate the interval
+ # between the last data we received for the session and this
+ # update. This can be used to find stale sessions.
+ #
+ query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ acctupdatetime = (@acctupdatetime_old:=acctupdatetime), \
+ acctupdatetime = ${....event_timestamp}, \
+ acctinterval = ${....event_timestamp_epoch} - \
+ UNIX_TIMESTAMP(@acctupdatetime_old), \
+ framedipaddress = '%{Framed-IP-Address}', \
+ framedipv6address = '%{Framed-IPv6-Address}', \
+ framedipv6prefix = '%{Framed-IPv6-Prefix}', \
+ framedinterfaceid = '%{Framed-Interface-Id}', \
+ delegatedipv6prefix = '%{Delegated-IPv6-Prefix}', \
+ acctsessiontime = %{%{Acct-Session-Time}:-NULL}, \
+ acctinputoctets = '%{%{Acct-Input-Gigawords}:-0}' \
+ << 32 | '%{%{Acct-Input-Octets}:-0}', \
+ acctoutputoctets = '%{%{Acct-Output-Gigawords}:-0}' \
+ << 32 | '%{%{Acct-Output-Octets}:-0}' \
+ WHERE AcctUniqueId = '%{Acct-Unique-Session-Id}'"
+
+ #
+ # The update condition matched no existing sessions. Use
+ # the values provided in the update to create a new session.
+ #
+ query = "\
+ INSERT INTO ${....acct_table1} \
+ (${...column_list}) \
+ VALUES \
+ ('%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{NAS-IP-Address}', \
+ '%{%{NAS-Port-ID}:-%{NAS-Port}}', \
+ '%{NAS-Port-Type}', \
+ FROM_UNIXTIME(${....event_timestamp_epoch} - %{%{Acct-Session-Time}:-0}), \
+ ${....event_timestamp}, \
+ NULL, \
+ %{%{Acct-Session-Time}:-NULL}, \
+ '%{Acct-Authentic}', \
+ '%{Connect-Info}', \
+ '', \
+ '%{%{Acct-Input-Gigawords}:-0}' << 32 | '%{%{Acct-Input-Octets}:-0}', \
+ '%{%{Acct-Output-Gigawords}:-0}' << 32 | '%{%{Acct-Output-Octets}:-0}', \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ '%{Framed-IP-Address}', \
+ '%{Framed-IPv6-Address}', \
+ '%{Framed-IPv6-Prefix}', \
+ '%{Framed-Interface-Id}', \
+ '%{Delegated-IPv6-Prefix}' \
+ ${....class.packet_xlat})"
+
+ #
+ # When using "sql_session_start", you should comment out
+ # the previous query, and enable this one.
+ #
+ # Just change the previous query to "-query",
+ # and this one to "query". The previous one
+ # will be ignored, and this one will be
+ # enabled.
+ #
+ -query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ AcctSessionId = '%{Acct-Session-Id}', \
+ AcctUniqueId = '%{Acct-Unique-Session-Id}', \
+ AcctAuthentic = '%{Acct-Authentic}', \
+ ConnectInfo_start = '%{Connect-Info}', \
+ ServiceType = '%{Service-Type}', \
+ FramedProtocol = '%{Framed-Protocol}', \
+ framedipaddress = '%{Framed-IP-Address}', \
+ framedipv6address = '%{Framed-IPv6-Address}', \
+ framedipv6prefix = '%{Framed-IPv6-Prefix}', \
+ framedinterfaceid = '%{Framed-Interface-Id}', \
+ delegatedipv6prefix = '%{Delegated-IPv6-Prefix}', \
+ AcctUpdateTime = ${....event_timestamp}, \
+ AcctSessionTime = %{%{Acct-Session-Time}:-NULL}, \
+ AcctInputOctets = '%{%{Acct-Input-Gigawords}:-0}' \
+ << 32 | '%{%{Acct-Input-Octets}:-0}', \
+ AcctOutputOctets = '%{%{Acct-Output-Gigawords}:-0}' \
+ << 32 | '%{%{Acct-Output-Octets}:-0}' \
+ WHERE UserName = '%{SQL-User-Name}' \
+ AND NASIPAddress = '%{%{NAS-IPv6-Address}:-%{NAS-IP-Address}}' \
+ AND NASPortId = '%{%{NAS-Port-ID}:-%{NAS-Port}}' \
+ AND NASPortType = '%{NAS-Port-Type}' \
+ AND AcctStopTime IS NULL"
+
+ }
+
+ stop {
+ #
+ # Session has terminated, update the stop time and statistics.
+ #
+ query = "\
+ UPDATE ${....acct_table2} SET \
+ acctstoptime = ${....event_timestamp}, \
+ acctsessiontime = %{%{Acct-Session-Time}:-NULL}, \
+ acctinputoctets = '%{%{Acct-Input-Gigawords}:-0}' \
+ << 32 | '%{%{Acct-Input-Octets}:-0}', \
+ acctoutputoctets = '%{%{Acct-Output-Gigawords}:-0}' \
+ << 32 | '%{%{Acct-Output-Octets}:-0}', \
+ acctterminatecause = '%{Acct-Terminate-Cause}', \
+ connectinfo_stop = '%{Connect-Info}' \
+ WHERE AcctUniqueId = '%{Acct-Unique-Session-Id}'"
+
+ #
+ # The update condition matched no existing sessions. Use
+ # the values provided in the update to create a new session.
+ #
+ query = "\
+ INSERT INTO ${....acct_table2} \
+ (${...column_list}) \
+ VALUES \
+ ('%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{NAS-IP-Address}', \
+ '%{%{NAS-Port-ID}:-%{NAS-Port}}', \
+ '%{NAS-Port-Type}', \
+ FROM_UNIXTIME(${....event_timestamp_epoch} - %{%{Acct-Session-Time}:-0}), \
+ ${....event_timestamp}, \
+ ${....event_timestamp}, \
+ %{%{Acct-Session-Time}:-NULL}, \
+ '%{Acct-Authentic}', \
+ '', \
+ '%{Connect-Info}', \
+ '%{%{Acct-Input-Gigawords}:-0}' << 32 | '%{%{Acct-Input-Octets}:-0}', \
+ '%{%{Acct-Output-Gigawords}:-0}' << 32 | '%{%{Acct-Output-Octets}:-0}', \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '%{Acct-Terminate-Cause}', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ '%{Framed-IP-Address}', \
+ '%{Framed-IPv6-Address}', \
+ '%{Framed-IPv6-Prefix}', \
+ '%{Framed-Interface-Id}', \
+ '%{Delegated-IPv6-Prefix}' \
+ ${....class.packet_xlat})"
+
+ #
+ # When using "sql_session_start", you should comment out
+ # the previous query, and enable this one.
+ #
+ # Just change the previous query to "-query",
+ # and this one to "query". The previous one
+ # will be ignored, and this one will be
+ # enabled.
+ #
+ -query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ AcctSessionId = '%{Acct-Session-Id}', \
+ AcctUniqueId = '%{Acct-Unique-Session-Id}', \
+ AcctAuthentic = '%{Acct-Authentic}', \
+ ConnectInfo_start = '%{Connect-Info}', \
+ ServiceType = '%{Service-Type}', \
+ FramedProtocol = '%{Framed-Protocol}', \
+ framedipaddress = '%{Framed-IP-Address}', \
+ framedipv6address = '%{Framed-IPv6-Address}', \
+ framedipv6prefix = '%{Framed-IPv6-Prefix}', \
+ framedinterfaceid = '%{Framed-Interface-Id}', \
+ delegatedipv6prefix = '%{Delegated-IPv6-Prefix}', \
+ AcctStopTime = ${....event_timestamp}, \
+ AcctUpdateTime = ${....event_timestamp}, \
+ AcctSessionTime = %{Acct-Session-Time}, \
+ AcctInputOctets = '%{%{Acct-Input-Gigawords}:-0}' \
+ << 32 | '%{%{Acct-Input-Octets}:-0}', \
+ AcctOutputOctets = '%{%{Acct-Output-Gigawords}:-0}' \
+ << 32 | '%{%{Acct-Output-Octets}:-0}', \
+ AcctTerminateCause = '%{Acct-Terminate-Cause}', \
+ ConnectInfo_stop = '%{Connect-Info}' \
+ WHERE UserName = '%{SQL-User-Name}' \
+ AND NASIPAddress = '%{%{NAS-IPv6-Address}:-%{NAS-IP-Address}}' \
+ AND NASPortId = '%{%{NAS-Port-ID}:-%{NAS-Port}}' \
+ AND NASPortType = '%{NAS-Port-Type}' \
+ AND AcctStopTime IS NULL"
+
+ }
+
+ #
+ # No Acct-Status-Type == ignore the packet
+ #
+ accounting {
+ query = "SELECT true"
+ }
+ }
+}
+
+
+#######################################################################
+# Authentication Logging Queries
+#######################################################################
+# postauth_query - Insert some info after authentication
+#######################################################################
+
+post-auth {
+ # Write SQL queries to a logfile. This is potentially useful for bulk inserts
+ # when used with the rlm_sql_null driver.
+# logfile = ${logdir}/post-auth.sql
+
+ query = "\
+ INSERT INTO ${..postauth_table} \
+ (username, pass, reply, authdate ${..class.column_name}) \
+ VALUES ( \
+ '%{SQL-User-Name}', \
+ '%{%{User-Password}:-%{Chap-Password}}', \
+ '%{reply:Packet-Type}', \
+ '%S.%M' \
+ ${..class.reply_xlat})"
+}
diff --git a/raddb/mods-config/sql/main/mysql/schema.sql b/raddb/mods-config/sql/main/mysql/schema.sql
new file mode 100644
index 0000000..84846b2
--- /dev/null
+++ b/raddb/mods-config/sql/main/mysql/schema.sql
@@ -0,0 +1,179 @@
+###########################################################################
+# $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 IF NOT EXISTS 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 '',
+ realm varchar(64) default '',
+ nasipaddress varchar(15) NOT NULL default '',
+ nasportid varchar(32) 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(128) default NULL,
+ connectinfo_stop varchar(128) 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 '',
+ framedipv6address varchar(45) NOT NULL default '',
+ framedipv6prefix varchar(45) NOT NULL default '',
+ framedinterfaceid varchar(44) NOT NULL default '',
+ delegatedipv6prefix varchar(45) NOT NULL default '',
+ class varchar(64) default NULL,
+ PRIMARY KEY (radacctid),
+ UNIQUE KEY acctuniqueid (acctuniqueid),
+ KEY username (username),
+ KEY framedipaddress (framedipaddress),
+ KEY framedipv6address (framedipv6address),
+ KEY framedipv6prefix (framedipv6prefix),
+ KEY framedinterfaceid (framedinterfaceid),
+ KEY delegatedipv6prefix (delegatedipv6prefix),
+ KEY acctsessionid (acctsessionid),
+ KEY acctsessiontime (acctsessiontime),
+ KEY acctstarttime (acctstarttime),
+ KEY acctinterval (acctinterval),
+ KEY acctstoptime (acctstoptime),
+ KEY nasipaddress (nasipaddress),
+ KEY class (class)
+) ENGINE = INNODB;
+
+#
+# Table structure for table 'radcheck'
+#
+
+CREATE TABLE IF NOT EXISTS 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 IF NOT EXISTS 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 IF NOT EXISTS 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 IF NOT EXISTS 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 IF NOT EXISTS radusergroup (
+ id int(11) unsigned NOT NULL auto_increment,
+ username varchar(64) NOT NULL default '',
+ groupname varchar(64) NOT NULL default '',
+ priority int(11) NOT NULL default '1',
+ PRIMARY KEY (id),
+ KEY username (username(32))
+);
+
+#
+# Table structure for table 'radpostauth'
+#
+# Note: MySQL versions since 5.6.4 support fractional precision timestamps
+# which we use here. Replace the authdate definition with the following
+# if your software is too old:
+#
+# authdate timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
+#
+CREATE TABLE IF NOT EXISTS 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(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
+ class varchar(64) default NULL,
+ PRIMARY KEY (id),
+ KEY username (username),
+ KEY class (class)
+) ENGINE = INNODB;
+
+#
+# Table structure for table 'nas'
+#
+CREATE TABLE IF NOT EXISTS 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)
+) ENGINE = INNODB;
+
+#
+# Table structure for table 'nasreload'
+#
+CREATE TABLE IF NOT EXISTS nasreload (
+ nasipaddress varchar(15) NOT NULL,
+ reloadtime datetime NOT NULL,
+ PRIMARY KEY (nasipaddress)
+) ENGINE = INNODB;
diff --git a/raddb/mods-config/sql/main/mysql/setup.sql b/raddb/mods-config/sql/main/mysql/setup.sql
new file mode 100755
index 0000000..5ae98cc
--- /dev/null
+++ b/raddb/mods-config/sql/main/mysql/setup.sql
@@ -0,0 +1,40 @@
+# -*- text -*-
+##
+## setup.sql -- MySQL commands for creating the RADIUS user.
+##
+## WARNING: You should change 'localhost' and 'radpass'
+## to something else. Also update raddb/mods-available/sql
+## with the new RADIUS password.
+##
+## $Id$
+
+#
+# Create default administrator for RADIUS
+#
+CREATE USER 'radius'@'localhost' IDENTIFIED BY 'radpass';
+
+#
+# The server can read the authorisation data
+#
+GRANT SELECT ON radius.radcheck TO 'radius'@'localhost';
+GRANT SELECT ON radius.radreply TO 'radius'@'localhost';
+GRANT SELECT ON radius.radusergroup TO 'radius'@'localhost';
+GRANT SELECT ON radius.radgroupcheck TO 'radius'@'localhost';
+GRANT SELECT ON radius.radgroupreply TO 'radius'@'localhost';
+
+#
+# The server can write accounting and post-auth data
+#
+GRANT SELECT, INSERT, UPDATE ON radius.radacct TO 'radius'@'localhost';
+GRANT SELECT, INSERT, UPDATE ON radius.radpostauth TO 'radius'@'localhost';
+
+#
+# The server can read the NAS data
+#
+GRANT SELECT ON radius.nas TO 'radius'@'localhost';
+
+#
+# In the case of the "lightweight accounting-on/off" strategy, the server also
+# records NAS reload times
+#
+GRANT SELECT, INSERT, UPDATE ON radius.nasreload TO 'radius'@'localhost';
diff --git a/raddb/mods-config/sql/main/ndb/README b/raddb/mods-config/sql/main/ndb/README
new file mode 100644
index 0000000..71f5aa3
--- /dev/null
+++ b/raddb/mods-config/sql/main/ndb/README
@@ -0,0 +1,5 @@
+ The SQL schema and 'create admin user" scripts are here in order to
+simplify the process of using MySQL cluster.
+
+ The queries are NOT located here, because the database driver for
+MySQL cluster is just "mysql", and not "ndb".
diff --git a/raddb/mods-config/sql/main/ndb/schema.sql b/raddb/mods-config/sql/main/ndb/schema.sql
new file mode 100644
index 0000000..d115d06
--- /dev/null
+++ b/raddb/mods-config/sql/main/ndb/schema.sql
@@ -0,0 +1,144 @@
+###########################################################################
+# $Id$ #
+# #
+# schema.sql rlm_sql - FreeRADIUS SQL Module #
+# #
+# Database schema for MySQL Cluster. #
+# The only difference between this file and ../mysql/schema.sql #
+# is the definition of the storage engine. #
+# #
+# 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 '',
+ realm varchar(64) default '',
+ nasipaddress varchar(15) NOT NULL default '',
+ nasportid varchar(32) 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(128) default NULL,
+ connectinfo_stop varchar(128) 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 '',
+ framedipv6address varchar(45) NOT NULL default '',
+ framedipv6prefix varchar(45) NOT NULL default '',
+ framedinterfaceid varchar(44) NOT NULL default '',
+ delegatedipv6prefix varchar(45) NOT NULL default '',
+ class varchar(64) default NULL,
+ PRIMARY KEY (radacctid),
+ UNIQUE KEY acctuniqueid (acctuniqueid),
+ KEY username (username),
+ KEY framedipaddress (framedipaddress),
+ KEY framedipv6address (framedipv6address),
+ KEY framedipv6prefix (framedipv6prefix),
+ KEY framedinterfaceid (framedinterfaceid),
+ KEY delegatedipv6prefix (delegatedipv6prefix),
+ KEY acctsessionid (acctsessionid),
+ KEY acctsessiontime (acctsessiontime),
+ KEY acctstarttime (acctstarttime),
+ KEY acctinterval (acctinterval),
+ KEY acctstoptime (acctstoptime),
+ KEY nasipaddress (nasipaddress)
+) ENGINE=ndbcluster;
+
+#
+# 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))
+) ENGINE=ndbcluster;
+
+#
+# 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))
+) ENGINE=ndbcluster;
+
+#
+# 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))
+) ENGINE=ndbcluster;
+
+#
+# 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))
+) ENGINE=ndbcluster;
+
+
+#
+# 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))
+) ENGINE=ndbcluster;
+
+#
+# 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 DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
+ PRIMARY KEY (id)
+) ENGINE=ndbcluster;
diff --git a/raddb/mods-config/sql/main/ndb/setup.sql b/raddb/mods-config/sql/main/ndb/setup.sql
new file mode 100644
index 0000000..003fc10
--- /dev/null
+++ b/raddb/mods-config/sql/main/ndb/setup.sql
@@ -0,0 +1,25 @@
+# -*- text -*-
+##
+## admin.sql -- MySQL commands for creating the RADIUS user.
+##
+## WARNING: You should change 'localhost' and 'radpass'
+## to something else. Also update raddb/mods-available/sql
+## with the new RADIUS password.
+##
+## $Id$
+
+#
+# Create default administrator for RADIUS
+#
+CREATE USER 'radius'@'localhost';
+SET PASSWORD FOR 'radius'@'localhost' = PASSWORD('radpass');
+
+# The server can read any table in SQL
+GRANT ALL ON radius.* TO 'radius'@'localhost' identified by 'radpass';
+GRANT ALL ON radius.* TO 'radius'@'radsrvr' identified by 'radpass';
+
+# The server can write to the accounting and post-auth logging table.
+#
+# i.e.
+#GRANT ALL on radius.radacct TO 'radius'@'localhost' identified by 'radpass';
+#GRANT ALL on radius.radacct TO 'radius'@'radsrvr' identified by 'radpass';
diff --git a/raddb/mods-config/sql/main/oracle/process-radacct.sql b/raddb/mods-config/sql/main/oracle/process-radacct.sql
new file mode 100644
index 0000000..858d946
--- /dev/null
+++ b/raddb/mods-config/sql/main/oracle/process-radacct.sql
@@ -0,0 +1,147 @@
+# -*- text -*-
+#
+# main/oracle/process-radacct.sql -- Schema extensions for processing radacct entries
+#
+# $Id$
+
+-- ---------------------------------
+-- - Per-user data usage over time -
+-- ---------------------------------
+--
+-- An extension to the standard schema to hold per-user data usage statistics
+-- for arbitrary periods.
+--
+-- The data_usage_by_period table is populated by periodically calling the
+-- fr_new_data_usage_period stored procedure.
+--
+-- This table can be queried in various ways to produce reports of aggregate
+-- data use over time. For example, if the fr_new_data_usage_period SP is
+-- invoked one per day just after midnight, to produce usage data with daily
+-- granularity, then a reasonably accurate monthly bandwidth summary for a
+-- given user could be obtained with:
+--
+-- SELECT
+-- MIN(TO_CHAR(period_start, 'YYYY-Month')) AS month,
+-- SUM(acctinputoctets)/1000/1000/1000 AS GB_in,
+-- SUM(acctoutputoctets)/1000/1000/1000 AS GB_out
+-- FROM
+-- data_usage_by_period
+-- WHERE
+-- username='bob' AND
+-- period_end IS NOT NULL
+-- GROUP BY
+-- TRUNC(period_start,'month');
+--
+-- +----------------+----------------+-----------------+
+-- | MONTH | GB_IN | GB_OUT |
+-- +----------------+----------------+-----------------+
+-- | 2019-July | 5.782279230000 | 50.545664820000 |
+-- | 2019-August | 4.230543340000 | 48.523096420000 |
+-- | 2019-September | 4.847360590000 | 48.631835480000 |
+-- | 2019-October | 6.456763250000 | 51.686231930000 |
+-- | 2019-November | 6.362537730000 | 52.385710570000 |
+-- | 2019-December | 4.301524440000 | 50.762240270000 |
+-- | 2020-January | 5.436280540000 | 49.067775280000 |
+-- +----------------+----------------+-----------------+
+--
+CREATE TABLE data_usage_by_period (
+ id NUMBER GENERATED BY DEFAULT AS IDENTITY,
+ username VARCHAR(64) NOT NULL,
+ period_start TIMESTAMP WITH TIME ZONE NOT NULL,
+ period_end TIMESTAMP WITH TIME ZONE,
+ acctinputoctets NUMERIC(19),
+ acctoutputoctets NUMERIC(19),
+ PRIMARY KEY (id)
+);
+CREATE UNIQUE INDEX idx_data_usage_by_period_username_period_start ON data_usage_by_period (username,period_start);
+CREATE INDEX idx_data_usage_by_period_period_start ON data_usage_by_period (period_start);
+CREATE INDEX idx_data_usage_by_period_period_end ON data_usage_by_period (period_end);
+
+--
+-- Stored procedure that when run with some arbitrary frequency, say
+-- once per day by cron, will process the recent radacct entries to extract
+-- time-windowed data containing acct{input,output}octets ("data usage") per
+-- username, per period.
+--
+-- Each invocation will create new rows in the data_usage_by_period tables
+-- containing the data used by each user since the procedure was last invoked.
+-- The intervals do not need to be identical but care should be taken to
+-- ensure that the start/end of each period aligns well with any intended
+-- reporting intervals.
+--
+-- It can be invoked by running:
+--
+-- CALL fr_new_data_usage_period();
+--
+--
+CREATE OR REPLACE PROCEDURE fr_new_data_usage_period
+AS
+ v_start TIMESTAMP WITH TIME ZONE;
+ v_end TIMESTAMP WITH TIME ZONE;
+BEGIN
+
+ SELECT COALESCE(MAX(period_end) + NUMTODSINTERVAL(1,'SECOND'), TO_DATE('1970-01-01','YYYY-MM-DD')) INTO v_start FROM data_usage_by_period;
+ SELECT CAST(CURRENT_TIMESTAMP AS DATE) INTO v_end FROM dual;
+
+ BEGIN
+
+ --
+ -- Add the data usage for the sessions that were active in the current
+ -- period to the table. Include all sessions that finished since the start
+ -- of this period as well as those still ongoing.
+ --
+ MERGE INTO data_usage_by_period d
+ USING (
+ SELECT
+ username,
+ MIN(v_start) period_start,
+ MIN(v_end) period_end,
+ SUM(acctinputoctets) AS acctinputoctets,
+ SUM(acctoutputoctets) AS acctoutputoctets
+ FROM
+ radacct
+ WHERE
+ acctstoptime > v_start OR
+ acctstoptime IS NULL
+ GROUP BY
+ username
+ ) s
+ ON ( d.username = s.username AND d.period_start = s.period_start )
+ WHEN MATCHED THEN
+ UPDATE SET
+ acctinputoctets = d.acctinputoctets + s.acctinputoctets,
+ acctoutputoctets = d.acctoutputoctets + s.acctoutputoctets,
+ period_end = v_end
+ WHEN NOT MATCHED THEN
+ INSERT
+ (username, period_start, period_end, acctinputoctets, acctoutputoctets)
+ VALUES
+ (s.username, s.period_start, s.period_end, s.acctinputoctets, s.acctoutputoctets);
+
+ --
+ -- Create an open-ended "next period" for all ongoing sessions and carry a
+ -- negative value of their data usage to avoid double-accounting when we
+ -- process the next period. Their current data usage has already been
+ -- allocated to the current and possibly previous periods.
+ --
+ INSERT INTO data_usage_by_period (username, period_start, period_end, acctinputoctets, acctoutputoctets)
+ SELECT *
+ FROM (
+ SELECT
+ username,
+ v_end + NUMTODSINTERVAL(1,'SECOND'),
+ NULL,
+ 0 - SUM(acctinputoctets),
+ 0 - SUM(acctoutputoctets)
+ FROM
+ radacct
+ WHERE
+ acctstoptime IS NULL
+ GROUP BY
+ username
+ ) s;
+
+ END;
+
+END;
+/
diff --git a/raddb/mods-config/sql/main/oracle/queries.conf b/raddb/mods-config/sql/main/oracle/queries.conf
new file mode 100644
index 0000000..58c3ba8
--- /dev/null
+++ b/raddb/mods-config/sql/main/oracle/queries.conf
@@ -0,0 +1,694 @@
+# -*- text -*-
+#
+# main/oracle/queries.conf -- Oracle configuration for default schema (schema.sql)
+#
+# $Id$
+
+#######################################################################
+# Query config: Username
+#######################################################################
+# This is the username that will get substituted, escaped, and added
+# as attribute 'SQL-User-Name'. '%{SQL-User-Name}' should be used below
+# everywhere a username substitution is needed so you you can be sure
+# the username passed from the client is escaped properly.
+#
+# Uncomment the next line, if you want the sql_user_name to mean:
+#
+# Use Stripped-User-Name, if it's there.
+# Else use User-Name, if it's there,
+# Else use hard-coded string "DEFAULT" as the user name.
+#sql_user_name = "%{%{Stripped-User-Name}:-%{%{User-Name}:-DEFAULT}}"
+#
+sql_user_name = "%{User-Name}"
+
+#######################################################################
+# Query config: Event-Timestamp
+#######################################################################
+# event_timestamp_epoch is the basis for the time inserted into
+# accounting records. Typically this will be the Event-Timestamp of the
+# accounting request, which is provided by a NAS.
+#
+# Uncomment the next line, if you want the timestamp to be based on the
+# request reception time recorded by this server, for example if you
+# distrust the provided Event-Timestamp.
+#event_timestamp_epoch = "%l"
+
+event_timestamp_epoch = "%{%{integer:Event-Timestamp}:-%l}"
+
+# event_timestamp is the SQL snippet for converting an epoch timestamp
+# to an SQL date.
+
+event_timestamp = "TO_DATE('1970-01-01','YYYY-MM-DD') + NUMTODSINTERVAL(${event_timestamp_epoch},'SECOND')"
+
+#######################################################################
+# Query config: Class attribute
+#######################################################################
+#
+# 3.0.22 and later have a "class" column in the accounting table.
+#
+# However, we do NOT want to break existing configurations by adding
+# the Class attribute to the default queries. If we did that, then
+# systems using newer versions of the server would fail, because
+# there is no "class" column in their accounting tables.
+#
+# The solution to that is the following "class" subsection. If your
+# database has a "class" column for the various tables, then you can
+# uncomment the configuration items here. The queries below will
+# then automatically insert the Class attribute into radacct,
+# radpostauth, etc.
+#
+class {
+ #
+ # Delete the '#' character from each of the configuration
+ # items in this section. This change puts the Class
+ # attribute into the various tables. Leave the double-quoted
+ # string there, as the value for the configuration item.
+ #
+ # See also policy.d/accounting, and the "insert_acct_class"
+ # policy. You will need to list (or uncomment)
+ # "insert_acct_class" in the "post-auth" section in order to
+ # create a Class attribute.
+ #
+ column_name = # ", class"
+ packet_xlat = # ", '%{Class}'"
+ reply_xlat = # ", '%{reply:Class}'"
+}
+
+#######################################################################
+# Default profile
+#######################################################################
+# This is the default profile. It is found in SQL by group membership.
+# That means that this profile must be a member of at least one group
+# which will contain the corresponding check and reply items.
+# This profile will be queried in the authorize section for every user.
+# The point is to assign all users a default profile without having to
+# manually add each one to a group that will contain the profile.
+# The SQL module will also honor the User-Profile attribute. This
+# attribute can be set anywhere in the authorize section (ie the users
+# file). It is found exactly as the default profile is found.
+# If it is set then it will *overwrite* the default profile setting.
+# The idea is to select profiles based on checks on the incoming packets,
+# not on user group membership. For example:
+# -- users file --
+# DEFAULT Service-Type == Outbound-User, User-Profile := "outbound"
+# DEFAULT Service-Type == Framed-User, User-Profile := "framed"
+#
+# By default the default_user_profile is not set
+#
+#default_user_profile = "DEFAULT"
+#
+# Determines if we will query the default_user_profile or the User-Profile
+# if the user is not found. If the profile is found then we consider the user
+# found. By default this is set to 'no'.
+#
+#query_on_not_found = no
+
+
+#######################################################################
+# NAS Query
+#######################################################################
+# This query retrieves the radius clients
+#
+# 0. Row ID (currently unused)
+# 1. Name (or IP address)
+# 2. Shortname
+# 3. Type
+# 4. Secret
+# 5. Virtual server
+#######################################################################
+
+client_query = "\
+ SELECT id, nasname, shortname, type, secret, server \
+ FROM ${client_table}"
+
+#######################################################################
+# Authorization Queries
+#######################################################################
+# These queries compare the check items for the user
+# in ${authcheck_table} and setup the reply items in
+# ${authreply_table}. You can use any query/tables
+# you want, but the return data for each row MUST
+# be in the following order:
+#
+# 0. Row ID (currently unused)
+# 1. UserName/GroupName
+# 2. Item Attr Name
+# 3. Item Attr Value
+# 4. Item Attr Operation
+#######################################################################
+#
+# WARNING: Oracle is case sensitive
+#
+# The main difference between MySQL and Oracle queries is the date format.
+# You must use the TO_DATE function to transform the radius date format to
+# the Oracle date format, and put NULL otherwise '0' in a void date field.
+#
+#######################################################################
+
+authorize_check_query = "\
+ SELECT id, UserName, Attribute, Value, op \
+ FROM ${authcheck_table} \
+ WHERE Username = '%{SQL-User-Name}' \
+ ORDER BY id"
+
+authorize_reply_query = "\
+ SELECT id, UserName, Attribute, Value, op \
+ FROM ${authreply_table} \
+ WHERE Username = '%{SQL-User-Name}' \
+ ORDER BY id"
+
+authorize_group_check_query = "\
+ SELECT \
+ ${groupcheck_table}.id, ${groupcheck_table}.GroupName, ${groupcheck_table}.Attribute, \
+ ${groupcheck_table}.Value,${groupcheck_table}.op \
+ FROM ${groupcheck_table}, ${usergroup_table} \
+ WHERE ${usergroup_table}.Username = '%{SQL-User-Name}' \
+ AND ${usergroup_table}.GroupName = ${groupcheck_table}.GroupName \
+ ORDER BY ${groupcheck_table}.id"
+
+authorize_group_reply_query = "\
+ SELECT \
+ ${groupreply_table}.id, ${groupreply_table}.GroupName, ${groupreply_table}.Attribute, \
+ ${groupreply_table}.Value, ${groupreply_table}.op \
+ FROM ${groupreply_table}, ${usergroup_table} \
+ WHERE ${usergroup_table}.Username = '%{SQL-User-Name}' \
+ AND ${usergroup_table}.GroupName = ${groupreply_table}.GroupName \
+ ORDER BY ${groupreply_table}.id"
+
+#######################################################################
+# Simultaneous Use Checking Queries
+#######################################################################
+# simul_count_query - query for the number of current connections
+# - If this is not defined, no simultaneous use checking
+# - will be performed by this module instance
+# simul_verify_query - query to return details of current connections for verification
+# - Leave blank or commented out to disable verification step
+# - Note that the returned field order should not be changed.
+#######################################################################
+
+simul_count_query = "\
+ SELECT COUNT(*) \
+ FROM ${acct_table1} \
+ WHERE UserName = '%{SQL-User-Name}' \
+ AND AcctStopTime IS NULL"
+
+simul_verify_query = "\
+ SELECT \
+ RadAcctId, AcctSessionId, UserName, NASIPAddress, NASPortId, \
+ FramedIPAddress, CallingStationId, FramedProtocol \
+ FROM ${acct_table1} \
+ WHERE UserName='%{SQL-User-Name}' \
+ AND AcctStopTime IS NULL"
+
+#######################################################################
+# Group Membership Queries
+#######################################################################
+# group_membership_query - Check user group membership
+#######################################################################
+
+group_membership_query = "\
+ SELECT GroupName \
+ FROM ${usergroup_table} \
+ WHERE UserName='%{SQL-User-Name}'"
+
+#######################################################################
+# Accounting and Post-Auth Queries
+#######################################################################
+# These queries insert/update accounting and authentication records.
+# The query to use is determined by the value of 'reference'.
+# This value is used as a configuration path and should resolve to one
+# or more 'query's. If reference points to multiple queries, and a query
+# fails, the next query is executed.
+#
+# Behaviour is identical to the old 1.x/2.x module, except we can now
+# fail between N queries, and query selection can be based on any
+# combination of attributes, or custom 'Acct-Status-Type' values.
+#######################################################################
+accounting {
+ reference = "%{tolower:type.%{%{Acct-Status-Type}:-%{Request-Processing-Stage}}.query}"
+
+ # Write SQL queries to a logfile. This is potentially useful for bulk inserts
+ # when used with the rlm_sql_null driver.
+# logfile = ${logdir}/accounting.sql
+
+ type {
+ accounting-on {
+ query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ AcctStopTime = ${....event_timestamp}, \
+ AcctSessionTime = ROUND((${....event_timestamp} - \
+ TO_DATE(TO_CHAR(acctstarttime, 'yyyy-mm-dd hh24:mi:ss'),'yyyy-mm-dd hh24:mi:ss'))*86400), \
+ AcctTerminateCause='%{%{Acct-Terminate-Cause}:-NAS-Reboot}', \
+ AcctStopDelay = %{%{Acct-Delay-Time}:-0} \
+ WHERE AcctStopTime IS NULL \
+ AND NASIPAddress = '%{NAS-IP-Address}' \
+ AND AcctStartTime <= ${....event_timestamp}"
+ }
+
+ accounting-off {
+ query = "${..accounting-on.query}"
+ }
+
+ #
+ # Implement the "sql_session_start" policy.
+ # See raddb/policy.d/accounting for more details.
+ #
+ # You also need to fix the other queries as
+ # documented below. Look for "sql_session_start".
+ #
+ post-auth {
+ query = "\
+ INSERT INTO ${....acct_table1} (\
+ AcctSessionId, \
+ AcctUniqueId, \
+ UserName, \
+ Realm, \
+ NASIPAddress, \
+ NASPortId, \
+ NASPortType, \
+ AcctStartTime, \
+ AcctUpdateTime, \
+ AcctStopTime, \
+ AcctSessionTime, \
+ AcctAuthentic, \
+ ConnectInfo_start, \
+ ConnectInfo_stop, \
+ AcctInputOctets, \
+ AcctOutputOctets, \
+ CalledStationId, \
+ CallingStationId, \
+ AcctTerminateCause, \
+ ServiceType, \
+ FramedProtocol, \
+ FramedIPAddress, \
+ FramedIPv6Address, \
+ FramedIPv6Prefix, \
+ FramedInterfaceId, \
+ DelegatedIPv6Prefix) \
+ VALUES(\
+ '%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{%{NAS-IPv6-Address}:-%{NAS-IP-Address}}', \
+ '%{%{NAS-Port-ID}:-%{NAS-Port}}', \
+ '%{NAS-Port-Type}', \
+ TO_DATE('%S','yyyy-mm-dd hh24:mi:ss'), \
+ TO_DATE('%S','yyyy-mm-dd hh24:mi:ss'), \
+ NULL, \
+ 0, \
+ '', \
+ '%{Connect-Info}', \
+ NULL, \
+ 0, \
+ 0, \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ NULL, \
+ '%{Service-Type}', \
+ NULL, \
+ '', \
+ '', \
+ '', \
+ '', \
+ '')"
+
+ query = "\
+ UPDATE ${....acct_table1} SET \
+ AcctStartTime = TO_DATE('%S','yyyy-mm-dd hh24:mi:ss'), \
+ AcctUpdateTime = TO_DATE('%S','yyyy-mm-dd hh24:mi:ss'), \
+ ConnectInfo_start = '%{Connect-Info}', \
+ AcctSessionId = '%{Acct-Session-Id}' \
+ WHERE UserName = '%{SQL-User-Name}' \
+ AND NASIPAddress = '%{%{NAS-IPv6-Address}:-%{NAS-IP-Address}}' \
+ AND NASPortId = '%{%{NAS-Port-ID}:-%{NAS-Port}}' \
+ AND NASPortType = '%{NAS-Port-Type}' \
+ AND AcctStopTime IS NULL"
+ }
+
+ start {
+ query = "\
+ INSERT INTO ${....acct_table1} (\
+ RadAcctId, \
+ AcctSessionId, \
+ AcctUniqueId, \
+ UserName, \
+ Realm, \
+ NASIPAddress, \
+ NASPortId, \
+ NASPortType, \
+ AcctStartTime, \
+ AcctUpdateTime, \
+ AcctStopTime, \
+ AcctSessionTime, \
+ AcctAuthentic, \
+ ConnectInfo_start, \
+ ConnectInfo_stop, \
+ AcctInputOctets, \
+ AcctOutputOctets, \
+ CalledStationId, \
+ CallingStationId, \
+ AcctTerminateCause, \
+ ServiceType, \
+ FramedProtocol, \
+ FramedIPAddress, \
+ FramedIPv6Address, \
+ FramedIPv6Prefix, \
+ FramedInterfaceId, \
+ DelegatedIPv6Prefix, \
+ AcctStartDelay, \
+ AcctStopDelay, \
+ XAscendSessionSvrKey \
+ ${....class.column_name}) \
+ VALUES(\
+ '', \
+ '%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{NAS-IP-Address}', \
+ '%{%{NAS-Port-ID}:-%{NAS-Port}}', \
+ '%{NAS-Port-Type}', \
+ ${....event_timestamp}, \
+ ${....event_timestamp}, \
+ NULL, \
+ '0', \
+ '%{Acct-Authentic}', \
+ '%{Connect-Info}', \
+ '', \
+ '0', \
+ '0', \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ '%{Framed-IP-Address}', \
+ '%{Framed-IPv6-Address}', \
+ '%{Framed-IPv6-Prefix}', \
+ '%{Framed-Interface-Id}', \
+ '%{Delegated-IPv6-Prefix}', \
+ '%{Acct-Delay-Time}', \
+ '0', \
+ '%{X-Ascend-Session-Svr-Key}' \
+ ${....class.packet_xlat})"
+
+ #
+ # When using "sql_session_start", you should comment out
+ # the previous query, and enable this one.
+ #
+ # Just change the previous query to "-query",
+ # and this one to "query". The previous one
+ # will be ignored, and this one will be
+ # enabled.
+ #
+ -query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ AcctSessionId = '%{Acct-Session-Id}', \
+ AcctUniqueId = '%{Acct-Unique-Session-Id}', \
+ AcctAuthentic = '%{Acct-Authentic}', \
+ ConnectInfo_start = '%{Connect-Info}', \
+ ServiceType = '%{Service-Type}', \
+ FramedProtocol = '%{Framed-Protocol}', \
+ FramedIPAddress = NULLIF('%{Framed-IP-Address}', ''), \
+ FramedIPv6Address = NULLIF('%{Framed-IPv6-Address}', ''), \
+ FramedIPv6Prefix = NULLIF('%{Framed-IPv6-Prefix}', ''), \
+ FramedInterfaceId = NULLIF('%{Framed-Interface-Id}', ''), \
+ DelegatedIPv6Prefix = NULLIF('%{Delegated-IPv6-Prefix}', ''), \
+ AcctStartTime = TO_DATE('%S','yyyy-mm-dd hh24:mi:ss'), \
+ AcctUpdateTime = TO_DATE('%S','yyyy-mm-dd hh24:mi:ss'), \
+ AcctSessionTime = '0' \
+ WHERE UserName = '%{SQL-User-Name}' \
+ AND NASIPAddress = '%{%{NAS-IPv6-Address}:-%{NAS-IP-Address}}' \
+ AND NASPortId = '%{%{NAS-Port-ID}:-%{NAS-Port}}' \
+ AND NASPortType = '%{NAS-Port-Type}' \
+ AND AcctStopTime IS NULL"
+
+ query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ AcctStartTime = ${....event_timestamp}, \
+ AcctStartDelay = '%{%{Acct-Delay-Time}:-0}', \
+ ConnectInfo_start = '%{Connect-Info}' \
+ WHERE AcctUniqueId = '%{Acct-Unique-Session-ID}' \
+ AND AcctStopTime IS NULL"
+ }
+
+ interim-update {
+ query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ AcctUpdateTime = ${....event_timestamp}, \
+ FramedIPAddress = NULLIF('%{Framed-IP-Address}', ''), \
+ FramedIPv6Address = NULLIF('%{Framed-IPv6-Address}', ''), \
+ FramedIPv6Prefix = NULLIF('%{Framed-IPv6-Prefix}', ''), \
+ FramedInterfaceId = NULLIF('%{Framed-Interface-Id}', ''), \
+ DelegatedIPv6Prefix = NULLIF('%{Delegated-IPv6-Prefix}', ''), \
+ AcctSessionTime = '%{Acct-Session-Time}', \
+ AcctInputOctets = '%{Acct-Input-Octets}' + \
+ ('%{%{Acct-Input-Gigawords}:-0}' * 4294967296), \
+ AcctOutputOctets = '%{Acct-Output-Octets}' + \
+ ('%{%{Acct-Output-Gigawords}:-0}' * 4294967296) \
+ WHERE AcctUniqueId = '%{Acct-Unique-Session-ID}' \
+ AND AcctStopTime IS NULL"
+
+ query = "\
+ INSERT into ${....acct_table1} (\
+ RadAcctId, \
+ AcctSessionId, \
+ AcctUniqueId, \
+ UserName, \
+ Realm, \
+ NASIPAddress, \
+ NASPortId, \
+ NASPortType, \
+ AcctStartTime, \
+ AcctUpdateTime, \
+ AcctSessionTime, \
+ AcctAuthentic, \
+ ConnectInfo_start, \
+ AcctInputOctets, \
+ AcctOutputOctets, \
+ CalledStationId, \
+ CallingStationId, \
+ ServiceType, \
+ FramedProtocol, \
+ FramedIPAddress, \
+ FramedIPv6Address, \
+ FramedIPv6Prefix, \
+ FramedInterfaceId, \
+ DelegatedIPv6Prefix, \
+ AcctStartDelay, \
+ XAscendSessionSvrKey \
+ ${....class.column_name}) \
+ VALUES(\
+ '', \
+ '%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{NAS-IP-Address}', \
+ '%{%{NAS-Port-ID}:-%{NAS-Port}}', \
+ '%{NAS-Port-Type}', \
+ ${....event_timestamp}, \
+ ${....event_timestamp}, \
+ '%{Acct-Session-Time}', \
+ '%{Acct-Authentic}', \
+ '', \
+ '%{Acct-Input-Octets}' + \
+ ('%{%{Acct-Input-Gigawords}:-0}' * 4294967296), \
+ '%{Acct-Output-Octets}' + \
+ ('%{%{Acct-Output-Gigawords}:-0}' * 4294967296), \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ '%{Framed-IP-Address}', \
+ '%{Framed-IPv6-Address}', \
+ '%{Framed-IPv6-Prefix}', \
+ '%{Framed-Interface-Id}', \
+ '%{Delegated-IPv6-Prefix}', \
+ '0', \
+ '%{X-Ascend-Session-Svr-Key}' \
+ ${....class.packet_xlat})"
+
+ #
+ # When using "sql_session_start", you should comment out
+ # the previous query, and enable this one.
+ #
+ # Just change the previous query to "-query",
+ # and this one to "query". The previous one
+ # will be ignored, and this one will be
+ # enabled.
+ #
+ -query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ AcctSessionId = '%{Acct-Session-Id}', \
+ AcctUniqueId = '%{Acct-Unique-Session-Id}', \
+ AcctAuthentic = '%{Acct-Authentic}', \
+ ConnectInfo_start = '%{Connect-Info}', \
+ ServiceType = '%{Service-Type}', \
+ FramedProtocol = '%{Framed-Protocol}', \
+ FramedIPAddress = NULLIF('%{Framed-IP-Address}', ''), \
+ FramedIPv6Address = NULLIF('%{Framed-IPv6-Address}', ''), \
+ FramedIPv6Prefix = NULLIF('%{Framed-IPv6-Prefix}', ''), \
+ FramedInterfaceId = NULLIF('%{Framed-Interface-Id}', ''), \
+ DelegatedIPv6Prefix = NULLIF('%{Delegated-IPv6-Prefix}', ''), \
+ AcctUpdateTime = ${....event_timestamp}, \
+ AcctSessionTime = '%{Acct-Session-Time}', \
+ AcctInputOctets = '%{Acct-Input-Octets}' + \
+ ('%{%{Acct-Input-Gigawords}:-0}' * 4294967296), \
+ AcctOutputOctets = '%{Acct-Output-Octets}' + \
+ ('%{%{Acct-Output-Gigawords}:-0}' * 4294967296) \
+ WHERE UserName = '%{SQL-User-Name}' \
+ AND NASIPAddress = '%{%{NAS-IPv6-Address}:-%{NAS-IP-Address}}' \
+ AND NASPortId = '%{%{NAS-Port-ID}:-%{NAS-Port}}' \
+ AND NASPortType = '%{NAS-Port-Type}' \
+ AND AcctStopTime IS NULL"
+
+ }
+
+ stop {
+ query = "\
+ UPDATE ${....acct_table2} \
+ SET \
+ AcctStopTime = ${....event_timestamp}, \
+ AcctSessionTime = '%{Acct-Session-Time}', \
+ AcctInputOctets = '%{Acct-Input-Octets}' + \
+ ('%{%{Acct-Input-Gigawords}:-0}' * 4294967296), \
+ AcctOutputOctets = '%{Acct-Output-Octets}' + \
+ ('%{%{Acct-Output-Gigawords}:-0}' * 4294967296), \
+ AcctTerminateCause = '%{Acct-Terminate-Cause}', \
+ AcctStopDelay = '%{%{Acct-Delay-Time}:-0}', \
+ ConnectInfo_stop = '%{Connect-Info}' \
+ WHERE AcctUniqueId = '%{Acct-Unique-Session-ID}' \
+ AND AcctStopTime IS NULL"
+
+ query = "\
+ INSERT into ${....acct_table2} (\
+ RadAcctId, \
+ AcctSessionId, \
+ AcctUniqueId, \
+ UserName, \
+ Realm, \
+ NASIPAddress, \
+ NASPortId, \
+ NASPortType, \
+ AcctStartTime, \
+ AcctStopTime, \
+ AcctSessionTime, \
+ AcctAuthentic, \
+ ConnectInfo_start, \
+ ConnectInfo_stop, \
+ AcctInputOctets, \
+ AcctOutputOctets, \
+ CalledStationId, \
+ CallingStationId, \
+ AcctTerminateCause, \
+ ServiceType, \
+ FramedProtocol, \
+ FramedIPAddress, \
+ FramedIPv6Address, \
+ FramedIPv6Prefix, \
+ FramedInterfaceId, \
+ DelegatedIPv6Prefix, \
+ AcctStartDelay, \
+ AcctStopDelay \
+ ${....class.column_name}) \
+ VALUES(\
+ '', \
+ '%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{NAS-IP-Address}', \
+ '%{%{NAS-Port-ID}:-%{NAS-Port}}', \
+ '%{NAS-Port-Type}', \
+ NULL, \
+ ${....event_timestamp}, \
+ '%{Acct-Session-Time}', \
+ '%{Acct-Authentic}', \
+ NULL, \
+ '%{Connect-Info}', \
+ '%{Acct-Input-Octets}' + \
+ ('%{%{Acct-Input-Gigawords}:-0}' * 4294967296), \
+ '%{Acct-Output-Octets}' + \
+ ('%{%{Acct-Output-Gigawords}:-0}' * 4294967296), \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '%{Acct-Terminate-Cause}', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ '%{Framed-IP-Address}', \
+ '%{Framed-IPv6-Address}', \
+ '%{Framed-IPv6-Prefix}', \
+ '%{Framed-Interface-Id}', \
+ '%{Delegated-IPv6-Prefix}', \
+ '0', \
+ '%{%{Acct-Delay-Time}:-0}' \
+ ${....class.packet_xlat})"
+
+ #
+ # When using "sql_session_start", you should comment out
+ # the previous query, and enable this one.
+ #
+ # Just change the previous query to "-query",
+ # and this one to "query". The previous one
+ # will be ignored, and this one will be
+ # enabled.
+ #
+ -query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ AcctSessionId = '%{Acct-Session-Id}', \
+ AcctUniqueId = '%{Acct-Unique-Session-Id}', \
+ AcctAuthentic = '%{Acct-Authentic}', \
+ ConnectInfo_start = '%{Connect-Info}', \
+ ServiceType = '%{Service-Type}', \
+ FramedProtocol = '%{Framed-Protocol}', \
+ FramedIPAddress = NULLIF('%{Framed-IP-Address}', ''), \
+ FramedIPv6Address = NULLIF('%{Framed-IPv6-Address}', ''), \
+ FramedIPv6Prefix = NULLIF('%{Framed-IPv6-Prefix}', ''), \
+ FramedInterfaceId = NULLIF('%{Framed-Interface-Id}', ''), \
+ DelegatedIPv6Prefix = NULLIF('%{Delegated-IPv6-Prefix}', ''), \
+ AcctStopTime = TO_DATE('%S','yyyy-mm-dd hh24:mi:ss'), \
+ AcctSessionTime = '%{Acct-Session-Time}', \
+ AcctInputOctets = '%{Acct-Input-Octets}' + \
+ ('%{%{Acct-Input-Gigawords}:-0}' * 4294967296), \
+ AcctOutputOctets = '%{Acct-Output-Octets}' + \
+ ('%{%{Acct-Output-Gigawords}:-0}' * 4294967296), \
+ AcctTerminateCause = '%{Acct-Terminate-Cause}', \
+ ConnectInfo_stop = '%{Connect-Info}' \
+ WHERE UserName = '%{SQL-User-Name}' \
+ AND NASIPAddress = '%{%{NAS-IPv6-Address}:-%{NAS-IP-Address}}' \
+ AND NASPortId = '%{%{NAS-Port-ID}:-%{NAS-Port}}' \
+ AND NASPortType = '%{NAS-Port-Type}' \
+ AND AcctStopTime IS NULL"
+
+ }
+ }
+}
+
+#######################################################################
+# Authentication Logging Queries
+#######################################################################
+# postauth_query - Insert some info after authentication
+#######################################################################
+
+post-auth {
+ # Write SQL queries to a logfile. This is potentially useful for bulk inserts
+ # when used with the rlm_sql_null driver.
+# logfile = ${logdir}/post-auth.sql
+ query = "\
+ INSERT INTO ${..postauth_table} \
+ (username, pass, reply, authdate ${..class.column_name}) \
+ VALUES (\
+ '%{User-Name}', \
+ '%{%{User-Password}:-%{Chap-Password}}', \
+ '%{reply:Packet-Type}', \
+ TO_TIMESTAMP('%S.%M','YYYY-MM-DDHH24:MI:SS.FF') \
+ ${..class.reply_xlat})"
+}
diff --git a/raddb/mods-config/sql/main/oracle/schema.sql b/raddb/mods-config/sql/main/oracle/schema.sql
new file mode 100644
index 0000000..8f89e9d
--- /dev/null
+++ b/raddb/mods-config/sql/main/oracle/schema.sql
@@ -0,0 +1,205 @@
+/*
+ * $Id$
+ *
+ * Oracle schema for FreeRADIUS
+ *
+ *
+ * NOTE: Which columns are NULLable??
+ */
+
+/*
+ * Table structure for table 'radacct'
+ */
+CREATE TABLE radacct (
+ radacctid INT PRIMARY KEY,
+ acctsessionid VARCHAR(96) NOT NULL,
+ acctuniqueid VARCHAR(32),
+ username VARCHAR(64) NOT NULL,
+ realm VARCHAR(64),
+ nasipaddress VARCHAR(15) NOT NULL,
+ nasportid VARCHAR(32),
+ nasporttype VARCHAR(32),
+ acctstarttime TIMESTAMP WITH TIME ZONE,
+ acctupdatetime TIMESTAMP WITH TIME ZONE,
+ acctstoptime TIMESTAMP WITH TIME ZONE,
+ acctsessiontime NUMERIC(19),
+ acctauthentic VARCHAR(32),
+ connectinfo_start VARCHAR(128),
+ connectinfo_stop VARCHAR(128),
+ acctinputoctets NUMERIC(19),
+ acctoutputoctets NUMERIC(19),
+ calledstationid VARCHAR(50),
+ callingstationid VARCHAR(50),
+ acctterminatecause VARCHAR(32),
+ servicetype VARCHAR(32),
+ framedprotocol VARCHAR(32),
+ framedipaddress VARCHAR(15),
+ framedipv6address VARCHAR(45),
+ framedipv6prefix VARCHAR(45),
+ framedinterfaceid VARCHAR(44),
+ delegatedipv6prefix VARCHAR(45),
+ acctstartdelay NUMERIC(12),
+ acctstopdelay NUMERIC(12),
+ XAscendSessionSvrKey VARCHAR(10),
+ Class VARCHAR(64)
+);
+
+CREATE UNIUQE INDEX radacct_idx0
+ ON radacct(acctuniqueid);
+CREATE UNIQUE INDEX radacct_idx1
+ ON radacct(acctsessionid,username,acctstarttime,
+ acctstoptime,nasipaddress,framedipaddress,framedipv6address,framedipv6prefix,framedinterfaceid,delegatedipv6prefix);
+CREATE INDEX radacct_idx2
+ ON radacct(class);
+
+CREATE SEQUENCE radacct_seq START WITH 1 INCREMENT BY 1;
+
+/* Trigger to emulate a serial # on the primary key */
+CREATE OR REPLACE TRIGGER radacct_serialnumber
+ BEFORE INSERT OR UPDATE OF radacctid ON radacct
+ FOR EACH ROW
+ BEGIN
+ if ( :new.radacctid = 0 or :new.radacctid is null ) then
+ SELECT radacct_seq.nextval into :new.radacctid from dual;
+ end if;
+ END;
+/
+
+/*
+ * Table structure for table 'radcheck'
+ */
+CREATE TABLE radcheck (
+ id INT PRIMARY KEY,
+ username VARCHAR(30) NOT NULL,
+ attribute VARCHAR(64),
+ op VARCHAR(2) NOT NULL,
+ value VARCHAR(40)
+);
+CREATE SEQUENCE radcheck_seq START WITH 1 INCREMENT BY 1;
+
+/* Trigger to emulate a serial # on the primary key */
+CREATE OR REPLACE TRIGGER radcheck_serialnumber
+ BEFORE INSERT OR UPDATE OF id ON radcheck
+ FOR EACH ROW
+ BEGIN
+ if ( :new.id = 0 or :new.id is null ) then
+ SELECT radcheck_seq.nextval into :new.id from dual;
+ end if;
+ END;
+/
+
+/*
+ * Table structure for table 'radgroupcheck'
+ */
+CREATE TABLE radgroupcheck (
+ id INT PRIMARY KEY,
+ groupname VARCHAR(20) NOT NULL,
+ attribute VARCHAR(64),
+ op CHAR(2) NOT NULL,
+ value VARCHAR(40)
+);
+CREATE SEQUENCE radgroupcheck_seq START WITH 1 INCREMENT BY 1;
+
+/*
+ * Table structure for table 'radgroupreply'
+ */
+CREATE TABLE radgroupreply (
+ id INT PRIMARY KEY,
+ GroupName VARCHAR(20) NOT NULL,
+ Attribute VARCHAR(64),
+ op CHAR(2) NOT NULL,
+ Value VARCHAR(40)
+);
+CREATE SEQUENCE radgroupreply_seq START WITH 1 INCREMENT BY 1;
+
+/*
+ * Table structure for table 'radreply'
+ */
+CREATE TABLE radreply (
+ id INT PRIMARY KEY,
+ UserName VARCHAR(30) NOT NULL,
+ Attribute VARCHAR(64),
+ op CHAR(2) NOT NULL,
+ Value VARCHAR(40)
+);
+CREATE INDEX radreply_idx1 ON radreply(UserName);
+CREATE SEQUENCE radreply_seq START WITH 1 INCREMENT BY 1;
+
+/* Trigger to emulate a serial # on the primary key */
+CREATE OR REPLACE TRIGGER radreply_serialnumber
+ BEFORE INSERT OR UPDATE OF id ON radreply
+ FOR EACH ROW
+ BEGIN
+ if ( :new.id = 0 or :new.id is null ) then
+ SELECT radreply_seq.nextval into :new.id from dual;
+ end if;
+ END;
+/
+
+/*
+ * Table structure for table 'radusergroup'
+ */
+CREATE TABLE radusergroup (
+ id INT PRIMARY KEY,
+ UserName VARCHAR(30) NOT NULL,
+ GroupName VARCHAR(30)
+);
+CREATE SEQUENCE radusergroup_seq START WITH 1 INCREMENT BY 1;
+
+/* Trigger to emulate a serial # on the primary key */
+CREATE OR REPLACE TRIGGER radusergroup_serialnumber
+ BEFORE INSERT OR UPDATE OF id ON radusergroup
+ FOR EACH ROW
+ BEGIN
+ if ( :new.id = 0 or :new.id is null ) then
+ SELECT radusergroup_seq.nextval into :new.id from dual;
+ end if;
+ END;
+/
+
+
+CREATE TABLE radpostauth (
+ id INT PRIMARY KEY,
+ UserName VARCHAR(64) NOT NULL,
+ Pass VARCHAR(64),
+ Reply VARCHAR(64),
+ AuthDate TIMESTAMP(6) WITH TIME ZONE,
+ Class VARCHAR(64)
+);
+CREATE INDEX radpostauth_idx0
+ ON radpostauth(UserName);
+CREATE INDEX radpostauth_idx1
+ ON radpostauth(class);
+
+CREATE SEQUENCE radpostauth_seq START WITH 1 INCREMENT BY 1;
+
+CREATE OR REPLACE TRIGGER radpostauth_TRIG
+ BEFORE INSERT OR UPDATE OF id ON radpostauth
+ FOR EACH ROW
+ BEGIN
+ if ( :new.id = 0 or :new.id is null ) then
+ SELECT radpostauth_seq.nextval into :new.id from dual;
+ end if;
+ if (:new.AuthDate is null) then
+ select systimestamp into :new.AuthDate from dual;
+ end if;
+ END;
+
+/
+
+/*
+ * Table structure for table 'nas'
+ */
+CREATE TABLE nas (
+ id INT PRIMARY KEY,
+ nasname VARCHAR(128),
+ shortname VARCHAR(32),
+ type VARCHAR(30),
+ ports INT,
+ secret VARCHAR(60),
+ server VARCHAR(64),
+ community VARCHAR(50),
+ description VARCHAR(200)
+);
+CREATE SEQUENCE nas_seq START WITH 1 INCREMENT BY 1;
+
diff --git a/raddb/mods-config/sql/main/postgresql/extras/cisco_h323_db_schema.sql b/raddb/mods-config/sql/main/postgresql/extras/cisco_h323_db_schema.sql
new file mode 100644
index 0000000..0fabd43
--- /dev/null
+++ b/raddb/mods-config/sql/main/postgresql/extras/cisco_h323_db_schema.sql
@@ -0,0 +1,295 @@
+/*
+ * $Id$
+ *
+ * --- Peter Nixon [ codemonkey@peternixon.net ]
+ *
+ * This is a custom SQL schema for doing H323 and SIP VoIP accounting
+ * with FreeRadius and Cisco equipment. It is currently known to work
+ * with 3640, 5300 and 5350 series as well as CSPS (Cisco SIP Proxy
+ * Server). It will scale A LOT better than the default radius schema
+ * which is designed for simple dialup installations of FreeRadius.
+ *
+ * For this schema to work properly you MUST use
+ * raddb/mods-config/sql/postgresql/voip-postpaid.conf rather than
+ * raddb/mods-config/sql/postgresql/dialup.conf
+ *
+ * If you wish to do RADIUS Authentication using the same database,
+ * you MUST use use raddb/mods-config/sql/postgresql/schema.sql as well as this schema.
+ */
+
+/*
+ * Table structure for 'Start' tables
+ */
+
+CREATE TABLE StartVoIP (
+ RadAcctId BIGSERIAL PRIMARY KEY,
+ AcctTime TIMESTAMP with time zone NOT NULL,
+ h323SetupTime TIMESTAMP with time zone,
+ H323ConnectTime TIMESTAMP with time zone,
+ UserName VARCHAR(64),
+ RadiusServerName VARCHAR(32),
+ NASIPAddress INET NOT NULL,
+ CalledStationId VARCHAR(80),
+ CallingStationId VARCHAR(80),
+ AcctDelayTime INTEGER,
+ H323GWID VARCHAR(32),
+ h323CallOrigin VARCHAR(10),
+ CallID VARCHAR(80) NOT NULL,
+ processed BOOLEAN DEFAULT false
+);
+create index startvoipcombo on startvoip (AcctTime, nasipaddress);
+
+
+CREATE TABLE StartTelephony (
+ RadAcctId BIGSERIAL PRIMARY KEY,
+ AcctTime TIMESTAMP with time zone NOT NULL,
+ h323SetupTime TIMESTAMP with time zone,
+ H323ConnectTime TIMESTAMP with time zone,
+ UserName VARCHAR(64),
+ RadiusServerName VARCHAR(32),
+ NASIPAddress INET NOT NULL,
+ CalledStationId VARCHAR(80),
+ CallingStationId VARCHAR(80),
+ AcctDelayTime INTEGER,
+ H323GWID VARCHAR(32),
+ h323CallOrigin VARCHAR(10),
+ CallID VARCHAR(80) NOT NULL,
+ processed BOOLEAN DEFAULT false
+);
+create index starttelephonycombo on starttelephony (AcctTime, nasipaddress);
+
+
+
+/*
+ * Table structure for 'Stop' tables
+ */
+CREATE TABLE StopVoIP (
+ RadAcctId BIGSERIAL PRIMARY KEY,
+ AcctTime TIMESTAMP with time zone NOT NULL,
+ H323SetupTime TIMESTAMP with time zone,
+ H323ConnectTime TIMESTAMP with time zone,
+ H323DisconnectTime TIMESTAMP with time zone,
+ UserName VARCHAR(32),
+ RadiusServerName VARCHAR(32),
+ NASIPAddress INET NOT NULL,
+ AcctSessionTime BIGINT,
+ AcctInputOctets BIGINT,
+ AcctOutputOctets BIGINT,
+ CalledStationId VARCHAR(80),
+ CallingStationId VARCHAR(80),
+ AcctDelayTime SMALLINT,
+ CiscoNASPort VARCHAR(1),
+ H323GWID VARCHAR(32),
+ H323CallOrigin VARCHAR(10),
+ H323DisconnectCause VARCHAR(20),
+ H323RemoteAddress INET,
+ H323VoiceQuality INTEGER,
+ CallID VARCHAR(80) NOT NULL,
+ processed BOOLEAN DEFAULT false
+);
+create UNIQUE index stopvoipcombo on stopvoip (AcctTime, nasipaddress, CallID);
+
+
+CREATE TABLE StopTelephony (
+ RadAcctId BIGSERIAL PRIMARY KEY,
+ AcctTime TIMESTAMP with time zone NOT NULL,
+ H323SetupTime TIMESTAMP with time zone NOT NULL,
+ H323ConnectTime TIMESTAMP with time zone NOT NULL,
+ H323DisconnectTime TIMESTAMP with time zone NOT NULL,
+ UserName VARCHAR(32) DEFAULT '' NOT NULL,
+ RadiusServerName VARCHAR(32),
+ NASIPAddress INET NOT NULL,
+ AcctSessionTime BIGINT,
+ AcctInputOctets BIGINT,
+ AcctOutputOctets BIGINT,
+ CalledStationId VARCHAR(80),
+ CallingStationId VARCHAR(80),
+ AcctDelayTime SMALLINT,
+ CiscoNASPort VARCHAR(16),
+ H323GWID VARCHAR(32),
+ H323CallOrigin VARCHAR(10),
+ H323DisconnectCause VARCHAR(20),
+ H323RemoteAddress INET,
+ H323VoiceQuality INTEGER,
+ CallID VARCHAR(80) NOT NULL,
+ processed BOOLEAN DEFAULT false
+);
+-- You can have more than one record that is identical except for CiscoNASPort if you have a dial peer hungroup
+-- configured for multiple PRIs.
+create UNIQUE index stoptelephonycombo on stoptelephony (AcctTime, nasipaddress, CallID, CiscoNASPort);
+
+/*
+ * Table structure for 'gateways'
+ *
+ * This table should list the IP addresses, names and locations of all your gateways
+ * This can be used to make more useful reports.
+ *
+ * Note: This table should be removed in favour of using the "nas" table.
+ */
+
+CREATE TABLE gateways (
+ gw_ip INET NOT NULL,
+ gw_name VARCHAR(32) NOT NULL,
+ gw_city VARCHAR(32)
+);
+
+
+/*
+ * Table structure for 'customers'
+ *
+ * This table should list your Customers names and company
+ * This can be used to make more useful reports.
+ */
+
+CREATE TABLE customers (
+ cust_id SERIAL NOT NULL,
+ company VARCHAR(32),
+ customer VARCHAR(32)
+);
+
+/*
+ * Table structure for 'cust_gw'
+ *
+ * This table should list the IP addresses and Customer IDs of all your Customers gateways
+ * This can be used to make more useful reports.
+ */
+
+CREATE TABLE cust_gw (
+ cust_gw INET PRIMARY KEY,
+ cust_id INTEGER NOT NULL,
+ "location" VARCHAR(32)
+);
+
+
+CREATE VIEW customerip AS
+ SELECT gw.cust_gw AS ipaddr, cust.company, cust.customer, gw."location" FROM customers cust, cust_gw gw WHERE (cust.cust_id = gw.cust_id);
+
+
+-- create plpgsql language (You need to be a database superuser to be able to do this)
+CREATE FUNCTION "plpgsql_call_handler" () RETURNS LANGUAGE_HANDLER AS '$libdir/plpgsql' LANGUAGE C;
+CREATE TRUSTED LANGUAGE "plpgsql" HANDLER "plpgsql_call_handler";
+
+/*
+ * Function 'strip_dot'
+ * removes "." from the start of cisco timestamps
+ *
+ * From the cisco website:
+ * "A timestamp that is preceded by an asterisk (*) or a dot (.) may not be accurate.
+ * An asterisk (*) means that after a gateway reboot, the gateway clock was not manually set
+ * and the gateway has not synchronized with an NTP server yet. A dot (.) means the gateway
+ * NTP has lost synchronization with an NTP server."
+ *
+ * We therefore do not bother to strip asterisks (*) from timestamps, as you NEED ntp setup
+ * unless you don't care about billing at all!
+ *
+ * * Example useage:
+ * insert into mytable values (strip_dot('.16:46:02.356 EET Wed Dec 11 2002'));
+ *
+ */
+
+
+CREATE OR REPLACE FUNCTION strip_dot (VARCHAR) RETURNS TIMESTAMPTZ AS '
+ DECLARE
+ original_timestamp ALIAS FOR $1;
+ BEGIN
+ IF original_timestamp = '''' THEN
+ RETURN NULL;
+ END IF;
+ IF substring(original_timestamp from 1 for 1) = ''.'' THEN
+ RETURN substring(original_timestamp from 2);
+ ELSE
+ RETURN original_timestamp;
+ END IF;
+ END;
+' LANGUAGE 'plpgsql';
+
+
+CREATE OR REPLACE FUNCTION pick_id (VARCHAR, VARCHAR) RETURNS VARCHAR AS '
+ DECLARE
+ h323confid ALIAS FOR $1;
+ callid ALIAS FOR $2;
+ BEGIN
+ IF h323confid <> '''' THEN
+ RETURN h323confid;
+ END IF;
+ IF callid <> '''' THEN
+ RETURN callid;
+ END IF;
+ RETURN NULL;
+ END;
+' LANGUAGE 'plpgsql';
+
+
+
+/*
+ * Table structure for 'isdn_error_codes' table
+ *
+ * Taken from cisco.com this data can be JOINED against h323DisconnectCause to
+ * give human readable error reports.
+ *
+ */
+
+
+CREATE TABLE isdn_error_codes (
+ error_code VARCHAR(2) PRIMARY KEY,
+ desc_short VARCHAR(90),
+ desc_long TEXT
+);
+
+/*
+ * Data for 'isdn_error_codes' table
+ */
+
+INSERT INTO isdn_error_codes VALUES ('1', 'Unallocated (unassigned) number', 'The ISDN number was sent to the switch in the correct format; however, the number is not assigned to any destination equipment.');
+INSERT INTO isdn_error_codes VALUES ('10', 'Normal call clearing', 'Normal call clearing has occurred.');
+INSERT INTO isdn_error_codes VALUES ('11', 'User busy', 'The called system acknowledges the connection request but is unable to accept the call because all B channels are in use.');
+INSERT INTO isdn_error_codes VALUES ('12', 'No user responding', 'The connection cannot be completed because the destination does not respond to the call.');
+INSERT INTO isdn_error_codes VALUES ('13', 'No answer from user (user alerted)', 'The destination responds to the connection request but fails to complete the connection within the prescribed time. The problem is at the remote end of the connection.');
+INSERT INTO isdn_error_codes VALUES ('15', 'Call rejected', 'The destination is capable of accepting the call but rejected the call for an unknown reason.');
+INSERT INTO isdn_error_codes VALUES ('16', 'Number changed', 'The ISDN number used to set up the call is not assigned to any system.');
+INSERT INTO isdn_error_codes VALUES ('1A', 'Non-selected user clearing', 'The destination is capable of accepting the call but rejected the call because it was not assigned to the user.');
+INSERT INTO isdn_error_codes VALUES ('1B', 'Designation out of order', 'The destination cannot be reached because the interface is not functioning correctly, and a signaling message cannot be delivered. This might be a temporary condition, but it could last for an extended period of time. For example, the remote equipment might be turned off.');
+INSERT INTO isdn_error_codes VALUES ('1C', 'Invalid number format', 'The connection could be established because the destination address was presented in an unrecognizable format or because the destination address was incomplete.');
+INSERT INTO isdn_error_codes VALUES ('1D', 'Facility rejected', 'The facility requested by the user cannot be provided by the network.');
+INSERT INTO isdn_error_codes VALUES ('1E', 'Response to STATUS ENQUIRY', 'The status message was generated in direct response to the prior receipt of a status enquiry message.');
+INSERT INTO isdn_error_codes VALUES ('1F', 'Normal, unspecified', 'Reports the occurrence of a normal event when no standard cause applies. No action required.');
+INSERT INTO isdn_error_codes VALUES ('2', 'No route to specified transit network', 'The ISDN exchange is asked to route the call through an unrecognized intermediate network.');
+INSERT INTO isdn_error_codes VALUES ('22', 'No circuit/channel available', 'The connection cannot be established because no appropriate channel is available to take the call.');
+INSERT INTO isdn_error_codes VALUES ('26', 'Network out of order', 'The destination cannot be reached because the network is not functioning correctly, and the condition might last for an extended period of time. An immediate reconnect attempt will probably be unsuccessful.');
+INSERT INTO isdn_error_codes VALUES ('29', 'Temporary failure', 'An error occurred because the network is not functioning correctly. The problem will be resolved shortly.');
+INSERT INTO isdn_error_codes VALUES ('2A', 'Switching equipment congestion', 'The destination cannot be reached because the network switching equipment is temporarily overloaded.');
+INSERT INTO isdn_error_codes VALUES ('2B', 'Access information discarded', 'The network cannot provide the requested access information.');
+INSERT INTO isdn_error_codes VALUES ('2C', 'Requested circuit/channel not available', 'The remote equipment cannot provide the requested channel for an unknown reason. This might be a temporary problem.');
+INSERT INTO isdn_error_codes VALUES ('2F', 'Resources unavailable, unspecified', 'The requested channel or service is unavailable for an unknown reason. This might be a temporary problem.');
+INSERT INTO isdn_error_codes VALUES ('3', 'No route to destination', 'The call was routed through an intermediate network that does not serve the destination address.');
+INSERT INTO isdn_error_codes VALUES ('31', 'Quality of service unavailable', 'The requested quality of service cannot be provided by the network. This might be a subscription problem.');
+INSERT INTO isdn_error_codes VALUES ('32', 'Requested facility not subscribed', 'The remote equipment supports the requested supplementary service by subscription only.');
+INSERT INTO isdn_error_codes VALUES ('39', 'Bearer capability not authorized', 'The user requested a bearer capability that the network provides, but the user is not authorized to use it. This might be a subscription problem.');
+INSERT INTO isdn_error_codes VALUES ('3A', 'Bearer capability not presently available', 'The network normally provides the requested bearer capability, but it is unavailable at the present time. This might be due to a temporary network problem or to a subscription problem.');
+INSERT INTO isdn_error_codes VALUES ('3F', 'Service or option not available, unspecified', 'The network or remote equipment was unable to provide the requested service option for an unspecified reason. This might be a subscription problem.');
+INSERT INTO isdn_error_codes VALUES ('41', 'Bearer capability not implemented', 'The network cannot provide the bearer capability requested by the user.');
+INSERT INTO isdn_error_codes VALUES ('42', 'Channel type not implemented', 'The network or the destination equipment does not support the requested channel type.');
+INSERT INTO isdn_error_codes VALUES ('45', 'Requested facility not implemented', 'The remote equipment does not support the requested supplementary service.');
+INSERT INTO isdn_error_codes VALUES ('46', 'Only restricted digital information bearer capability is available', 'The network is unable to provide unrestricted digital information bearer capability.');
+INSERT INTO isdn_error_codes VALUES ('4F', 'Service or option not implemented, unspecified', 'The network or remote equipment is unable to provide the requested service option for an unspecified reason. This might be a subscription problem.');
+INSERT INTO isdn_error_codes VALUES ('51', 'Invalid call reference value', 'The remote equipment received a call with a call reference that is not currently in use on the user-network interface.');
+INSERT INTO isdn_error_codes VALUES ('52', 'Identified channel does not exist', 'The receiving equipment is requested to use a channel that is not activated on the interface for calls.');
+INSERT INTO isdn_error_codes VALUES ('53', 'A suspended call exists, but this call identity does not', 'The network received a call resume request. The call resume request contained a Call Identify information element that indicates that the call identity is being used for a suspended call.');
+INSERT INTO isdn_error_codes VALUES ('54', 'Call identity in use', 'The network received a call resume request. The call resume request contained a Call Identify information element that indicates that it is in use for a suspended call.');
+INSERT INTO isdn_error_codes VALUES ('55', 'No call suspended', 'The network received a call resume request when there was not a suspended call pending. This might be a transient error that will be resolved by successive call retries.');
+INSERT INTO isdn_error_codes VALUES ('56', 'Call having the requested call identity has been cleared', 'The network received a call resume request. The call resume request contained a Call Identity information element, which once indicated a suspended call. However, the suspended call was cleared either by timeout or by the remote user.');
+INSERT INTO isdn_error_codes VALUES ('58', 'Incompatible destination', 'Indicates that an attempt was made to connect to non-ISDN equipment. For example, to an analog line.');
+INSERT INTO isdn_error_codes VALUES ('5B', 'Invalid transit network selection', 'The ISDN exchange was asked to route the call through an unrecognized intermediate network.');
+INSERT INTO isdn_error_codes VALUES ('5F', 'Invalid message, unspecified', 'An invalid message was received, and no standard cause applies. This is usually due to a D-channel error. If this error occurs systematically, report it to your ISDN service provider.');
+INSERT INTO isdn_error_codes VALUES ('6', 'Channel unacceptable', 'The service quality of the specified channel is insufficient to accept the connection.');
+INSERT INTO isdn_error_codes VALUES ('60', 'Mandatory information element is missing', 'The receiving equipment received a message that did not include one of the mandatory information elements. This is usually due to a D-channel error. If this error occurs systematically, report it to your ISDN service provider.');
+INSERT INTO isdn_error_codes VALUES ('61', 'Message type non-existent or not implemented', 'The receiving equipment received an unrecognized message, either because the message type was invalid or because the message type was valid but not supported. The cause is due to either a problem with the remote configuration or a problem with the local D channel.');
+INSERT INTO isdn_error_codes VALUES ('62', 'Message not compatible with call state or message type non-existent or not implemented', 'The remote equipment received an invalid message, and no standard cause applies. This cause is due to a D-channel error. If this error occurs systematically, report it to your ISDN service provider.');
+INSERT INTO isdn_error_codes VALUES ('63', 'Information element non-existent or not implemented', 'The remote equipment received a message that includes information elements, which were not recognized. This is usually due to a D-channel error. If this error occurs systematically, report it to your ISDN service provider.');
+INSERT INTO isdn_error_codes VALUES ('64', 'Invalid information element contents', 'The remote equipment received a message that includes invalid information in the information element. This is usually due to a D-channel error.');
+INSERT INTO isdn_error_codes VALUES ('65', 'Message not compatible with call state', 'The remote equipment received an unexpected message that does not correspond to the current state of the connection. This is usually due to a D-channel error.');
+INSERT INTO isdn_error_codes VALUES ('66', 'Recovery on timer expires', 'An error-handling (recovery) procedure was initiated by a timer expiry. This is usually a temporary problem.');
+INSERT INTO isdn_error_codes VALUES ('6F', 'Protocol error, unspecified', 'An unspecified D-channel error when no other standard cause applies.');
+INSERT INTO isdn_error_codes VALUES ('7', 'Call awarded and being delivered in an established channel', 'The user is assigned an incoming call that is being connected to an already-established call channel.');
+INSERT INTO isdn_error_codes VALUES ('7F', 'Internetworking, unspecified', 'An event occurred, but the network does not provide causes for the action that it takes. The precise problem is unknown.');
+
diff --git a/raddb/mods-config/sql/main/postgresql/extras/voip-postpaid.conf b/raddb/mods-config/sql/main/postgresql/extras/voip-postpaid.conf
new file mode 100644
index 0000000..9f1449c
--- /dev/null
+++ b/raddb/mods-config/sql/main/postgresql/extras/voip-postpaid.conf
@@ -0,0 +1,70 @@
+# -*- text -*-
+##
+## voip-postpaid.conf -- PostgreSQL configuration for H323 VoIP billingx
+## (cisco_h323_db_schema.sql)
+##
+## $Id$
+
+
+ #######################################################################
+ # Query config: Username
+ #######################################################################
+ # This is the username that will get substituted, escaped, and added
+ # as attribute 'SQL-User-Name'. '%{SQL-User-Name}' should be used below
+ # everywhere a username substitution is needed so you you can be sure
+ # the username passed from the client is escaped properly.
+ #
+ # Uncomment the next line, if you want the sql_user_name to mean:
+ #
+ # Use Stripped-User-Name, if it's there.
+ # Else use User-Name, if it's there,
+ # Else use hard-coded string "none" as the user name.
+ #
+ #sql_user_name = "%{%{Stripped-User-Name}:-%{%{User-Name}:-none}}"
+ #
+ sql_user_name = "%{User-Name}"
+
+ accounting {
+ reference = "%{tolower:type.%{Acct-Status-Type}.query}"
+
+ # Write SQL queries to a logfile. This is potentially useful for bulk inserts
+ # when used with the rlm_sql_null driver.
+# logfile = ${logdir}/accounting.sql
+
+ type {
+ start {
+ query = "INSERT INTO ${....acct_table1}%{h323-call-type} \
+ (RadiusServerName, UserName, NASIPAddress, AcctTime, CalledStationId, \
+ CallingStationId, AcctDelayTime, h323gwid, h323callorigin, \
+ h323setuptime, H323ConnectTime, callid) \
+ VALUES(\
+ '${radius_server_name}', '%{SQL-User-Name}', \
+ '%{NAS-IP-Address}', now(), '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', '%{%{Acct-Delay-Time}:-0}', '%{h323-gw-id}', \
+ '%{h323-call-origin}', strip_dot('%{h323-setup-time}'), \
+ strip_dot('%{h323-connect-time}'), pick_id('%{h323-conf-id}', \
+ '%{call-id}'))"
+ }
+
+ stop {
+ query = "INSERT INTO $....acct_table2}%{h323-call-type} \
+ (RadiusServerName, UserName, NASIPAddress, AcctTime, \
+ AcctSessionTime, AcctInputOctets, AcctOutputOctets, CalledStationId, \
+ CallingStationId, AcctDelayTime, H323RemoteAddress, H323VoiceQuality, \
+ CiscoNASPort, h323callorigin, callid, h323connecttime, \
+ h323disconnectcause, h323disconnecttime, h323gwid, h323setuptime) \
+ VALUES(\
+ '${radius_server_name}', '%{SQL-User-Name}', '%{NAS-IP-Address}', \
+ NOW(), '%{%{Acct-Session-Time}:-0}', \
+ '%{%{Acct-Input-Octets}:-0}', '%{%{Acct-Output-Octets}:-0}', \
+ '%{Called-Station-Id}', '%{Calling-Station-Id}', \
+ '%{%{Acct-Delay-Time}:-0}', NULLIF('%{h323-remote-address}', '')::inet, \
+ NULLIF('%{h323-voice-quality}','')::integer, \
+ NULLIF('%{Cisco-NAS-Port}', ''), \
+ '%{h323-call-origin}', pick_id('%{h323-conf-id}', '%{call-id}'), \
+ strip_dot('%{h323-connect-time}'), '%{h323-disconnect-cause}', \
+ strip_dot('%{h323-disconnect-time}'), '%{h323-gw-id}', \
+ strip_dot('%{h323-setup-time}'))"
+ }
+ }
+ }
diff --git a/raddb/mods-config/sql/main/postgresql/process-radacct.sql b/raddb/mods-config/sql/main/postgresql/process-radacct.sql
new file mode 100644
index 0000000..a454369
--- /dev/null
+++ b/raddb/mods-config/sql/main/postgresql/process-radacct.sql
@@ -0,0 +1,288 @@
+# -*- text -*-
+#
+# main/postgresql/process-radacct.sql -- Schema extensions for processing radacct entries
+#
+# $Id$
+
+-- ---------------------------------
+-- - Per-user data usage over time -
+-- ---------------------------------
+--
+-- An extension to the standard schema to hold per-user data usage statistics
+-- for arbitrary periods.
+--
+-- The data_usage_by_period table is populated by periodically calling the
+-- fr_new_data_usage_period stored procedure.
+--
+-- This table can be queried in various ways to produce reports of aggregate
+-- data use over time. For example, if the fr_new_data_usage_period SP is
+-- invoked one per day just after midnight, to produce usage data with daily
+-- granularity, then a reasonably accurate monthly bandwidth summary for a
+-- given user could be obtained by queriing this table with:
+--
+-- SELECT
+-- TO_CHAR(period_start, 'YYYY-Month') AS month,
+-- TRUNC(SUM(acctinputoctets)/1000/1000/1000,9) AS gb_in,
+-- TRUNC(SUM(acctoutputoctets)/1000/1000/1000,9) AS gb_out
+-- FROM
+-- data_usage_by_period
+-- WHERE
+-- username='bob' AND
+-- period_end IS NOT NULL
+-- GROUP BY
+-- month;
+--
+-- month | gb_in | gb_out
+-- ----------------+-------------+--------------
+-- 2019-July | 5.782279231 | 50.545664824
+-- 2019-August | 4.230543344 | 48.523096424
+-- 2019-September | 4.847360599 | 48.631835488
+-- 2019-October | 6.456763254 | 51.686231937
+-- 2019-November | 6.362537735 | 52.385710572
+-- 2019-December | 4.301524442 | 50.762240277
+-- 2020-January | 5.436280545 | 49.067775286
+-- (7 rows)
+--
+CREATE TABLE data_usage_by_period (
+ username text,
+ period_start timestamp with time zone,
+ period_end timestamp with time zone,
+ acctinputoctets bigint,
+ acctoutputoctets bigint
+);
+ALTER TABLE data_usage_by_period ADD CONSTRAINT data_usage_by_period_pkey PRIMARY KEY (username, period_start);
+CREATE INDEX data_usage_by_period_pkey_period_end ON data_usage_by_period(period_end);
+
+
+--
+-- Stored procedure that when run with some arbitrary frequency, say
+-- once per day by cron, will process the recent radacct entries to extract
+-- time-windowed data containing acct{input,output}octets ("data usage") per
+-- username, per period.
+--
+-- Each invocation will create new rows in the data_usage_by_period tables
+-- containing the data used by each user since the procedure was last invoked.
+-- The intervals do not need to be identical but care should be taken to
+-- ensure that the start/end of each period aligns well with any intended
+-- reporting intervals.
+--
+-- It can be invoked by running:
+--
+-- SELECT fr_new_data_usage_period();
+--
+--
+CREATE OR REPLACE FUNCTION fr_new_data_usage_period ()
+RETURNS void
+LANGUAGE plpgsql
+AS $$
+DECLARE v_start timestamp;
+DECLARE v_end timestamp;
+BEGIN
+
+ SELECT COALESCE(MAX(period_end) + INTERVAL '1 SECOND', TO_TIMESTAMP(0)) INTO v_start FROM data_usage_by_period;
+ SELECT DATE_TRUNC('second',CURRENT_TIMESTAMP) INTO v_end;
+
+ --
+ -- Add the data usage for the sessions that were active in the current
+ -- period to the table. Include all sessions that finished since the start
+ -- of this period as well as those still ongoing.
+ --
+ INSERT INTO data_usage_by_period (username, period_start, period_end, acctinputoctets, acctoutputoctets)
+ SELECT *
+ FROM (
+ SELECT
+ username,
+ v_start,
+ v_end,
+ SUM(acctinputoctets) AS acctinputoctets,
+ SUM(acctoutputoctets) AS acctoutputoctets
+ FROM ((
+ SELECT
+ username, acctinputoctets, acctoutputoctets
+ FROM
+ radacct
+ WHERE
+ acctstoptime > v_start
+ ) UNION ALL (
+ SELECT
+ username, acctinputoctets, acctoutputoctets
+ FROM
+ radacct
+ WHERE
+ acctstoptime IS NULL
+ )) AS a
+ GROUP BY
+ username
+ ) AS s
+ ON CONFLICT ON CONSTRAINT data_usage_by_period_pkey
+ DO UPDATE
+ SET
+ acctinputoctets = data_usage_by_period.acctinputoctets + EXCLUDED.acctinputoctets,
+ acctoutputoctets = data_usage_by_period.acctoutputoctets + EXCLUDED.acctoutputoctets,
+ period_end = v_end;
+
+ --
+ -- Create an open-ended "next period" for all ongoing sessions and carry a
+ -- negative value of their data usage to avoid double-accounting when we
+ -- process the next period. Their current data usage has already been
+ -- allocated to the current and possibly previous periods.
+ --
+ INSERT INTO data_usage_by_period (username, period_start, period_end, acctinputoctets, acctoutputoctets)
+ SELECT *
+ FROM (
+ SELECT
+ username,
+ v_end + INTERVAL '1 SECOND',
+ NULL::timestamp,
+ 0 - SUM(acctinputoctets),
+ 0 - SUM(acctoutputoctets)
+ FROM
+ radacct
+ WHERE
+ acctstoptime IS NULL
+ GROUP BY
+ username
+ ) AS s;
+
+END
+$$;
+
+
+-- ------------------------------------------------------
+-- - "Lightweight" Accounting-On/Off strategy resources -
+-- ------------------------------------------------------
+--
+-- The following resources are for use only when the "lightweight"
+-- Accounting-On/Off strategy is enabled in queries.conf.
+--
+-- Instead of bulk closing the radacct sessions belonging to a reloaded NAS,
+-- this strategy leaves them open and records the NAS reload time in the
+-- nasreload table.
+--
+-- Where applicable, the onus is on the administator to:
+--
+-- * Consider the nas reload times when deriving a list of
+-- active/inactive sessions, and when determining the duration of sessions
+-- interrupted by a NAS reload. (Refer to the view below.)
+--
+-- * Close the affected sessions out of band. (Refer to the SP below.)
+--
+--
+-- The radacct_with_reloads view presents the radacct table with two additional
+-- columns: acctstoptime_with_reloads and acctsessiontime_with_reloads
+--
+-- Where the session isn't closed (acctstoptime IS NULL), yet it started before
+-- the last reload of the NAS (radacct.acctstarttime < nasreload.reloadtime),
+-- the derived columns are set based on the reload time of the NAS (effectively
+-- the point in time that the session was interrupted.)
+--
+CREATE VIEW radacct_with_reloads AS
+SELECT
+ a.*,
+ COALESCE(a.AcctStopTime,
+ CASE WHEN a.AcctStartTime < n.ReloadTime THEN n.ReloadTime END
+ ) AS AcctStopTime_With_Reloads,
+ COALESCE(a.AcctSessionTime,
+ CASE WHEN a.AcctStopTime IS NULL AND a.AcctStartTime < n.ReloadTime THEN
+ EXTRACT(EPOCH FROM (n.ReloadTime - a.AcctStartTime))
+ END
+ ) AS AcctSessionTime_With_Reloads
+FROM radacct a
+LEFT OUTER JOIN nasreload n USING (nasipaddress);
+
+
+--
+-- It may be desirable to periodically "close" radacct sessions belonging to a
+-- reloaded NAS, replicating the "bulk close" Accounting-On/Off behaviour,
+-- just not in real time.
+--
+-- The fr_radacct_close_after_reload SP will set radacct.acctstoptime to
+-- nasreload.reloadtime, calculate the corresponding radacct.acctsessiontime,
+-- and set acctterminatecause to "NAS reboot" for interrupted sessions. It
+-- does so in batches, which avoids long-lived locks on the affected rows.
+--
+-- It can be invoked as follows:
+--
+-- CALL fr_radacct_close_after_reload();
+--
+-- Note: This SP requires PostgreSQL >= 11 which was the first version to
+-- introduce PROCEDUREs which permit transaction control. This allows COMMIT
+-- to be called to incrementally apply successive batch updates prior to the
+-- end of the procedure. Prior to version 11 there exists only FUNCTIONs that
+-- execute atomically. You can convert this procedure to a function, but by
+-- doing so you are really no better off than performing a single,
+-- long-running bulk update.
+--
+-- Note: This SP walks radacct in strides of v_batch_size. It will typically
+-- skip closed and ongoing sessions at a rate significantly faster than
+-- 500,000 rows per second and process batched updates faster than 25,000
+-- orphaned sessions per second. If this isn't fast enough then you should
+-- really consider using a custom schema that includes partitioning by
+-- nasipaddress or acct{start,stop}time.
+--
+CREATE OR REPLACE PROCEDURE fr_radacct_close_after_reload ()
+LANGUAGE plpgsql
+AS $$
+
+DECLARE v_a bigint;
+DECLARE v_z bigint;
+DECLARE v_updated bigint DEFAULT 0;
+DECLARE v_last_report bigint DEFAULT 0;
+DECLARE v_now bigint;
+DECLARE v_last boolean DEFAULT false;
+DECLARE v_rowcount integer;
+
+--
+-- This works for many circumstances
+--
+DECLARE v_batch_size CONSTANT integer := 2500;
+
+BEGIN
+
+ SELECT MIN(RadAcctId) INTO v_a FROM radacct WHERE AcctStopTime IS NULL;
+
+ LOOP
+
+ v_z := NULL;
+ SELECT RadAcctId INTO v_z FROM radacct WHERE RadAcctId > v_a ORDER BY RadAcctId OFFSET v_batch_size LIMIT 1;
+
+ IF v_z IS NULL THEN
+ SELECT MAX(RadAcctId) INTO v_z FROM radacct;
+ v_last := true;
+ END IF;
+
+ UPDATE radacct a
+ SET
+ AcctStopTime = n.reloadtime,
+ AcctSessionTime = EXTRACT(EPOCH FROM (n.ReloadTime - a.AcctStartTime)),
+ AcctTerminateCause = 'NAS reboot'
+ FROM nasreload n
+ WHERE
+ a.NASIPAddress = n.NASIPAddress
+ AND RadAcctId BETWEEN v_a AND v_z
+ AND AcctStopTime IS NULL
+ AND AcctStartTime < n.ReloadTime;
+
+ GET DIAGNOSTICS v_rowcount := ROW_COUNT;
+ v_updated := v_updated + v_rowcount;
+
+ COMMIT; -- Make the update visible
+
+ v_a := v_z + 1;
+
+ --
+ -- Periodically report how far we've got
+ --
+ SELECT EXTRACT(EPOCH FROM CURRENT_TIMESTAMP) INTO v_now;
+ IF v_last_report != v_now OR v_last THEN
+ RAISE NOTICE 'RadAcctID: %; Sessions closed: %', v_z, v_updated;
+ v_last_report := v_now;
+ END IF;
+
+ EXIT WHEN v_last;
+
+ END LOOP;
+
+END
+$$;
+
diff --git a/raddb/mods-config/sql/main/postgresql/queries.conf b/raddb/mods-config/sql/main/postgresql/queries.conf
new file mode 100644
index 0000000..18a1ed0
--- /dev/null
+++ b/raddb/mods-config/sql/main/postgresql/queries.conf
@@ -0,0 +1,742 @@
+# -*- text -*-
+#
+# main/postgresql/queries.conf -- PostgreSQL configuration for default schema (schema.sql)
+#
+# $Id$
+
+# Use the driver specific SQL escape method.
+#
+# If you enable this configuration item, the "safe_characters"
+# configuration is ignored. FreeRADIUS then uses the PostgreSQL escape
+# functions to escape input strings. The only downside to making this
+# change is that the PostgreSQL escaping method is not the same the one
+# used by FreeRADIUS. So characters which are NOT in the
+# "safe_characters" list will now be stored differently in the database.
+#
+#auto_escape = yes
+
+# Safe characters list for sql queries. Everything else is replaced
+# with their mime-encoded equivalents.
+# The default list should be ok
+# Using 'auto_escape' is preferred
+# safe_characters = "@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_: /"
+
+#######################################################################
+# Query config: Username
+#######################################################################
+# This is the username that will get substituted, escaped, and added
+# as attribute 'SQL-User-Name'. '%{SQL-User-Name}' should be used
+# below everywhere a username substitution is needed so you you can
+# be sure the username passed from the client is escaped properly.
+#
+# Uncomment the next line, if you want the sql_user_name to mean:
+#
+# Use Stripped-User-Name, if it's there.
+# Else use User-Name, if it's there,
+# Else use hard-coded string "none" as the user name.
+#
+#sql_user_name = "%{%{Stripped-User-Name}:-%{%{User-Name}:-none}}"
+
+sql_user_name = "%{User-Name}"
+
+#######################################################################
+# Query config: Event-Timestamp
+#######################################################################
+# event_timestamp_epoch is the basis for the time inserted into
+# accounting records. Typically this will be the Event-Timestamp of the
+# accounting request, which is usually provided by a NAS.
+#
+# Uncomment the next line, if you want the timestamp to be based on the
+# request reception time recorded by this server, for example if you
+# distrust the provided Event-Timestamp.
+#event_timestamp_epoch = "%l"
+
+event_timestamp_epoch = "%{%{integer:Event-Timestamp}:-%l}"
+
+# event_timestamp is the SQL snippet for converting an epoch timestamp
+# to an SQL date.
+
+event_timestamp = "TO_TIMESTAMP(${event_timestamp_epoch})"
+
+#######################################################################
+# Query config: Class attribute
+#######################################################################
+#
+# 3.0.22 and later have a "class" column in the accounting table.
+#
+# However, we do NOT want to break existing configurations by adding
+# the Class attribute to the default queries. If we did that, then
+# systems using newer versions of the server would fail, because
+# there is no "class" column in their accounting tables.
+#
+# The solution to that is the following "class" subsection. If your
+# database has a "class" column for the various tables, then you can
+# uncomment the configuration items here. The queries below will
+# then automatically insert the Class attribute into radacct,
+# radpostauth, etc.
+#
+class {
+ #
+ # Delete the '#' character from each of the configuration
+ # items in this section. This change puts the Class
+ # attribute into the various tables. Leave the double-quoted
+ # string there, as the value for the configuration item.
+ #
+ # See also policy.d/accounting, and the "insert_acct_class"
+ # policy. You will need to list (or uncomment)
+ # "insert_acct_class" in the "post-auth" section in order to
+ # create a Class attribute.
+ #
+ column_name = # ", Class"
+ packet_xlat = # ", '%{Class}'"
+ reply_xlat = # ", '%{reply:Class}'"
+}
+
+#######################################################################
+# Default profile
+#######################################################################
+# This is the default profile. It is found in SQL by group membership.
+# That means that this profile must be a member of at least one group
+# which will contain the corresponding check and reply items.
+# This profile will be queried in the authorize section for every user.
+# The point is to assign all users a default profile without having to
+# manually add each one to a group that will contain the profile.
+# The SQL module will also honor the User-Profile attribute. This
+# attribute can be set anywhere in the authorize section (ie the users
+# file). It is found exactly as the default profile is found.
+# If it is set then it will *overwrite* the default profile setting.
+# The idea is to select profiles based on checks on the incoming
+# packets, not on user group membership. For example:
+# -- users file --
+# DEFAULT Service-Type == Outbound-User, User-Profile := "outbound"
+# DEFAULT Service-Type == Framed-User, User-Profile := "framed"
+#
+# By default the default_user_profile is not set
+#
+# default_user_profile = "DEFAULT"
+
+#######################################################################
+# Open Query
+#######################################################################
+# This query is run whenever a new connection is opened.
+# It is commented out by default.
+#
+# If you have issues with connections hanging for too long, uncomment
+# the next line, and set the timeout in milliseconds. As a general
+# rule, if the queries take longer than a second, something is wrong
+# with the database.
+#open_query = "set statement_timeout to 1000"
+
+#######################################################################
+# NAS Query
+#######################################################################
+# This query retrieves the radius clients
+#
+# 0. Row ID (currently unused)
+# 1. Name (or IP address)
+# 2. Shortname
+# 3. Type
+# 4. Secret
+# 5. Server
+#######################################################################
+
+client_query = "\
+ SELECT id, nasname, shortname, type, secret, server \
+ FROM ${client_table}"
+
+#######################################################################
+# Authorization Queries
+#######################################################################
+# These queries compare the check items for the user
+# in ${authcheck_table} and setup the reply items in
+# ${authreply_table}. You can use any query/tables
+# you want, but the return data for each row MUST
+# be in the following order:
+#
+# 0. Row ID (currently unused)
+# 1. UserName/GroupName
+# 2. Item Attr Name
+# 3. Item Attr Value
+# 4. Item Attr Operation
+#######################################################################
+
+#
+# Use these for case insensitive usernames. WARNING: Slower queries!
+#
+#authorize_check_query = "\
+# SELECT id, UserName, Attribute, Value, Op \
+# FROM ${authcheck_table} \
+# WHERE LOWER(UserName) = LOWER('%{SQL-User-Name}') \
+# ORDER BY id"
+
+#authorize_reply_query = "\
+# SELECT id, UserName, Attribute, Value, Op \
+# FROM ${authreply_table} \
+# WHERE LOWER(UserName) = LOWER('%{SQL-User-Name}') \
+# ORDER BY id"
+
+authorize_check_query = "\
+ SELECT id, UserName, Attribute, Value, Op \
+ FROM ${authcheck_table} \
+ WHERE Username = '%{SQL-User-Name}' \
+ ORDER BY id"
+
+authorize_reply_query = "\
+ SELECT id, UserName, Attribute, Value, Op \
+ FROM ${authreply_table} \
+ WHERE Username = '%{SQL-User-Name}' \
+ ORDER BY id"
+
+#
+# Use these for case insensitive usernames. WARNING: Slower queries!
+#
+#authorize_group_check_query = "\
+# SELECT \
+# ${groupcheck_table}.id, ${groupcheck_table}.GroupName, ${groupcheck_table}.Attribute, \
+# ${groupcheck_table}.Value, ${groupcheck_table}.Op \
+# FROM ${groupcheck_table}, ${usergroup_table} \
+# WHERE LOWER(${usergroup_table}.UserName) = LOWER('%{SQL-User-Name}') \
+# AND ${usergroup_table}.GroupName = ${groupcheck_table}.GroupName \
+# ORDER BY ${groupcheck_table}.id"
+
+#authorize_group_reply_query = "\
+# SELECT \
+# ${groupreply_table}.id, ${groupreply_table}.GroupName, \
+# ${groupreply_table}.Attribute, ${groupreply_table}.Value, ${groupreply_table}.Op \
+# FROM ${groupreply_table}, ${usergroup_table} \
+# WHERE LOWER(${usergroup_table}.UserName) = LOWER('%{SQL-User-Name}') \
+# AND ${usergroup_table}.GroupName = ${groupreply_table}.GroupName \
+# ORDER BY ${groupreply_table}.id"
+
+authorize_group_check_query = "\
+ SELECT id, GroupName, Attribute, Value, op \
+ FROM ${groupcheck_table} \
+ WHERE GroupName = '%{${group_attribute}}' \
+ ORDER BY id"
+
+authorize_group_reply_query = "\
+ SELECT id, GroupName, Attribute, Value, op \
+ FROM ${groupreply_table} \
+ WHERE GroupName = '%{${group_attribute}}' \
+ ORDER BY id"
+
+#######################################################################
+# Simultaneous Use Checking Queries
+#######################################################################
+# simul_count_query - query for the number of current connections
+# - If this is not defined, no simultaneous use checking
+# - will be performed by this module instance
+# simul_verify_query - query to return details of current connections for verification
+# - Leave blank or commented out to disable verification step
+# - Note that the returned field order should not be changed.
+#######################################################################
+
+simul_count_query = "\
+ SELECT COUNT(RadAcctId) \
+ FROM ${acct_table1} a \
+ LEFT OUTER JOIN nasreload n USING (NASIPAddress) \
+ WHERE UserName='%{SQL-User-Name}' \
+ AND AcctStopTime IS NULL \
+ AND (a.AcctStartTime > n.ReloadTime OR n.ReloadTime IS NULL)"
+
+simul_verify_query = "\
+ SELECT RadAcctId, AcctSessionId, UserName, NASIPAddress, NASPortId, FramedIPAddress, CallingStationId, \
+ FramedProtocol \
+ FROM ${acct_table1} a \
+ LEFT OUTER JOIN nasreload n USING (nasipaddress) \
+ WHERE UserName='%{SQL-User-Name}' \
+ AND AcctStopTime IS NULL \
+ AND (a.AcctStartTime > n.reloadtime OR n.reloadtime IS NULL)"
+
+#######################################################################
+# Group Membership Queries
+#######################################################################
+# group_membership_query - Check user group membership
+#######################################################################
+
+# Use these for case insensitive usernames. WARNING: Slower queries!
+#group_membership_query = "\
+# SELECT GroupName \
+# FROM ${usergroup_table} \
+# WHERE LOWER(UserName) = LOWER('%{SQL-User-Name}') \
+# ORDER BY priority"
+
+group_membership_query = "\
+ SELECT GroupName \
+ FROM ${usergroup_table} \
+ WHERE UserName='%{SQL-User-Name}' \
+ ORDER BY priority"
+
+#######################################################################
+# Accounting and Post-Auth Queries
+#######################################################################
+# These queries insert/update accounting and authentication records.
+# The query to use is determined by the value of 'reference'.
+# This value is used as a configuration path and should resolve to one
+# or more 'query's. If reference points to multiple queries, and a query
+# fails, the next query is executed.
+#
+# Behaviour is identical to the old 1.x/2.x module, except we can now
+# fail between N queries, and query selection can be based on any
+# combination of attributes, or custom 'Acct-Status-Type' values.
+#######################################################################
+
+accounting {
+ reference = "%{tolower:type.%{%{Acct-Status-Type}:-%{Request-Processing-Stage}}.query}"
+
+ # Write SQL queries to a logfile. This is potentially useful for bulk inserts
+ # when used with the rlm_sql_null driver.
+# logfile = ${logdir}/accounting.sql
+
+ column_list = "\
+ AcctSessionId, \
+ AcctUniqueId, \
+ UserName, \
+ Realm, \
+ NASIPAddress, \
+ NASPortId, \
+ NASPortType, \
+ AcctStartTime, \
+ AcctUpdateTime, \
+ AcctStopTime, \
+ AcctSessionTime, \
+ AcctAuthentic, \
+ ConnectInfo_start, \
+ ConnectInfo_Stop, \
+ AcctInputOctets, \
+ AcctOutputOctets, \
+ CalledStationId, \
+ CallingStationId, \
+ AcctTerminateCause, \
+ ServiceType, \
+ FramedProtocol, \
+ FramedIpAddress, \
+ FramedIpv6Address, \
+ FramedIpv6Prefix, \
+ FramedInterfaceId, \
+ DelegatedIpv6Prefix \
+ ${..class.column_name}"
+
+ type {
+
+ accounting-on {
+
+ #
+ # "Bulk update" Accounting-On/Off strategy.
+ #
+ # Immediately terminate all sessions associated with a
+ # given NAS.
+ #
+ # Note: If a large number of sessions require closing
+ # then the bulk update may be take a long time to run
+ # and lock an excessive number of rows. See the
+ # strategy below for an alternative approach that does
+ # not touch the radacct session data.
+ #
+ query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ AcctStopTime = ${....event_timestamp}, \
+ AcctUpdateTime = ${....event_timestamp}, \
+ AcctSessionTime = (${....event_timestamp_epoch} - EXTRACT(EPOCH FROM(AcctStartTime))), \
+ AcctTerminateCause = '%{%{Acct-Terminate-Cause}:-NAS-Reboot}' \
+ WHERE AcctStopTime IS NULL \
+ AND NASIPAddress= '%{%{NAS-IPv6-Address}:-%{NAS-IP-Address}}' \
+ AND AcctStartTime <= ${....event_timestamp}"
+
+ #
+ # "Lightweight" Accounting-On/Off strategy.
+ #
+ # Record the reload time of the NAS and let the
+ # administrator actually close the sessions in radacct
+ # out-of-band, if desired.
+ #
+ # Implementation advice, together with a stored
+ # procedure for closing sessions and a view showing
+ # the effective stop time of each session is provided
+ # in process-radacct.sql.
+ #
+ # To enable this strategy, just change the previous
+ # query to "-query", and this one to "query". The
+ # previous one will be ignored, and this one will be
+ # enabled.
+ #
+ -query = "\
+ INSERT INTO nasreload (NASIPAddress, ReloadTime) \
+ VALUES ('%{NAS-IP-Address}', ${....event_timestamp}) \
+ ON CONFLICT ON (NASIPAddress) \
+ DO UPDATE SET \
+ ReloadTime = ${....event_timestamp}"
+
+ }
+
+ accounting-off {
+ query = "${..accounting-on.query}"
+ }
+
+ #
+ # Implement the "sql_session_start" policy.
+ # See raddb/policy.d/accounting for more details.
+ #
+ # You also need to fix the other queries as
+ # documented below. Look for "sql_session_start".
+ #
+ post-auth {
+ query = "\
+ INSERT INTO ${....acct_table1} \
+ (${...column_list}) \
+ VALUES(\
+ '%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ NULLIF('%{Realm}', ''), \
+ '%{%{NAS-IPv6-Address}:-%{NAS-IP-Address}}', \
+ NULLIF('%{%{NAS-Port-ID}:-%{NAS-Port}}', ''), \
+ '%{NAS-Port-Type}', \
+ ${....event_timestamp}, \
+ ${....event_timestamp}, \
+ NULL, \
+ 0, \
+ '', \
+ '%{Connect-Info}', \
+ NULL, \
+ 0, \
+ 0, \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ NULL, \
+ '%{Service-Type}', \
+ '', \
+ NULL, \
+ NULL, \
+ NULL, \
+ NULL, \
+ NULL \
+ ${....class.reply_xlat})"
+
+ query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ AcctStartTime = ${....event_timestamp}, \
+ AcctUpdateTime = ${....event_timestamp}, \
+ ConnectInfo_start = '%{Connect-Info}', \
+ AcctSessionId = '%{Acct-Session-Id}' \
+ WHERE AcctUniqueId = '%{Acct-Unique-Session-Id}' \
+ AND AcctStopTime IS NULL"
+ }
+
+ start {
+ query = "\
+ INSERT INTO ${....acct_table1} \
+ (${...column_list}) \
+ VALUES(\
+ '%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ NULLIF('%{Realm}', ''), \
+ '%{%{NAS-IPv6-Address}:-%{NAS-IP-Address}}', \
+ NULLIF('%{%{NAS-Port-ID}:-%{NAS-Port}}', ''), \
+ '%{NAS-Port-Type}', \
+ ${....event_timestamp}, \
+ ${....event_timestamp}, \
+ NULL, \
+ 0, \
+ '%{Acct-Authentic}', \
+ '%{Connect-Info}', \
+ NULL, \
+ 0, \
+ 0, \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ NULL, \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ NULLIF('%{Framed-IP-Address}', '')::inet, \
+ NULLIF('%{Framed-IPv6-Address}', '')::inet, \
+ NULLIF('%{Framed-IPv6-Prefix}', '')::inet, \
+ NULLIF('%{Framed-Interface-Id}', ''), \
+ NULLIF('%{Delegated-IPv6-Prefix}', '')::inet \
+ ${....class.packet_xlat} ) \
+ ON CONFLICT (AcctUniqueId) \
+ DO UPDATE \
+ SET \
+ AcctStartTime = ${....event_timestamp}, \
+ AcctUpdateTime = ${....event_timestamp}, \
+ ConnectInfo_start = '%{Connect-Info}' \
+ WHERE ${....acct_table1}.AcctUniqueId = '%{Acct-Unique-Session-Id}' \
+ AND ${....acct_table1}.AcctStopTime IS NULL"
+
+ #
+ # When using "sql_session_start", you should comment out
+ # the previous query, and enable this one.
+ #
+ # Just change the previous query to "-query",
+ # and this one to "query". The previous one
+ # will be ignored, and this one will be
+ # enabled.
+ #
+ -query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ AcctSessionId = '%{Acct-Session-Id}', \
+ AcctUniqueId = '%{Acct-Unique-Session-Id}', \
+ AcctAuthentic = '%{Acct-Authentic}', \
+ ConnectInfo_start = '%{Connect-Info}', \
+ ServiceType = '%{Service-Type}', \
+ FramedProtocol = '%{Framed-Protocol}', \
+ FramedIPAddress = NULLIF('%{Framed-IP-Address}', '')::inet, \
+ FramedIPv6Address = NULLIF('%{Framed-IPv6-Address}', '')::inet, \
+ FramedIPv6Prefix = NULLIF('%{Framed-IPv6-Prefix}', '')::inet, \
+ FramedInterfaceId = NULLIF('%{Framed-Interface-Id}', ''), \
+ DelegatedIPv6Prefix = NULLIF('%{Delegated-IPv6-Prefix}', '')::inet, \
+ AcctStartTime = ${....event_timestamp}, \
+ AcctUpdateTime = ${....event_timestamp} \
+ WHERE AcctUniqueId = '%{Acct-Unique-Session-Id}' \
+ AND AcctStopTime IS NULL"
+
+ # and again where we don't have "AND AcctStopTime IS NULL"
+ query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ AcctStartTime = ${....event_timestamp}, \
+ AcctUpdateTime = ${....event_timestamp}, \
+ ConnectInfo_start = '%{Connect-Info}' \
+ WHERE AcctUniqueId = '%{Acct-Unique-Session-Id}'"
+ }
+
+ interim-update {
+ query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ FramedIPAddress = NULLIF('%{Framed-IP-Address}', '')::inet, \
+ FramedIPv6Address = NULLIF('%{Framed-IPv6-Address}', '')::inet, \
+ FramedIPv6Prefix = NULLIF('%{Framed-IPv6-Prefix}', '')::inet, \
+ FramedInterfaceId = NULLIF('%{Framed-Interface-Id}', ''), \
+ DelegatedIPv6Prefix = NULLIF('%{Delegated-IPv6-Prefix}', '')::inet, \
+ AcctSessionTime = %{%{Acct-Session-Time}:-NULL}, \
+ AcctInterval = (${....event_timestamp_epoch} - EXTRACT(EPOCH FROM (COALESCE(AcctUpdateTime, AcctStartTime)))), \
+ AcctUpdateTime = ${....event_timestamp}, \
+ AcctInputOctets = (('%{%{Acct-Input-Gigawords}:-0}'::bigint << 32) + \
+ '%{%{Acct-Input-Octets}:-0}'::bigint), \
+ AcctOutputOctets = (('%{%{Acct-Output-Gigawords}:-0}'::bigint << 32) + \
+ '%{%{Acct-Output-Octets}:-0}'::bigint) \
+ WHERE AcctUniqueId = '%{Acct-Unique-Session-Id}' \
+ AND AcctStopTime IS NULL"
+
+ query = "\
+ INSERT INTO ${....acct_table1} \
+ (${...column_list}) \
+ VALUES(\
+ '%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ NULLIF('%{Realm}', ''), \
+ '%{%{NAS-IPv6-Address}:-%{NAS-IP-Address}}', \
+ NULLIF('%{%{NAS-Port-ID}:-%{NAS-Port}}', ''), \
+ '%{NAS-Port-Type}', \
+ ${....event_timestamp}, \
+ ${....event_timestamp}, \
+ NULL, \
+ %{%{Acct-Session-Time}:-NULL}, \
+ '%{Acct-Authentic}', \
+ '%{Connect-Info}', \
+ NULL, \
+ (('%{%{Acct-Input-Gigawords}:-0}'::bigint << 32) + \
+ '%{%{Acct-Input-Octets}:-0}'::bigint), \
+ (('%{%{Acct-Output-Gigawords}:-0}'::bigint << 32) + \
+ '%{%{Acct-Output-Octets}:-0}'::bigint), \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ NULL, \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ NULLIF('%{Framed-IP-Address}', '')::inet, \
+ NULLIF('%{Framed-IPv6-Address}', '')::inet, \
+ NULLIF('%{Framed-IPv6-Prefix}', '')::inet, \
+ NULLIF('%{Framed-Interface-Id}', ''), \
+ NULLIF('%{Delegated-IPv6-Prefix}', '')::inet \
+ ${....class.packet_xlat}) \
+ ON CONFLICT (AcctUniqueId) \
+ DO NOTHING"
+
+ #
+ # When using "sql_session_start", you should comment out
+ # the previous query, and enable this one.
+ #
+ # Just change the previous query to "-query",
+ # and this one to "query". The previous one
+ # will be ignored, and this one will be
+ # enabled.
+ #
+ -query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ AcctSessionId = '%{Acct-Session-Id}', \
+ AcctUniqueId = '%{Acct-Unique-Session-Id}', \
+ AcctAuthentic = '%{Acct-Authentic}', \
+ ConnectInfo_start = '%{Connect-Info}', \
+ ServiceType = '%{Service-Type}', \
+ FramedProtocol = '%{Framed-Protocol}', \
+ FramedIPAddress = NULLIF('%{Framed-IP-Address}', '')::inet, \
+ FramedIPv6Address = NULLIF('%{Framed-IPv6-Address}', '')::inet, \
+ FramedIPv6Prefix = NULLIF('%{Framed-IPv6-Prefix}', '')::inet, \
+ FramedInterfaceId = NULLIF('%{Framed-Interface-Id}', ''), \
+ DelegatedIPv6Prefix = NULLIF('%{Delegated-IPv6-Prefix}', '')::inet, \
+ AcctUpdateTime = ${....event_timestamp}, \
+ AcctSessionTime = COALESCE(%{%{Acct-Session-Time}:-NULL}, \
+ (${....event_timestamp_epoch} - EXTRACT(EPOCH FROM(AcctStartTime)))), \
+ AcctInputOctets = (('%{%{Acct-Input-Gigawords}:-0}'::bigint << 32) + \
+ '%{%{Acct-Input-Octets}:-0}'::bigint), \
+ AcctOutputOctets = (('%{%{Acct-Output-Gigawords}:-0}'::bigint << 32) + \
+ '%{%{Acct-Output-Octets}:-0}'::bigint) \
+ WHERE AcctUniqueId = '%{Acct-Unique-Session-Id}' \
+ AND AcctStopTime IS NULL"
+ }
+
+ stop {
+ query = "\
+ UPDATE ${....acct_table2} \
+ SET \
+ AcctStopTime = ${....event_timestamp}, \
+ AcctUpdateTime = ${....event_timestamp}, \
+ AcctSessionTime = COALESCE(%{%{Acct-Session-Time}:-NULL}, \
+ (${....event_timestamp_epoch} - EXTRACT(EPOCH FROM(AcctStartTime)))), \
+ AcctInputOctets = (('%{%{Acct-Input-Gigawords}:-0}'::bigint << 32) + \
+ '%{%{Acct-Input-Octets}:-0}'::bigint), \
+ AcctOutputOctets = (('%{%{Acct-Output-Gigawords}:-0}'::bigint << 32) + \
+ '%{%{Acct-Output-Octets}:-0}'::bigint), \
+ AcctTerminateCause = '%{Acct-Terminate-Cause}', \
+ FramedIPAddress = NULLIF('%{Framed-IP-Address}', '')::inet, \
+ FramedIPv6Address = NULLIF('%{Framed-IPv6-Address}', '')::inet, \
+ FramedIPv6Prefix = NULLIF('%{Framed-IPv6-Prefix}', '')::inet, \
+ FramedInterfaceId = NULLIF('%{Framed-Interface-Id}', ''), \
+ DelegatedIPv6Prefix = NULLIF('%{Delegated-IPv6-Prefix}', '')::inet, \
+ ConnectInfo_stop = '%{Connect-Info}' \
+ WHERE AcctUniqueId = '%{Acct-Unique-Session-Id}' \
+ AND AcctStopTime IS NULL"
+
+ query = "\
+ INSERT INTO ${....acct_table1} \
+ (${...column_list}) \
+ VALUES(\
+ '%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ NULLIF('%{Realm}', ''), \
+ '%{%{NAS-IPv6-Address}:-%{NAS-IP-Address}}', \
+ NULLIF('%{%{NAS-Port-ID}:-%{NAS-Port}}', ''), \
+ '%{NAS-Port-Type}', \
+ TO_TIMESTAMP(${....event_timestamp_epoch} - %{%{Acct-Session-Time}:-0}), \
+ ${....event_timestamp}, \
+ ${....event_timestamp}, \
+ NULLIF('%{Acct-Session-Time}', '')::bigint, \
+ '%{Acct-Authentic}', \
+ '%{Connect-Info}', \
+ NULL, \
+ (('%{%{Acct-Input-Gigawords}:-0}'::bigint << 32) + \
+ '%{%{Acct-Input-Octets}:-0}'::bigint), \
+ (('%{%{Acct-Output-Gigawords}:-0}'::bigint << 32) + \
+ '%{%{Acct-Output-Octets}:-0}'::bigint), \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '%{Acct-Terminate-Cause}', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ NULLIF('%{Framed-IP-Address}', '')::inet, \
+ NULLIF('%{Framed-IPv6-Address}', '')::inet, \
+ NULLIF('%{Framed-IPv6-Prefix}', '')::inet, \
+ NULLIF('%{Framed-Interface-Id}', ''), \
+ NULLIF('%{Delegated-IPv6-Prefix}', '')::inet \
+ ${....class.packet_xlat}) \
+ ON CONFLICT (AcctUniqueId) \
+ DO NOTHING"
+
+ #
+ # When using "sql_session_start", you should comment out
+ # the previous query, and enable this one.
+ #
+ # Just change the previous query to "-query",
+ # and this one to "query". The previous one
+ # will be ignored, and this one will be
+ # enabled.
+ #
+ -query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ AcctSessionId = '%{Acct-Session-Id}', \
+ AcctUniqueId = '%{Acct-Unique-Session-Id}', \
+ AcctAuthentic = '%{Acct-Authentic}', \
+ ConnectInfo_start = '%{Connect-Info}', \
+ ServiceType = '%{Service-Type}', \
+ FramedProtocol = '%{Framed-Protocol}', \
+ FramedIPAddress = NULLIF('%{Framed-IP-Address}', '')::inet, \
+ FramedIPv6Address = NULLIF('%{Framed-IPv6-Address}', '')::inet, \
+ FramedIPv6Prefix = NULLIF('%{Framed-IPv6-Prefix}', '')::inet, \
+ FramedInterfaceId = NULLIF('%{Framed-Interface-Id}', ''), \
+ DelegatedIPv6Prefix = NULLIF('%{Delegated-IPv6-Prefix}', '')::inet, \
+ AcctStopTime = ${....event_timestamp}, \
+ AcctUpdateTime = ${....event_timestamp}, \
+ AcctSessionTime = COALESCE(%{%{Acct-Session-Time}:-NULL}, \
+ (${....event_timestamp_epoch} - EXTRACT(EPOCH FROM(AcctStartTime)))), \
+ AcctInputOctets = (('%{%{Acct-Input-Gigawords}:-0}'::bigint << 32) + \
+ '%{%{Acct-Input-Octets}:-0}'::bigint), \
+ AcctOutputOctets = (('%{%{Acct-Output-Gigawords}:-0}'::bigint << 32) + \
+ '%{%{Acct-Output-Octets}:-0}'::bigint), \
+ AcctTerminateCause = '%{Acct-Terminate-Cause}', \
+ ConnectInfo_stop = '%{Connect-Info}' \
+ WHERE AcctUniqueId = '%{Acct-Unique-Session-Id}' \
+ AND AcctStopTime IS NULL"
+
+ # and again where we don't have "AND AcctStopTime IS NULL"
+ query = "\
+ UPDATE ${....acct_table2} \
+ SET \
+ AcctStopTime = ${....event_timestamp}, \
+ AcctUpdateTime = ${....event_timestamp}, \
+ AcctSessionTime = COALESCE(%{%{Acct-Session-Time}:-NULL}, \
+ (${....event_timestamp_epoch} - EXTRACT(EPOCH FROM(AcctStartTime)))), \
+ AcctInputOctets = (('%{%{Acct-Input-Gigawords}:-0}'::bigint << 32) + \
+ '%{%{Acct-Input-Octets}:-0}'::bigint), \
+ AcctOutputOctets = (('%{%{Acct-Output-Gigawords}:-0}'::bigint << 32) + \
+ '%{%{Acct-Output-Octets}:-0}'::bigint), \
+ AcctTerminateCause = '%{Acct-Terminate-Cause}', \
+ FramedIPAddress = NULLIF('%{Framed-IP-Address}', '')::inet, \
+ FramedIPv6Address = NULLIF('%{Framed-IPv6-Address}', '')::inet, \
+ FramedIPv6Prefix = NULLIF('%{Framed-IPv6-Prefix}', '')::inet, \
+ FramedInterfaceId = NULLIF('%{Framed-Interface-Id}', ''), \
+ DelegatedIPv6Prefix = NULLIF('%{Delegated-IPv6-Prefix}', '')::inet, \
+ ConnectInfo_stop = '%{Connect-Info}' \
+ WHERE AcctUniqueId = '%{Acct-Unique-Session-Id}'"
+ }
+
+ #
+ # No Acct-Status-Type == ignore the packet
+ #
+ accounting {
+ query = "SELECT true"
+ }
+ }
+}
+
+
+#######################################################################
+# Authentication Logging Queries
+#######################################################################
+# postauth_query - Insert some info after authentication
+#######################################################################
+
+post-auth {
+ # Write SQL queries to a logfile. This is potentially useful for bulk inserts
+ # when used with the rlm_sql_null driver.
+# logfile = ${logdir}/post-auth.sql
+
+ query = "\
+ INSERT INTO ${..postauth_table} \
+ (username, pass, reply, authdate ${..class.column_name}) \
+ VALUES(\
+ '%{User-Name}', \
+ '%{%{User-Password}:-%{Chap-Password}}', \
+ '%{reply:Packet-Type}', \
+ '%S.%M' \
+ ${..class.reply_xlat})"
+}
diff --git a/raddb/mods-config/sql/main/postgresql/schema.sql b/raddb/mods-config/sql/main/postgresql/schema.sql
new file mode 100644
index 0000000..518bc5d
--- /dev/null
+++ b/raddb/mods-config/sql/main/postgresql/schema.sql
@@ -0,0 +1,178 @@
+/*
+ * $Id$
+ *
+ * PostgreSQL schema for FreeRADIUS
+ *
+ */
+
+/*
+ * Table structure for table 'radacct'
+ *
+ */
+CREATE TABLE IF NOT EXISTS radacct (
+ RadAcctId bigserial PRIMARY KEY,
+ AcctSessionId text NOT NULL,
+ AcctUniqueId text NOT NULL UNIQUE,
+ UserName 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,
+ FramedIPv6Address inet,
+ FramedIPv6Prefix inet,
+ FramedInterfaceId text,
+ DelegatedIPv6Prefix inet,
+ Class text
+);
+-- 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);
+
+-- and for Class
+CREATE INDEX radacct_calss_idx ON radacct (Class);
+
+
+/*
+ * Table structure for table 'radcheck'
+ */
+CREATE TABLE IF NOT EXISTS 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 IF NOT EXISTS 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 IF NOT EXISTS 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 IF NOT EXISTS 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 IF NOT EXISTS 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 IF NOT EXISTS 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(),
+ Class text
+);
+CREATE INDEX radpostauth_username_idx ON radpostauth (username);
+CREATE INDEX radpostauth_class_idx ON radpostauth (Class);
+
+/*
+ * Table structure for table 'nas'
+ */
+CREATE TABLE IF NOT EXISTS 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);
+
+/*
+ * Table structure for table 'nasreload'
+ */
+CREATE TABLE IF NOT EXISTS nasreload (
+ NASIPAddress inet PRIMARY KEY,
+ ReloadTime timestamp with time zone NOT NULL
+);
diff --git a/raddb/mods-config/sql/main/postgresql/setup.sql b/raddb/mods-config/sql/main/postgresql/setup.sql
new file mode 100644
index 0000000..def5531
--- /dev/null
+++ b/raddb/mods-config/sql/main/postgresql/setup.sql
@@ -0,0 +1,58 @@
+/*
+ * setup.sql -- PostgreSQL commands for creating the RADIUS user.
+ *
+ * WARNING: You should change 'localhost' and 'radpass'
+ * to something else. Also update raddb/mods-available/sql
+ * with the new RADIUS password.
+ *
+ * $Id$
+ */
+
+/*
+ * Create default administrator for RADIUS
+ *
+ */
+CREATE USER radius WITH PASSWORD 'radpass';
+
+/*
+ * The server can read the authorisation data
+ *
+ */
+GRANT SELECT ON radcheck TO radius;
+GRANT SELECT ON radreply TO radius;
+GRANT SELECT ON radusergroup TO radius;
+GRANT SELECT ON radgroupcheck TO radius;
+GRANT SELECT ON radgroupreply TO radius;
+
+/*
+ * The server can write accounting and post-auth data
+ *
+ */
+GRANT SELECT, INSERT, UPDATE on radacct TO radius;
+GRANT SELECT, INSERT, UPDATE on radpostauth TO radius;
+
+/*
+ * The server can read the NAS data
+ *
+ */
+GRANT SELECT ON nas TO radius;
+
+/*
+ * In the case of the "lightweight accounting-on/off" strategy, the server also
+ * records NAS reload times
+ *
+ */
+GRANT SELECT, INSERT, UPDATE ON nasreload TO radius;
+
+/*
+ * Grant permissions on sequences
+ *
+ */
+GRANT USAGE, SELECT ON SEQUENCE radcheck_id_seq TO radius;
+GRANT USAGE, SELECT ON SEQUENCE radreply_id_seq TO radius;
+GRANT USAGE, SELECT ON SEQUENCE radusergroup_id_seq TO radius;
+GRANT USAGE, SELECT ON SEQUENCE radgroupcheck_id_seq TO radius;
+GRANT USAGE, SELECT ON SEQUENCE radgroupreply_id_seq TO radius;
+GRANT USAGE, SELECT ON SEQUENCE radacct_radacctid_seq TO radius;
+GRANT USAGE, SELECT ON SEQUENCE radpostauth_id_seq TO radius;
+GRANT USAGE, SELECT ON SEQUENCE nas_id_seq TO radius;
diff --git a/raddb/mods-config/sql/main/sqlite/process-radacct-close-after-reload.pl b/raddb/mods-config/sql/main/sqlite/process-radacct-close-after-reload.pl
new file mode 100755
index 0000000..c43da06
--- /dev/null
+++ b/raddb/mods-config/sql/main/sqlite/process-radacct-close-after-reload.pl
@@ -0,0 +1,119 @@
+#!/usr/bin/perl -Tw
+
+#
+# main/sqlite/process-radacct-close-after_reload.pl -- Script for
+# processing radacct entries to close sessions interrupted by a NAS reload
+#
+# Requires the DBD::SQLite module: perl-DBD-SQLite (RedHat); libdbd-sqlite3-perl (Debian)
+#
+# $Id$
+#
+# It may be desirable to periodically "close" radacct sessions belonging to a
+# reloaded NAS, replicating the "bulk close" Accounting-On/Off behaviour,
+# just not in real time.
+#
+# This script will set radacct.acctstoptime to nasreload.reloadtime, calculate
+# the corresponding radacct.acctsessiontime, and set acctterminatecause to
+# "NAS reboot" for interrupted sessions. It does so in batches, which avoids a
+# single long-lived lock on the table.
+#
+# It can be invoked as follows:
+#
+# ./process-radacct-close-after-reload.pl <sqlite_db_file>
+#
+# Note: This script walks radacct in strides of v_batch_size. It will
+# typically skip closed and ongoing sessions at a rate significantly faster
+# than 10,000 rows per second and process batched updates faster than 5000
+# orphaned sessions per second. If this isn't fast enough then you should
+# really consider using a server-based database for accounting purposes.
+#
+
+use strict;
+use DBI;
+
+#
+# Fine for most purposes
+#
+my $batch_size = 2500;
+
+if ($#ARGV != 0) {
+ print "Usage: process-radacct-close-after_reload.pl SQLITE_DB_FILE\n\n";
+ exit 1;
+}
+die "The SQLite database must exist: $ARGV[0]" unless -r $ARGV[0];
+
+
+my $dbh = DBI->connect("DBI:SQLite:dbname=$ARGV[0]", '', '', { RaiseError => 1 }) or die $DBI::errstr;
+
+#
+# There is no UPDATE ... JOIN/FROM in SQLite, so we have to resort to this
+# construction # which does not provide an accurate rows updated count...
+#
+my $sth_upd = $dbh->prepare(<<'EOF');
+ UPDATE radacct
+ SET
+ acctstoptime = (
+ SELECT COALESCE(acctstoptime, CASE WHEN radacct.acctstarttime < reloadtime THEN reloadtime END)
+ FROM nasreload WHERE nasipaddress = radacct.nasipaddress
+ ),
+ acctsessiontime = (
+ SELECT COALESCE(acctsessiontime,
+ CASE WHEN radacct.acctstoptime IS NULL AND radacct.acctstarttime < reloadtime THEN
+ CAST((julianday(reloadtime) - julianday(radacct.acctstarttime)) * 86400 AS integer)
+ END)
+ FROM nasreload WHERE nasipaddress = radacct.nasipaddress
+ ),
+ acctterminatecause = (
+ SELECT
+ CASE WHEN radacct.acctstoptime IS NULL AND radacct.acctstarttime < reloadtime THEN
+ 'NAS reboot'
+ ELSE
+ acctterminatecause
+ END
+ FROM nasreload WHERE nasipaddress = radacct.nasipaddress
+ )
+ WHERE
+ radacctid BETWEEN ? AND ?
+ AND acctstoptime IS NULL
+EOF
+
+my $sth = $dbh->prepare('SELECT MIN(radacctid), MAX(radacctid) FROM radacct WHERE acctstoptime IS NULL');
+$sth->execute() or die $DBI::errstr;
+(my $a, my $m) = $sth->fetchrow_array();
+$sth->finish;
+
+my $sth_nxt = $dbh->prepare('SELECT radacctid FROM radacct WHERE radacctid > ? ORDER BY radacctid LIMIT ?,1');
+
+
+my $last = 0;
+my $last_report = 0;
+
+unless ($last) {
+
+ $sth_nxt->execute($a, $batch_size) or die $DBI::errstr;
+ (my $z) = $sth_nxt->fetchrow_array();
+
+ unless ($z) {
+ $z = $m;
+ $last = 1;
+ }
+
+ my $rc = $sth_upd->execute($a, $z) or die $DBI::errstr;
+
+ $a = $z + 1;
+
+ #
+ # Periodically report how far we've got
+ #
+ my $now = time();
+ if ($last_report != $now || $last) {
+ print "RadAcctID: $z\n";
+ $last_report = $now;
+ }
+
+}
+
+$sth_upd->finish;
+$sth_nxt->finish;
+
+$dbh->disconnect;
diff --git a/raddb/mods-config/sql/main/sqlite/process-radacct-new-data-usage-period.sh b/raddb/mods-config/sql/main/sqlite/process-radacct-new-data-usage-period.sh
new file mode 100755
index 0000000..0deb391
--- /dev/null
+++ b/raddb/mods-config/sql/main/sqlite/process-radacct-new-data-usage-period.sh
@@ -0,0 +1,124 @@
+#!/bin/sh
+#
+# main/sqlite/process-radacct-new-data-usage-period.sh -- Script for
+# processing radacct entries to extract daily usage
+#
+# $Id$
+
+#
+# See process-radacct-schema.sql for details.
+#
+
+if [ "$#" -ne 1 ]; then
+ echo "Usage: process-radacct-new-data-usage-period.sh SQLITE_DB_FILE" 2>&1
+ exit 1
+fi
+
+if [ ! -r "$1" ]; then
+ echo "The SQLite database must exist: $1" 1>&2
+ exit 1
+fi
+
+cat <<EOF | sqlite3 "$1"
+
+ --
+ -- SQLite doesn't have a concept of session variables so we fake it.
+ --
+ DROP TABLE IF EXISTS vars;
+ CREATE TEMPORARY TABLE vars (
+ key text,
+ value text,
+ PRIMARY KEY (key)
+ );
+
+ INSERT INTO vars SELECT 'v_start', COALESCE(DATETIME(MAX(period_end), '+1 seconds'), DATETIME(0, 'unixepoch')) FROM data_usage_by_period;
+ INSERT INTO vars SELECT 'v_end', CURRENT_TIMESTAMP;
+
+
+ --
+ -- Make of copy of the sessions that were active during this period to
+ -- avoid having to execute a potentially long transaction that might hold a
+ -- global database lock.
+ --
+ DROP TABLE IF EXISTS radacct_sessions;
+ CREATE TEMPORARY TABLE radacct_sessions (
+ username text,
+ acctstarttime datetime,
+ acctstoptime datetime,
+ acctinputoctets bigint,
+ acctoutputoctets bigint
+ );
+ CREATE INDEX temp.idx_radacct_sessions_username ON radacct_sessions(username);
+ CREATE INDEX temp.idx_radacct_sessions_acctstoptime ON radacct_sessions(acctstoptime);
+
+ INSERT INTO radacct_sessions
+ SELECT
+ username,
+ acctstarttime,
+ acctstoptime,
+ acctinputoctets,
+ acctoutputoctets
+ FROM
+ radacct
+ WHERE
+ acctstoptime > (SELECT value FROM vars WHERE key='v_start');
+
+ INSERT INTO radacct_sessions
+ SELECT
+ username,
+ acctstarttime,
+ acctstoptime,
+ acctinputoctets,
+ acctoutputoctets
+ FROM
+ radacct
+ WHERE
+ acctstoptime IS NULL;
+
+
+ --
+ -- Add the data usage for the sessions that were active in the current
+ -- period to the table. Include all sessions that finished since the start
+ -- of this period as well as those still ongoing.
+ --
+ INSERT INTO data_usage_by_period (username, period_start, period_end, acctinputoctets, acctoutputoctets)
+ SELECT
+ username,
+ (SELECT value FROM vars WHERE key='v_start'),
+ (SELECT value FROM vars WHERE key='v_end'),
+ SUM(acctinputoctets) AS acctinputoctets,
+ SUM(acctoutputoctets) AS acctoutputoctets
+ FROM
+ radacct_sessions
+ GROUP BY
+ username
+ ON CONFLICT(username,period_start) DO UPDATE
+ SET
+ acctinputoctets = data_usage_by_period.acctinputoctets + EXCLUDED.acctinputoctets,
+ acctoutputoctets = data_usage_by_period.acctoutputoctets + EXCLUDED.acctoutputoctets,
+ period_end = (SELECT value FROM vars WHERE key='v_end');
+
+ --
+ -- Create an open-ended "next period" for all ongoing sessions and carry a
+ -- negative value of their data usage to avoid double-accounting when we
+ -- process the next period. Their current data usage has already been
+ -- allocated to the current and possibly previous periods.
+ --
+ INSERT INTO data_usage_by_period (username, period_start, period_end, acctinputoctets, acctoutputoctets)
+ SELECT
+ username,
+ (SELECT DATETIME(value, '+1 seconds') FROM vars WHERE key='v_end'),
+ NULL,
+ 0 - SUM(acctinputoctets),
+ 0 - SUM(acctoutputoctets)
+ FROM
+ radacct_sessions
+ WHERE
+ acctstoptime IS NULL
+ GROUP BY
+ username;
+
+ DROP TABLE vars;
+ DROP TABLE radacct_sessions;
+
+EOF
diff --git a/raddb/mods-config/sql/main/sqlite/process-radacct-schema.sql b/raddb/mods-config/sql/main/sqlite/process-radacct-schema.sql
new file mode 100644
index 0000000..b429d4c
--- /dev/null
+++ b/raddb/mods-config/sql/main/sqlite/process-radacct-schema.sql
@@ -0,0 +1,95 @@
+# -*- text -*-
+#
+# main/sqlite/process-radacct.sql -- Schema extensions for processing radacct entries
+#
+# $Id$
+
+-- ---------------------------------
+-- - Per-user data usage over time -
+-- ---------------------------------
+--
+-- An extension to the standard schema to hold per-user data usage statistics
+-- for arbitrary periods.
+--
+-- The data_usage_by_period table is populated by periodically calling the
+-- process-radacct-new-data-usage-period.sh script.
+--
+-- This table can be queried in various ways to produce reports of aggregate
+-- data use over time. For example, if the refresh script is invoked once per
+-- day just after midnight, to produce usage data with daily granularity, then
+-- a reasonably accurate monthly bandwidth summary for a given user could be
+-- obtained by queriing this table with:
+--
+-- SELECT
+-- STRFTIME('%Y-%m',CURRENT_TIMESTAMP) AS month,
+-- SUM(acctinputoctets)*1.0/1000/1000/1000 AS gb_in,
+-- SUM(acctoutputoctets)*1.0/1000/1000/1000 AS gb_out
+-- FROM
+-- data_usage_by_period
+-- WHERE
+-- username='bob' AND
+-- period_end IS NOT NULL
+-- GROUP BY
+-- month;
+--
+-- 2019-07|5.782279231|50.545664824
+-- 2019-08|4.230543344|48.523096424
+-- 2019-09|4.847360599|48.631835488
+-- 2019-10|6.456763254|51.686231937
+-- 2019-11|6.362537735|52.385710572
+-- 2019-12|4.301524442|50.762240277
+-- 2020-01|5.436280545|49.067775286
+--
+CREATE TABLE data_usage_by_period (
+ username text,
+ period_start datetime,
+ period_end datetime,
+ acctinputoctets bigint,
+ acctoutputoctets bigint,
+ PRIMARY KEY (username, period_start)
+);
+CREATE INDEX idx_data_usage_by_period_period_start ON data_usage_by_period(period_start);
+CREATE INDEX idx_data_usage_by_period_period_end ON data_usage_by_period(period_end);
+
+
+-- ------------------------------------------------------
+-- - "Lightweight" Accounting-On/Off strategy resources -
+-- ------------------------------------------------------
+--
+-- The following resources are for use only when the "lightweight"
+-- Accounting-On/Off strategy is enabled in queries.conf.
+--
+-- Instead of bulk closing the radacct sessions belonging to a reloaded NAS,
+-- this strategy leaves them open and records the NAS reload time in the
+-- nasreload table.
+--
+-- Where applicable, the onus is on the administator to:
+--
+-- * Consider the nas reload times when deriving a list of
+-- active/inactive sessions, and when determining the duration of sessions
+-- interrupted by a NAS reload. (Refer to the view below.)
+--
+-- * Close the affected sessions out of band. (Refer to the
+-- process-radacct-close-after_reload.pl script.)
+--
+-- The radacct_with_reloads view presents the radacct table with two additional
+-- columns: acctstoptime_with_reloads and acctsessiontime_with_reloads
+--
+-- Where the session isn't closed (acctstoptime IS NULL), yet it started before
+-- the last reload of the NAS (radacct.acctstarttime < nasreload.reloadtime),
+-- the derived columns are set based on the reload time of the NAS (effectively
+-- the point in time that the session was interrupted.)
+--
+CREATE VIEW radacct_with_reloads AS
+SELECT
+ a.*,
+ COALESCE(a.AcctStopTime,
+ CASE WHEN a.AcctStartTime < n.ReloadTime THEN n.ReloadTime END
+ ) AS AcctStopTime_With_Reloads,
+ COALESCE(a.AcctSessionTime,
+ CASE WHEN a.AcctStopTime IS NULL AND a.AcctStartTime < n.ReloadTime THEN
+ CAST((julianday(n.ReloadTime) - julianday(a.AcctStartTime)) * 86400 AS integer)
+ END
+ ) AS AcctSessionTime_With_Reloads
+FROM radacct a
+LEFT OUTER JOIN nasreload n USING (nasipaddress);
diff --git a/raddb/mods-config/sql/main/sqlite/queries.conf b/raddb/mods-config/sql/main/sqlite/queries.conf
new file mode 100644
index 0000000..35016f4
--- /dev/null
+++ b/raddb/mods-config/sql/main/sqlite/queries.conf
@@ -0,0 +1,635 @@
+# -*- text -*-
+#
+# main/sqlite/queries.conf -- SQLite configuration for default schema (schema.sql)
+#
+# Id: e1e83bf94814ed8be6239977b7bacfed21c0cd6a $
+
+# Safe characters list for sql queries. Everything else is replaced
+# with their mime-encoded equivalents.
+# The default list should be ok
+#safe_characters = "@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_: /"
+
+#######################################################################
+# Query config: Username
+#######################################################################
+# This is the username that will get substituted, escaped, and added
+# as attribute 'SQL-User-Name'. '%{SQL-User-Name}' should be used below
+# everywhere a username substitution is needed so you you can be sure
+# the username passed from the client is escaped properly.
+#
+# Uncomment the next line, if you want the sql_user_name to mean:
+#
+# Use Stripped-User-Name, if it's there.
+# Else use User-Name, if it's there,
+# Else use hard-coded string "DEFAULT" as the user name.
+#sql_user_name = "%{%{Stripped-User-Name}:-%{%{User-Name}:-DEFAULT}}"
+#
+sql_user_name = "%{User-Name}"
+
+#######################################################################
+# Query config: Event-Timestamp
+#######################################################################
+# event_timestamp_epoch is the basis for the time inserted into
+# accounting records. Typically this will be the Event-Timestamp of the
+# accounting request, which is usually provided by a NAS.
+#
+# Uncomment the next line, if you want the timestamp to be based on the
+# request reception time recorded by this server, for example if you
+# distrust the provided Event-Timestamp.
+#event_timestamp_epoch = "%l"
+
+event_timestamp_epoch = "%{%{integer:Event-Timestamp}:-%l}"
+
+# event_timestamp is the SQL snippet for converting an epoch timestamp
+# to an SQL date.
+
+event_timestamp = "${event_timestamp_epoch}"
+
+# NOTE: Recent SQLite versions allow proper arithmetic with dates
+# stored as strings including comparison using an index, so we keep
+# these variables differentiated in preparation for switching away from
+# integer storage.
+
+#######################################################################
+# Query config: Class attribute
+#######################################################################
+#
+# 3.0.22 and later have a "class" column in the accounting table.
+#
+# However, we do NOT want to break existing configurations by adding
+# the Class attribute to the default queries. If we did that, then
+# systems using newer versions of the server would fail, because
+# there is no "class" column in their accounting tables.
+#
+# The solution to that is the following "class" subsection. If your
+# database has a "class" column for the various tables, then you can
+# uncomment the configuration items here. The queries below will
+# then automatically insert the Class attribute into radacct,
+# radpostauth, etc.
+#
+class {
+ #
+ # Delete the '#' character from each of the configuration
+ # items in this section. This change puts the Class
+ # attribute into the various tables. Leave the double-quoted
+ # string there, as the value for the configuration item.
+ #
+ # See also policy.d/accounting, and the "insert_acct_class"
+ # policy. You will need to list (or uncomment)
+ # "insert_acct_class" in the "post-auth" section in order to
+ # create a Class attribute.
+ #
+ column_name = # ", class"
+ packet_xlat = # ", '%{Class}'"
+ reply_xlat = # ", '%{reply:Class}'"
+}
+
+#######################################################################
+# Default profile
+#######################################################################
+# This is the default profile. It is found in SQL by group membership.
+# That means that this profile must be a member of at least one group
+# which will contain the corresponding check and reply items.
+# This profile will be queried in the authorize section for every user.
+# The point is to assign all users a default profile without having to
+# manually add each one to a group that will contain the profile.
+# The SQL module will also honor the User-Profile attribute. This
+# attribute can be set anywhere in the authorize section (ie the users
+# file). It is found exactly as the default profile is found.
+# If it is set then it will *overwrite* the default profile setting.
+# The idea is to select profiles based on checks on the incoming packets,
+# not on user group membership. For example:
+# -- users file --
+# DEFAULT Service-Type == Outbound-User, User-Profile := "outbound"
+# DEFAULT Service-Type == Framed-User, User-Profile := "framed"
+#
+# By default the default_user_profile is not set
+#
+#default_user_profile = "DEFAULT"
+
+#######################################################################
+# NAS Query
+#######################################################################
+# This query retrieves the radius clients
+#
+# 0. Row ID (currently unused)
+# 1. Name (or IP address)
+# 2. Shortname
+# 3. Type
+# 4. Secret
+# 5. Server
+#######################################################################
+
+client_query = "\
+ SELECT id, nasname, shortname, type, secret, server \
+ FROM ${client_table}"
+
+#######################################################################
+# Authorization Queries
+#######################################################################
+# These queries compare the check items for the user
+# in ${authcheck_table} and setup the reply items in
+# ${authreply_table}. You can use any query/tables
+# you want, but the return data for each row MUST
+# be in the following order:
+#
+# 0. Row ID (currently unused)
+# 1. UserName/GroupName
+# 2. Item Attr Name
+# 3. Item Attr Value
+# 4. Item Attr Operation
+#######################################################################
+
+#
+# Use these for case sensitive usernames.
+#
+#authorize_check_query = "\
+# SELECT id, username, attribute, value, op \
+# FROM ${authcheck_table} \
+# WHERE username = BINARY '%{SQL-User-Name}' \
+# ORDER BY id"
+
+#authorize_reply_query = "\
+# SELECT id, username, attribute, value, op \
+# FROM ${authreply_table} \
+# WHERE username = BINARY '%{SQL-User-Name}' \
+# ORDER BY id"
+
+#
+# The default queries are case insensitive. (for compatibility with older versions of FreeRADIUS)
+#
+authorize_check_query = "\
+ SELECT id, username, attribute, value, op \
+ FROM ${authcheck_table} \
+ WHERE username = '%{SQL-User-Name}' \
+ ORDER BY id"
+
+authorize_reply_query = "\
+ SELECT id, username, attribute, value, op \
+ FROM ${authreply_table} \
+ WHERE username = '%{SQL-User-Name}' \
+ ORDER BY id"
+
+#
+# Use these for case sensitive usernames.
+#
+#group_membership_query = "\
+# SELECT groupname \
+# FROM ${usergroup_table} \
+# WHERE username = BINARY '%{SQL-User-Name}' \
+# ORDER BY priority"
+
+group_membership_query = "\
+ SELECT groupname \
+ FROM ${usergroup_table} \
+ WHERE username = '%{SQL-User-Name}' \
+ ORDER BY priority"
+
+authorize_group_check_query = "\
+ SELECT id, groupname, attribute, \
+ Value, op \
+ FROM ${groupcheck_table} \
+ WHERE groupname = '%{${group_attribute}}' \
+ ORDER BY id"
+
+authorize_group_reply_query = "\
+ SELECT id, groupname, attribute, \
+ value, op \
+ FROM ${groupreply_table} \
+ WHERE groupname = '%{${group_attribute}}' \
+ ORDER BY id"
+
+#######################################################################
+# Simultaneous Use Checking Queries
+#######################################################################
+# simul_count_query - query for the number of current connections
+# - If this is not defined, no simultaneous use checking
+# - will be performed by this module instance
+# simul_verify_query - query to return details of current connections
+# for verification
+# - Leave blank or commented out to disable verification step
+# - Note that the returned field order should not be changed.
+#######################################################################
+
+simul_count_query = "\
+ SELECT COUNT(*) \
+ FROM ${acct_table1} a \
+ LEFT OUTER JOIN nasreload n USING (nasipaddress) \
+ WHERE username = '%{SQL-User-Name}' \
+ AND acctstoptime IS NULL \
+ AND (a.acctstarttime > n.reloadtime OR n.reloadtime IS NULL)"
+
+simul_verify_query = "\
+ SELECT radacctid, acctsessionid, username, nasipaddress, nasportid, framedipaddress, \
+ callingstationid, framedprotocol \
+ FROM ${acct_table1} a \
+ LEFT OUTER JOIN nasreload n USING (nasipaddress) \
+ WHERE username = '%{${group_attribute}}' \
+ AND acctstoptime IS NULL \
+ AND (a.acctstarttime > n.reloadtime OR n.reloadtime IS NULL)"
+
+#######################################################################
+# Accounting and Post-Auth Queries
+#######################################################################
+# These queries insert/update accounting and authentication records.
+# The query to use is determined by the value of 'reference'.
+# This value is used as a configuration path and should resolve to one
+# or more 'query's. If reference points to multiple queries, and a query
+# fails, the next query is executed.
+#
+# Behaviour is identical to the old 1.x/2.x module, except we can now
+# fail between N queries, and query selection can be based on any
+# combination of attributes, or custom 'Acct-Status-Type' values.
+#######################################################################
+accounting {
+ reference = "%{tolower:type.%{%{Acct-Status-Type}:-%{Request-Processing-Stage}}.query}"
+
+ # Write SQL queries to a logfile. This is potentially useful for bulk inserts
+ # when used with the rlm_sql_null driver.
+# logfile = ${logdir}/accounting.sql
+
+ column_list = "\
+ acctsessionid, \
+ acctuniqueid, \
+ username, \
+ realm, \
+ nasipaddress, \
+ nasportid, \
+ nasporttype, \
+ acctstarttime, \
+ acctupdatetime, \
+ acctstoptime, \
+ acctsessiontime, \
+ acctauthentic, \
+ connectinfo_start, \
+ connectinfo_stop, \
+ acctinputoctets, \
+ acctoutputoctets, \
+ calledstationid, \
+ callingstationid, \
+ acctterminatecause, \
+ servicetype, \
+ framedprotocol, \
+ framedipaddress, \
+ framedipv6address, \
+ framedipv6prefix, \
+ framedinterfaceid, \
+ delegatedipv6prefix \
+ ${..class.column_name}"
+
+ type {
+ accounting-on {
+
+ #
+ # "Bulk update" Accounting-On/Off strategy.
+ #
+ # Immediately terminate all sessions associated with a
+ # given NAS.
+ #
+ # Note: If a large number of sessions require closing
+ # then the bulk update may be take a long time to run
+ # and lock an excessive number of rows. See the
+ # strategy below for an alternative approach that does
+ # not touch the radacct session data.
+ #
+ query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ acctstoptime = ${....event_timestamp}, \
+ acctsessiontime = \
+ (${....event_timestamp_epoch} \
+ - acctstarttime), \
+ acctterminatecause = '%{Acct-Terminate-Cause}' \
+ WHERE acctstoptime IS NULL \
+ AND nasipaddress = '%{NAS-IP-Address}' \
+ AND acctstarttime <= ${....event_timestamp}"
+
+ #
+ # "Lightweight" Accounting-On/Off strategy.
+ #
+ # Record the reload time of the NAS and let the
+ # administrator actually close the sessions in radacct
+ # out-of-band, if desired.
+ #
+ # Implementation advice, together with a stored
+ # procedure for closing sessions and a view showing
+ # the effective stop time of each session is provided
+ # in process-radacct.sql.
+ #
+ # To enable this strategy, just change the previous
+ # query to "-query", and this one to "query". The
+ # previous one will be ignored, and this one will be
+ # enabled.
+ #
+ -query = "\
+ INSERT OR REPLACE INTO nasreload (nasipaddress, reloadtime) \
+ VALUES ('%{NAS-IP-Address}', ${....event_timestamp})"
+
+ }
+
+ accounting-off {
+ query = "${..accounting-on.query}"
+ }
+
+ start {
+ #
+ # Insert a new record into the sessions table
+ #
+ query = "\
+ INSERT INTO ${....acct_table1} \
+ (${...column_list}) \
+ VALUES \
+ ('%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{NAS-IP-Address}', \
+ '%{%{NAS-Port-ID}:-%{NAS-Port}}', \
+ '%{NAS-Port-Type}', \
+ ${....event_timestamp}, \
+ ${....event_timestamp}, \
+ NULL, \
+ '0', \
+ '%{Acct-Authentic}', \
+ '%{Connect-Info}', \
+ '', \
+ '0', \
+ '0', \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ '%{Framed-IP-Address}', \
+ '%{Framed-IPv6-Address}', \
+ '%{Framed-IPv6-Prefix}', \
+ '%{Framed-Interface-Id}', \
+ '%{Delegated-IPv6-Prefix}' \
+ ${....class.packet_xlat})"
+
+ #
+ # When using "sql_session_start", you should comment out
+ # the previous query, and enable this one.
+ #
+ # Just change the previous query to "-query",
+ # and this one to "query". The previous one
+ # will be ignored, and this one will be
+ # enabled.
+ #
+ -query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ AcctSessionId = '%{Acct-Session-Id}', \
+ AcctUniqueId = '%{Acct-Unique-Session-Id}', \
+ AcctAuthentic = '%{Acct-Authentic}', \
+ ConnectInfo_start = '%{Connect-Info}', \
+ ServiceType = '%{Service-Type}', \
+ FramedProtocol = '%{Framed-Protocol}', \
+ framedipaddress = '%{Framed-IP-Address}', \
+ framedipv6address = '%{Framed-IPv6-Address}', \
+ framedipv6prefix = '%{Framed-IPv6-Prefix}', \
+ framedinterfaceid = '%{Framed-Interface-Id}', \
+ delegatedipv6prefix = '%{Delegated-IPv6-Prefix}', \
+ AcctStartTime = ${....event_timestamp}, \
+ AcctUpdateTime = ${....event_timestamp} \
+ WHERE UserName = '%{SQL-User-Name}' \
+ AND NASIPAddress = '%{%{NAS-IPv6-Address}:-%{NAS-IP-Address}}' \
+ AND NASPortId = '%{%{NAS-Port-ID}:-%{NAS-Port}}' \
+ AND NASPortType = '%{NAS-Port-Type}' \
+ AND AcctStopTime IS NULL"
+
+ #
+ # Key constraints prevented us from inserting a new session,
+ # use the alternate query to update an existing session.
+ #
+ query = "\
+ UPDATE ${....acct_table1} SET \
+ acctstarttime = ${....event_timestamp}, \
+ acctupdatetime = ${....event_timestamp}, \
+ connectinfo_start = '%{Connect-Info}' \
+ WHERE AcctUniqueId = '%{Acct-Unique-Session-Id}'"
+ }
+
+ interim-update {
+ #
+ # Update an existing session and calculate the interval
+ # between the last data we received for the session and this
+ # update. This can be used to find stale sessions.
+ #
+ query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ acctupdatetime = ${....event_timestamp}, \
+ acctinterval = 0, \
+ framedipaddress = '%{Framed-IP-Address}', \
+ framedipv6address = '%{Framed-IPv6-Address}', \
+ framedipv6prefix = '%{Framed-IPv6-Prefix}', \
+ framedinterfaceid = '%{Framed-Interface-Id}', \
+ delegatedipv6prefix = '%{Delegated-IPv6-Prefix}', \
+ acctsessiontime = %{%{Acct-Session-Time}:-NULL}, \
+ acctinputoctets = %{%{Acct-Input-Gigawords}:-0} \
+ << 32 | %{%{Acct-Input-Octets}:-0}, \
+ acctoutputoctets = %{%{Acct-Output-Gigawords}:-0} \
+ << 32 | %{%{Acct-Output-Octets}:-0} \
+ WHERE AcctUniqueId = '%{Acct-Unique-Session-Id}'"
+
+ #
+ # The update condition matched no existing sessions. Use
+ # the values provided in the update to create a new session.
+ #
+ query = "\
+ INSERT INTO ${....acct_table1} \
+ (${...column_list}) \
+ VALUES \
+ ('%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{NAS-IP-Address}', \
+ '%{%{NAS-Port-ID}:-%{NAS-Port}}', \
+ '%{NAS-Port-Type}', \
+ (${....event_timestamp_epoch} - %{%{Acct-Session-Time}:-0}), \
+ ${....event_timestamp}, \
+ NULL, \
+ %{%{Acct-Session-Time}:-NULL}, \
+ '%{Acct-Authentic}', \
+ '%{Connect-Info}', \
+ '', \
+ %{%{Acct-Input-Gigawords}:-0} << 32 | \
+ %{%{Acct-Input-Octets}:-0}, \
+ %{%{Acct-Output-Gigawords}:-0} << 32 | \
+ %{%{Acct-Output-Octets}:-0}, \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ '%{Framed-IP-Address}', \
+ '%{Framed-IPv6-Address}', \
+ '%{Framed-IPv6-Prefix}', \
+ '%{Framed-Interface-Id}', \
+ '%{Delegated-IPv6-Prefix}' \
+ ${....class.packet_xlat})"
+
+ #
+ # When using "sql_session_start", you should comment out
+ # the previous query, and enable this one.
+ #
+ # Just change the previous query to "-query",
+ # and this one to "query". The previous one
+ # will be ignored, and this one will be
+ # enabled.
+ #
+ -query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ AcctSessionId = '%{Acct-Session-Id}', \
+ AcctUniqueId = '%{Acct-Unique-Session-Id}', \
+ AcctAuthentic = '%{Acct-Authentic}', \
+ ConnectInfo_start = '%{Connect-Info}', \
+ ServiceType = '%{Service-Type}', \
+ FramedProtocol = '%{Framed-Protocol}', \
+ framedipaddress = '%{Framed-IP-Address}', \
+ framedipv6address = '%{Framed-IPv6-Address}', \
+ framedipv6prefix = '%{Framed-IPv6-Prefix}', \
+ framedinterfaceid = '%{Framed-Interface-Id}', \
+ delegatedipv6prefix = '%{Delegated-IPv6-Prefix}', \
+ AcctUpdateTime = ${....event_timestamp}, \
+ AcctSessionTime = %{%{Acct-Session-Time}:-NULL}, \
+ AcctInputOctets = '%{%{Acct-Input-Gigawords}:-0}' \
+ << 32 | '%{%{Acct-Input-Octets}:-0}', \
+ AcctOutputOctets = '%{%{Acct-Output-Gigawords}:-0}' \
+ << 32 | '%{%{Acct-Output-Octets}:-0}' \
+ WHERE UserName = '%{SQL-User-Name}' \
+ AND NASIPAddress = '%{%{NAS-IPv6-Address}:-%{NAS-IP-Address}}' \
+ AND NASPortId = '%{%{NAS-Port-ID}:-%{NAS-Port}}' \
+ AND NASPortType = '%{NAS-Port-Type}' \
+ AND AcctStopTime IS NULL"
+
+ }
+
+ stop {
+ #
+ # Session has terminated, update the stop time and statistics.
+ #
+ query = "\
+ UPDATE ${....acct_table2} SET \
+ acctstoptime = ${....event_timestamp}, \
+ acctsessiontime = %{%{Acct-Session-Time}:-NULL}, \
+ acctinputoctets = %{%{Acct-Input-Gigawords}:-0} \
+ << 32 | %{%{Acct-Input-Octets}:-0}, \
+ acctoutputoctets = %{%{Acct-Output-Gigawords}:-0} \
+ << 32 | %{%{Acct-Output-Octets}:-0}, \
+ acctterminatecause = '%{Acct-Terminate-Cause}', \
+ connectinfo_stop = '%{Connect-Info}' \
+ WHERE AcctUniqueId = '%{Acct-Unique-Session-Id}'"
+
+ #
+ # The update condition matched no existing sessions. Use
+ # the values provided in the update to create a new session.
+ #
+ query = "\
+ INSERT INTO ${....acct_table2} \
+ (${...column_list}) \
+ VALUES \
+ ('%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{NAS-IP-Address}', \
+ '%{%{NAS-Port-ID}:-%{NAS-Port}}', \
+ '%{NAS-Port-Type}', \
+ (${....event_timestamp_epoch} - %{%{Acct-Session-Time}:-0}), \
+ ${....event_timestamp}, \
+ ${....event_timestamp}, \
+ %{%{Acct-Session-Time}:-NULL}, \
+ '%{Acct-Authentic}', \
+ '', \
+ '%{Connect-Info}', \
+ %{%{Acct-Input-Gigawords}:-0} << 32 | \
+ %{%{Acct-Input-Octets}:-0}, \
+ %{%{Acct-Output-Gigawords}:-0} << 32 | \
+ %{%{Acct-Output-Octets}:-0}, \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '%{Acct-Terminate-Cause}', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ '%{Framed-IP-Address}', \
+ '%{Framed-IPv6-Address}', \
+ '%{Framed-IPv6-Prefix}', \
+ '%{Framed-Interface-Id}', \
+ '%{Delegated-IPv6-Prefix}' \
+ ${....class.packet_xlat})"
+
+ #
+ # When using "sql_session_start", you should comment out
+ # the previous query, and enable this one.
+ #
+ # Just change the previous query to "-query",
+ # and this one to "query". The previous one
+ # will be ignored, and this one will be
+ # enabled.
+ #
+ -query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ AcctSessionId = '%{Acct-Session-Id}', \
+ AcctUniqueId = '%{Acct-Unique-Session-Id}', \
+ AcctAuthentic = '%{Acct-Authentic}', \
+ ConnectInfo_start = '%{Connect-Info}', \
+ ServiceType = '%{Service-Type}', \
+ FramedProtocol = '%{Framed-Protocol}', \
+ framedipaddress = '%{Framed-IP-Address}', \
+ framedipv6address = '%{Framed-IPv6-Address}', \
+ framedipv6prefix = '%{Framed-IPv6-Prefix}', \
+ framedinterfaceid = '%{Framed-Interface-Id}', \
+ delegatedipv6prefix = '%{Delegated-IPv6-Prefix}', \
+ AcctStopTime = ${....event_timestamp}, \
+ AcctUpdateTime = ${....event_timestamp}, \
+ AcctSessionTime = %{%{Acct-Session-Time}:-NULL}, \
+ AcctInputOctets = '%{%{Acct-Input-Gigawords}:-0}' \
+ << 32 | '%{%{Acct-Input-Octets}:-0}', \
+ AcctOutputOctets = '%{%{Acct-Output-Gigawords}:-0}' \
+ << 32 | '%{%{Acct-Output-Octets}:-0}', \
+ AcctTerminateCause = '%{Acct-Terminate-Cause}', \
+ ConnectInfo_stop = '%{Connect-Info}' \
+ WHERE UserName = '%{SQL-User-Name}' \
+ AND NASIPAddress = '%{%{NAS-IPv6-Address}:-%{NAS-IP-Address}}' \
+ AND NASPortId = '%{%{NAS-Port-ID}:-%{NAS-Port}}' \
+ AND NASPortType = '%{NAS-Port-Type}' \
+ AND AcctStopTime IS NULL"
+
+ }
+
+
+ #
+ # No Acct-Status-Type == ignore the packet
+ #
+ accounting {
+ query = "SELECT true"
+ }
+ }
+}
+
+#######################################################################
+# Authentication Logging Queries
+#######################################################################
+# postauth_query - Insert some info after authentication
+#######################################################################
+
+post-auth {
+ # Write SQL queries to a logfile. This is potentially useful for bulk inserts
+ # when used with the rlm_sql_null driver.
+# logfile = ${logdir}/post-auth.sql
+
+ query = "\
+ INSERT INTO ${..postauth_table} \
+ (username, pass, reply, authdate ${..class.column_name}) \
+ VALUES ( \
+ '%{SQL-User-Name}', \
+ '%{%{User-Password}:-%{Chap-Password}}', \
+ '%{reply:Packet-Type}', \
+ '%S.%M' \
+ ${..class.reply_xlat})"
+}
diff --git a/raddb/mods-config/sql/main/sqlite/schema.sql b/raddb/mods-config/sql/main/sqlite/schema.sql
new file mode 100644
index 0000000..4625a58
--- /dev/null
+++ b/raddb/mods-config/sql/main/sqlite/schema.sql
@@ -0,0 +1,164 @@
+-----------------------------------------------------------------------------
+-- $Id$ --
+-- --
+-- schema.sql rlm_sql - FreeRADIUS SQLite Module --
+-- --
+-- Database schema for SQLite rlm_sql module --
+-- --
+-----------------------------------------------------------------------------
+
+--
+-- Table structure for table 'radacct'
+--
+CREATE TABLE IF NOT EXISTS radacct (
+ radacctid INTEGER PRIMARY KEY AUTOINCREMENT,
+ acctsessionid varchar(64) NOT NULL default '',
+ acctuniqueid varchar(32) NOT NULL default '',
+ username varchar(64) NOT NULL default '',
+ realm varchar(64) default '',
+ nasipaddress varchar(15) NOT NULL default '',
+ nasportid varchar(32) 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) default NULL,
+ acctauthentic varchar(32) default NULL,
+ connectinfo_start varchar(128) default NULL,
+ connectinfo_stop varchar(128) 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 '',
+ framedipv6address varchar(45) NOT NULL default '',
+ framedipv6prefix varchar(45) NOT NULL default '',
+ framedinterfaceid varchar(44) NOT NULL default '',
+ delegatedipv6prefix varchar(45) NOT NULL default '',
+ class varchar(64) default NULL
+);
+
+--
+-- You might not need all of these indexes. It should be safe to
+-- delete indexes you do not use. For example, if you're not using
+-- IPv6, you can delete the indexes on IPv6 attributes.
+--
+-- You MUST however leave the indexes needed by the server, which
+-- include username, acctstoptime, nasipaddress, acctstarttime, and
+-- acctuniqueid.
+--
+CREATE UNIQUE INDEX acctuniqueid ON radacct(acctuniqueid);
+CREATE INDEX username ON radacct(username);
+CREATE INDEX framedipaddress ON radacct (framedipaddress);
+CREATE INDEX framedipv6address ON radacct (framedipv6address);
+CREATE INDEX framedipv6prefix ON radacct (framedipv6prefix);
+CREATE INDEX framedinterfaceid ON radacct (framedinterfaceid);
+CREATE INDEX delegatedipv6prefix ON radacct (delegatedipv6prefix);
+CREATE INDEX acctsessionid ON radacct(acctsessionid);
+CREATE INDEX acctsessiontime ON radacct(acctsessiontime);
+CREATE INDEX acctstarttime ON radacct(acctstarttime);
+CREATE INDEX acctinterval ON radacct(acctinterval);
+CREATE INDEX acctstoptime ON radacct(acctstoptime);
+CREATE INDEX nasipaddress ON radacct(nasipaddress);
+CREATE INDEX class ON radacct(class);
+
+--
+-- Table structure for table 'radcheck'
+--
+CREATE TABLE IF NOT EXISTS radcheck (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ username varchar(64) NOT NULL default '',
+ attribute varchar(64) NOT NULL default '',
+ op char(2) NOT NULL DEFAULT '==',
+ value varchar(253) NOT NULL default ''
+);
+CREATE INDEX check_username ON radcheck(username);
+
+--
+-- Table structure for table 'radgroupcheck'
+--
+CREATE TABLE IF NOT EXISTS radgroupcheck (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ groupname varchar(64) NOT NULL default '',
+ attribute varchar(64) NOT NULL default '',
+ op char(2) NOT NULL DEFAULT '==',
+ value varchar(253) NOT NULL default ''
+);
+CREATE INDEX check_groupname ON radgroupcheck(groupname);
+
+--
+-- Table structure for table 'radgroupreply'
+--
+CREATE TABLE IF NOT EXISTS radgroupreply (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ groupname varchar(64) NOT NULL default '',
+ attribute varchar(64) NOT NULL default '',
+ op char(2) NOT NULL DEFAULT '=',
+ value varchar(253) NOT NULL default ''
+);
+CREATE INDEX reply_groupname ON radgroupreply(groupname);
+
+--
+-- Table structure for table 'radreply'
+--
+CREATE TABLE IF NOT EXISTS radreply (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ username varchar(64) NOT NULL default '',
+ attribute varchar(64) NOT NULL default '',
+ op char(2) NOT NULL DEFAULT '=',
+ value varchar(253) NOT NULL default ''
+);
+CREATE INDEX reply_username ON radreply(username);
+
+--
+-- Table structure for table 'radusergroup'
+--
+CREATE TABLE IF NOT EXISTS radusergroup (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ username varchar(64) NOT NULL default '',
+ groupname varchar(64) NOT NULL default '',
+ priority int(11) NOT NULL default '1'
+);
+CREATE INDEX usergroup_username ON radusergroup(username);
+
+--
+-- Table structure for table 'radpostauth'
+--
+CREATE TABLE IF NOT EXISTS radpostauth (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ username varchar(64) NOT NULL default '',
+ pass varchar(64) NOT NULL default '',
+ reply varchar(32) NOT NULL default '',
+ authdate timestamp NOT NULL,
+ class varchar(64) default NULL
+);
+CREATE INDEX radpostauth_username ON radpostauth(username);
+CREATE INDEX radpostauth_class ON radpostauth(class);
+
+--
+-- Table structure for table 'nas'
+--
+CREATE TABLE IF NOT EXISTS nas (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ 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'
+);
+CREATE INDEX nasname ON nas(nasname);
+
+--
+-- Table structure for table 'nasreload'
+--
+CREATE TABLE IF NOT EXISTS nasreload (
+ nasipaddress varchar(15) PRIMARY KEY,
+ reloadtime datetime NOT NULL
+);
diff --git a/raddb/mods-config/sql/moonshot-targeted-ids/mysql/queries.conf b/raddb/mods-config/sql/moonshot-targeted-ids/mysql/queries.conf
new file mode 100644
index 0000000..68306db
--- /dev/null
+++ b/raddb/mods-config/sql/moonshot-targeted-ids/mysql/queries.conf
@@ -0,0 +1,15 @@
+# -*- text -*-
+#
+# moonshot-targeted-ids/mysql/queries.conf -- Queries to update a MySQL Moonshot-Targeted-Ids table.
+#
+# $Id$
+
+post-auth {
+ # Query to store the Moonshot-*-TargetedId
+ query = "\
+ INSERT IGNORE INTO ${..moonshot_tid_table} \
+ (gss_acceptor, namespace, username, targeted_id) \
+ VALUES \
+ ('%{control:Moonshot-MSTID-GSS-Acceptor}', '%{control:Moonshot-MSTID-Namespace}', \
+ '%{tolower:%{User-Name}}', '%{control:Moonshot-MSTID-TargetedId}')"
+}
diff --git a/raddb/mods-config/sql/moonshot-targeted-ids/mysql/schema.sql b/raddb/mods-config/sql/moonshot-targeted-ids/mysql/schema.sql
new file mode 100644
index 0000000..8a33dc1
--- /dev/null
+++ b/raddb/mods-config/sql/moonshot-targeted-ids/mysql/schema.sql
@@ -0,0 +1,8 @@
+CREATE TABLE `moonshot_targeted_ids` (
+ `gss_acceptor` varchar(254) NOT NULL default '',
+ `namespace` varchar(36) NOT NULL default '',
+ `username` varchar(64) NOT NULL default '',
+ `targeted_id` varchar(128) NOT NULL default '',
+ `creationdate` timestamp NOT NULL default CURRENT_TIMESTAMP,
+ PRIMARY KEY (`username`,`gss_acceptor`,`namespace`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
diff --git a/raddb/mods-config/sql/moonshot-targeted-ids/postgresql/queries.conf b/raddb/mods-config/sql/moonshot-targeted-ids/postgresql/queries.conf
new file mode 100644
index 0000000..f757a87
--- /dev/null
+++ b/raddb/mods-config/sql/moonshot-targeted-ids/postgresql/queries.conf
@@ -0,0 +1,15 @@
+# -*- text -*-
+#
+# moonshot-targeted-ids/postgresql/queries.conf -- Queries to update a PostgreSQL Moonshot-*-Targeted-Ids table.
+#
+# $Id$
+
+post-auth {
+ # Query to store the Moonshot-*-TargetedId
+ query = "\
+ INSERT INTO ${..moonshot_tid_table} \
+ (gss_acceptor, namespace, username, targeted_id) \
+ VALUES \
+ ('%{control:Moonshot-MSTID-GSS-Acceptor}', '%{control:Moonshot-MSTID-Namespace}', \
+ '%{tolower:%{User-Name}}', '%{control:Moonshot-MSTID-TargetedId}')"
+}
diff --git a/raddb/mods-config/sql/moonshot-targeted-ids/postgresql/schema.sql b/raddb/mods-config/sql/moonshot-targeted-ids/postgresql/schema.sql
new file mode 100644
index 0000000..649c627
--- /dev/null
+++ b/raddb/mods-config/sql/moonshot-targeted-ids/postgresql/schema.sql
@@ -0,0 +1,8 @@
+CREATE TABLE moonshot_targeted_ids (
+ gss_acceptor varchar(254) NOT NULL DEFAULT '',
+ namespace varchar(36) NOT NULL DEFAULT '',
+ username varchar(64) NOT NULL DEFAULT '',
+ targeted_id varchar(128) NOT NULL DEFAULT '',
+ creationdate TIMESTAMP with time zone NOT NULL default 'now()',
+ PRIMARY KEY (username, gss_acceptor, namespace)
+);
diff --git a/raddb/mods-config/sql/moonshot-targeted-ids/sqlite/queries.conf b/raddb/mods-config/sql/moonshot-targeted-ids/sqlite/queries.conf
new file mode 100644
index 0000000..8cdb803
--- /dev/null
+++ b/raddb/mods-config/sql/moonshot-targeted-ids/sqlite/queries.conf
@@ -0,0 +1,15 @@
+# -*- text -*-
+#
+# moonshot-targeted-ids/sqlite/queries.conf -- Queries to update a sqlite Moonshot-*-Targeted-Ids table.
+#
+# $Id$
+
+post-auth {
+ # Query to store the Moonshot-*-TargetedId
+ query = "\
+ INSERT INTO ${..moonshot_tid_table} \
+ (gss_acceptor, namespace, username, targeted_id) \
+ VALUES \
+ ('%{control:Moonshot-MSTID-GSS-Acceptor}', '%{control:Moonshot-MSTID-Namespace}', \
+ '%{tolower:%{User-Name}}', '%{control:Moonshot-MSTID-TargetedId}')"
+}
diff --git a/raddb/mods-config/sql/moonshot-targeted-ids/sqlite/schema.sql b/raddb/mods-config/sql/moonshot-targeted-ids/sqlite/schema.sql
new file mode 100644
index 0000000..71195ad
--- /dev/null
+++ b/raddb/mods-config/sql/moonshot-targeted-ids/sqlite/schema.sql
@@ -0,0 +1,8 @@
+CREATE TABLE `moonshot_targeted_ids` (
+ `gss_acceptor` varchar(254) NOT NULL default '',
+ `namespace` varchar(36) NOT NULL default '',
+ `username` varchar(64) NOT NULL default '',
+ `targeted_id` varchar(128) NOT NULL default '',
+ `creationdate` timestamp NOT NULL default CURRENT_TIMESTAMP,
+ PRIMARY KEY (`username`,`gss_acceptor`,`namespace`)
+);
diff --git a/raddb/mods-config/unbound/default.conf b/raddb/mods-config/unbound/default.conf
new file mode 100644
index 0000000..9aac368
--- /dev/null
+++ b/raddb/mods-config/unbound/default.conf
@@ -0,0 +1,2 @@
+server:
+ num-threads: 2
diff --git a/raddb/panic.gdb b/raddb/panic.gdb
new file mode 100644
index 0000000..3ae253a
--- /dev/null
+++ b/raddb/panic.gdb
@@ -0,0 +1,4 @@
+info locals
+info args
+thread apply all bt full
+quit
diff --git a/raddb/policy.d/abfab-tr b/raddb/policy.d/abfab-tr
new file mode 100644
index 0000000..3a08853
--- /dev/null
+++ b/raddb/policy.d/abfab-tr
@@ -0,0 +1,106 @@
+#
+# ABFAB Trust router policies.
+#
+# $Id$
+#
+
+
+#
+# Verify rp parameters
+#
+psk_authorize {
+ if (&TLS-PSK-Identity) {
+ # TODO: may need to check trust-router-apc as well
+ if ("%{psksql:select distinct keyid from authorizations_keys where keyid = '%{tls-psk-identity}' and '%{trust-router-coi}' like coi and '%{gss-acceptor-realm-name}' like acceptor_realm and '%{gss-acceptor-host-name}' like hostname;}") {
+ # do things here
+ }
+ else {
+ update reply {
+ Reply-Message = "RP not authorized for this ABFAB request"
+ }
+ reject
+ }
+ }
+}
+
+abfab_client_check {
+ # check that GSS-Acceptor-Host-Name is correct
+ if ("%{client:gss_acceptor_host_name}") {
+ if (&request:GSS-Acceptor-Host-Name) {
+ if (&request:GSS-Acceptor-Host-Name != "%{client:gss_acceptor_host_name}") {
+ update reply {
+ Reply-Message = "GSS-Acceptor-Host-Name incorrect"
+ }
+ reject
+ }
+ }
+ else {
+ # set GSS-Acceptor-Host-Name if it is not set by the mechanism
+ # but it is defined in the client configuration
+ update request {
+ GSS-Acceptor-Host-Name = "%{client:gss_acceptor_host_name}"
+ }
+ }
+ }
+
+ # set Trust-Router-COI attribute from the client configuration
+ if ("%{client:trust_router_coi}") {
+ update request {
+ Trust-Router-COI := "%{client:trust_router_coi}"
+ }
+ }
+
+ # set GSS-Acceptor-Realm-Name attribute from the client configuration
+ if ("%{client:gss_acceptor_realm_name}") {
+ update request {
+ GSS-Acceptor-Realm-Name := "%{client:gss_acceptor_realm_name}"
+ }
+ }
+
+ # set GSS-Acceptor-Service-Name attribute from the client configuration
+ if ("%{client:gss_acceptor_service_name}") {
+ update request {
+ GSS-Acceptor-Service-Name = "%{client:gss_acceptor_service_name}"
+ }
+ }
+
+}
+
+# A policy which is used to validate channel-bindings.
+#
+abfab_channel_bindings {
+ if (&GSS-Acceptor-Service-Name && (&outer.request:GSS-Acceptor-Service-Name != &GSS-Acceptor-Service-Name)) {
+ reject
+ }
+
+ if (&GSS-Acceptor-Host-Name && &outer.request:GSS-Acceptor-Host-Name != &GSS-Acceptor-Host-Name ) {
+ reject
+ }
+
+ if (&GSS-Acceptor-Realm-Name && &outer.request:GSS-Acceptor-Realm-Name != &GSS-Acceptor-Realm-Name ) {
+ reject
+ }
+
+ if (&GSS-Acceptor-Service-Name || &GSS-Acceptor-Realm-Name || &GSS-Acceptor-Host-Name) {
+ update control {
+ &Chbind-Response-Code := success
+ }
+
+ #
+ # ACK the attributes in the request.
+ #
+ # If any one of these attributes don't exist in the request,
+ # then they won't be copied to the reply.
+ #
+ update reply {
+ &GSS-Acceptor-Service-Name = &GSS-Acceptor-Service-Name
+ &GSS-Acceptor-Host-Name = &GSS-Acceptor-Host-Name
+ &GSS-Acceptor-Realm-Name = &GSS-Acceptor-Realm-Name
+ }
+ }
+
+ #
+ # Return "handled" so that the "authenticate" section isn't used.
+ #
+ handled
+}
diff --git a/raddb/policy.d/accounting b/raddb/policy.d/accounting
new file mode 100644
index 0000000..6199d37
--- /dev/null
+++ b/raddb/policy.d/accounting
@@ -0,0 +1,127 @@
+# We check for this prefix to determine whether the class value was
+# generated by this server. It should be changed so that it is
+# globally unique.
+class_value_prefix = 'ai:'
+
+#
+# Replacement for the old rlm_acct_unique module
+#
+acct_unique {
+ #
+ # If we have a class attribute in the format
+ # 'auth_id:[0-9a-f]{32}' it'll have a local value
+ # (defined by insert_acct_class), this ensures
+ # uniqueness and suitability.
+ #
+ # We could just use the Class attribute as
+ # Acct-Unique-Session-Id, but this may cause problems
+ # with NAS that carry Class values across between
+ # multiple linked sessions. So we rehash class with
+ # Acct-Session-ID to provide a truely unique session
+ # identifier.
+ #
+ # Using a Class/Session-ID combination is more robust
+ # than using elements in the Accounting-Request,
+ # which may be subject to change, such as
+ # NAS-IP-Address, Client-IP-Address and
+ # NAS-Port-ID/NAS-Port.
+ #
+ # This policy should ensure that session data is not
+ # affected if NAS IP addresses change, or the client
+ # roams to a different 'port' whilst maintaining its
+ # initial authentication session (Common in a
+ # wireless environment).
+ #
+ update request {
+ &Tmp-String-9 := "${policy.class_value_prefix}"
+ }
+
+ if (("%{hex:&Class}" =~ /^%{hex:&Tmp-String-9}/) && \
+ ("%{string:&Class}" =~ /^${policy.class_value_prefix}([0-9a-f]{32})/i)) {
+ update request {
+ &Acct-Unique-Session-Id := "%{md5:%{1},%{Acct-Session-ID}}"
+ }
+ }
+
+ #
+ # Not All devices respect RFC 2865 when dealing with
+ # the class attribute, so be prepared to use the
+ # older style of hashing scheme if a class attribute
+ # is not included
+ #
+ else {
+ update request {
+ &Acct-Unique-Session-Id := "%{md5:%{User-Name},%{Acct-Session-ID},%{%{NAS-IPv6-Address}:-%{NAS-IP-Address}},%{NAS-Identifier},%{NAS-Port-ID},%{NAS-Port}}"
+ }
+ }
+
+ update request {
+ &Tmp-String-9 !* ANY
+ }
+}
+
+#
+# Insert a (hopefully unique) value into class
+#
+insert_acct_class {
+ update reply {
+ &Class = "${policy.class_value_prefix}%{md5:%t,%{Packet-Src-Port},%{%{Packet-Src-IP-Address}:-%{Packet-Src-IPv6-Address}},%{NAS-IP-Address},%{Calling-Station-ID},%{User-Name},%{session-state:User-Name} }"
+ }
+}
+
+#
+# Merges Acct-[Input|Output]-Octets and Acct-[Input|Output]-Gigawords into Acct-[Input|Output]-Octets64
+#
+# If the &Attr-Foo doesn't exist, it's value is taken as zero.
+#
+acct_counters64.preacct {
+ update request {
+ &Acct-Input-Octets64 = "%{expr:(&Acct-Input-Gigawords << 32) | &Acct-Input-Octets}"
+ &Acct-Output-Octets64 = "%{expr:(&Acct-Output-Gigawords << 32) | &Acct-Output-Octets}"
+ }
+}
+
+#
+# There is a delay between sending the Access-Accept and receiving
+# the corresponding Accounting-Request "start" packet. This delay
+# can be leveraged by a user to bypass Simultaneous-Use checks.
+#
+# The user can start up multiple sessions at the same time. When
+# that happens, both Simultaneous-Use checks are performed before any
+# Accounting-Request packet is received. Both Simultaneous-Use
+# checks will result in "no user session" in the radacct table, and
+# both sessions will be allowed. At some point later in time, the
+# Accounting-Request packets are received. But by then it's too
+# late.
+#
+# The solution is to insert a temporary session into the "radacct"
+# table, during the "post-auth" section. This is done by
+# uncommenting the "sql_session_start" entry in
+# sites-enabled/default. Then, reading
+# raddb/mods-config/sql/main/*/queries.conf, and looking for the
+# "sql_session_start" comments. Follow the instructions there to
+# finalize the configuration.
+#
+# The server will then create a temporary entry in "radacct" before
+# it returns the Access-Request. Any other Access-Request which is
+# received at the same time will then have it's Simultaneous-Use
+# check see that entry, and will be rejected.
+#
+# Subsequent Accounting-Request packets for the first session will
+# then UPDATE (not INSERT) the data for the session.
+#
+# There is still a small race condition as the Simultaneous-Use
+# checks are not done at the same time as updating radacct. But the
+# window of opportunity is much smaller. i.e. milliseconds, instead
+# of seconds.
+#
+# This policy can also be used to "bootstrap" accounting sessions.
+# If there is data which is only available in the Access-Request,
+# it can be placed in the accounting table. Then, when accounting
+# packets are received, they will update the row which contains
+# the session information.
+#
+sql_session_start.post-auth {
+ acct_unique
+ sql.accounting
+}
diff --git a/raddb/policy.d/canonicalization b/raddb/policy.d/canonicalization
new file mode 100644
index 0000000..6d90e37
--- /dev/null
+++ b/raddb/policy.d/canonicalization
@@ -0,0 +1,113 @@
+#
+# Split User-Name in NAI format (RFC 4282) into components
+#
+# This policy writes the Username and Domain portions of the
+# NAI into the Stripped-User-Name and Stripped-User-Domain
+# attributes.
+#
+# The regular expression to do this is not strictly compliant
+# with the standard, but it is not possible to write a
+# compliant regexp without perl style regular expressions (or
+# at least not a legible one).
+#
+nai_regexp = '^([^@]*)(@([-[:alnum:]]+\.[-[:alnum:].]+))?$'
+
+split_username_nai {
+ if (&User-Name && (&User-Name =~ /${policy.nai_regexp}/)) {
+ update request {
+ &Stripped-User-Name := "%{1}"
+ }
+
+ # Only add the Stripped-User-Domain attribute if
+ # we have a domain. This means presence checks
+ # for Stripped-User-Domain work.
+ if ("%{3}" != '') {
+ update request {
+ &Stripped-User-Domain = "%{3}"
+ }
+ }
+
+ # If any of the expansions result in a null
+ # string, the update section may return
+ # something other than updated...
+ updated
+ }
+ else {
+ noop
+ }
+}
+
+#
+# If called in post-proxy we modify the proxy-reply message
+#
+split_username_nai.post-proxy {
+ if (&proxy-reply:User-Name && (&proxy-reply:User-Name =~ /${policy.nai_regexp}/)) {
+ update proxy-reply {
+ &Stripped-User-Name := "%{1}"
+ }
+
+ # Only add the Stripped-User-Domain attribute if
+ # we have a domain. This means presence checks
+ # for Stripped-User-Domain work.
+ if ("%{3}" != '') {
+ update proxy-reply {
+ &Stripped-User-Domain = "%{3}"
+ }
+ }
+ updated
+ }
+ else {
+ noop
+ }
+}
+
+#
+# Normalize the MAC Addresses in the Calling/Called-Station-Id
+#
+mac-addr-regexp = '([0-9a-f]{2})[^0-9a-f]?([0-9a-f]{2})[^0-9a-f]?([0-9a-f]{2})[^0-9a-f]?([0-9a-f]{2})[^0-9a-f]?([0-9a-f]{2})[^0-9a-f]?([0-9a-f]{2})'
+
+#
+# Add "rewrite_called_station_id" in the "authorize" and
+# "preacct" sections.
+#
+# Makes Called-Station-ID conform to what RFC3580 says should
+# be provided by 802.1X authenticators.
+#
+rewrite_called_station_id {
+ if (&Called-Station-Id && (&Called-Station-Id =~ /^${policy.mac-addr-regexp}([^0-9a-f](.+))?$/i)) {
+ update request {
+ &Called-Station-Id := "%{toupper:%{1}-%{2}-%{3}-%{4}-%{5}-%{6}}"
+ }
+
+ # SSID component?
+ if ("%{8}") {
+ update request {
+ &Called-Station-SSID := "%{8}"
+ }
+ }
+ updated
+ }
+ else {
+ noop
+ }
+}
+
+#
+# Add "rewrite_calling_station_id" in the "authorize" and
+# "preacct" sections.
+#
+# Makes Calling-Station-ID conform to what RFC3580 says should
+# be provided by 802.1X authenticators.
+#
+rewrite_calling_station_id {
+ if (&Calling-Station-Id && (&Calling-Station-Id =~ /^${policy.mac-addr-regexp}$/i)) {
+ update request {
+ &Calling-Station-Id := "%{toupper:%{1}-%{2}-%{3}-%{4}-%{5}-%{6}}"
+ }
+ updated
+ }
+ else {
+ noop
+ }
+}
+
diff --git a/raddb/policy.d/control b/raddb/policy.d/control
new file mode 100644
index 0000000..b3f1e03
--- /dev/null
+++ b/raddb/policy.d/control
@@ -0,0 +1,40 @@
+#
+# If you want the server to pretend that it is dead,
+# then use the "do_not_respond" policy.
+#
+do_not_respond {
+ update control {
+ &Response-Packet-Type := Do-Not-Respond
+ }
+ handled
+}
+
+#
+# Send Access-Accept immediately
+#
+accept {
+ update control {
+ &Response-Packet-Type = Access-Accept
+ }
+ handled
+}
+
+#
+# Send Access-Challenge immediately
+#
+challenge {
+ update control {
+ &Response-Packet-Type = Access-Challenge
+ }
+ handled
+}
+
+#
+# Send an Accounting-Response immediately
+#
+acct_response {
+ update control {
+ &Response-Packet-Type = Accounting-Response
+ }
+ handled
+}
diff --git a/raddb/policy.d/cui b/raddb/policy.d/cui
new file mode 100644
index 0000000..08b2c91
--- /dev/null
+++ b/raddb/policy.d/cui
@@ -0,0 +1,131 @@
+#
+# The following policies are for the Chargeable-User-Identity
+# (CUI) configuration.
+#
+# The policies below can be called as just 'cui' (not
+# cui.authorize etc..) from the various config sections.
+#
+
+#
+# cui_hash_key definition
+# This key serves the purpose of protecting CUI values against
+# dictionary attacks, therefore should be chosen as a "random"
+# string and kept secret.
+#
+cui_hash_key = "changeme"
+
+#
+# cui_require_operator_name switch
+# If this is set to nonzero value then CUI will only be added
+# when a non-empty Operator-Name value is present in the request
+#
+cui_require_operator_name = "no"
+
+#
+# The client indicates it can do CUI by sending a CUI attribute
+# containing one zero byte.
+# A non-empty value in Operator-Name can be an additional requirement.
+# Normally CUI support is turned on only for such requests.
+# CUI support can be used for local clients which do not
+# supports CUI themselves, the server can simulate a CUI request
+# adding the missing NUL CUI value and the Operator-Name attribute.
+# Clients which are supposed to get this treatment should
+# be marked by add_cui flag in clients.conf
+# We assume that local clients are marked in the client.conf with
+# add_cui flag, e.g.
+# client xxxx {
+# ...
+# add_cui = yes
+# }
+#
+cui.authorize {
+ if ("%{client:add_cui}" == 'yes') {
+ update request {
+ &Chargeable-User-Identity := 0x00
+ }
+ }
+}
+
+#
+# Before proxing an Access-Request to a remote server, a NUL CUI
+# attribute should be added, unless it is already present in the request.
+#
+cui.pre-proxy {
+ if (("%{request:Packet-Type}" == 'Access-Request') && ("%{client:add_cui}" == 'yes')) {
+ update proxy-request {
+ &Chargeable-User-Identity = 0x00
+ }
+ }
+}
+
+
+#
+# Add a CUI attribute based on the User-Name, and a secret key
+# known only to this server.
+# For EAP-TTLS and EAP-PEAP methods
+# use_tunneled_reply parameter MUST be set to yes
+#
+cui.post-auth {
+ if (!&control:Proxy-To-Realm && &Chargeable-User-Identity && !&reply:Chargeable-User-Identity && \
+ (&Operator-Name || ('${policy.cui_require_operator_name}' != 'yes')) ) {
+ update reply {
+ &Chargeable-User-Identity = "%{sha1:${policy.cui_hash_key}%{tolower:%{User-Name}%{%{Operator-Name}:-}}}"
+ }
+ }
+
+ #
+ # The section below will store a CUI for the User in the DB and remove the
+ # User-Name attribute from the reply if a CUI is present.
+ #
+ # You need to configure the cuisql module and your database for this to work.
+ # If your NAS can do CUI based accounting themselves or you do not care about
+ # accounting, comment out the 'cuisql' line below.
+ #
+ if (&reply:Chargeable-User-Identity) {
+ # Force User-Name to be the User-Name from the request
+ update {
+ &reply:User-Name := &request:User-Name
+ }
+ cuisql
+ }
+}
+
+
+cui-inner.post-auth {
+ if (&outer.request:Chargeable-User-Identity && \
+ (&outer.request:Operator-Name || ('${policy.cui_require_operator_name}' != 'yes'))) {
+ update reply {
+ &Chargeable-User-Identity := "%{sha1:${policy.cui_hash_key}%{tolower:%{User-Name}%{%{outer.request:Operator-Name}:-}}}"
+ }
+ }
+}
+
+#
+# If your NAS can do CUI based accounting or you do not care about
+# accounting then just comment out the call to cui in ......
+#
+# If we had stored a CUI for the User, add it to the request.
+#
+cui.accounting {
+ #
+ # If the CUI isn't in the packet, see if we can find it
+ # in the DB.
+ #
+ if (!&Chargeable-User-Identity) {
+ update request {
+ &Chargeable-User-Identity := "%{cuisql:\
+ SELECT cui FROM cui \
+ WHERE clientipaddress = '%{%{Packet-Src-IPv6-Address}:-%{Packet-Src-IP-Address}}' \
+ AND callingstationid = '%{Calling-Station-Id}' \
+ AND username = '%{User-Name}'}"
+ }
+ }
+
+ #
+ # If it exists now, then write out when we last saw
+ # this CUI.
+ #
+ if (&Chargeable-User-Identity && (&Chargeable-User-Identity != '')) {
+ cuisql
+ }
+}
diff --git a/raddb/policy.d/debug b/raddb/policy.d/debug
new file mode 100644
index 0000000..26583f1
--- /dev/null
+++ b/raddb/policy.d/debug
@@ -0,0 +1,64 @@
+#
+# 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 coa list in debugging (-X) mode
+#
+debug_coa {
+ if("%{debug_attr:coa:}" == '') {
+ 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 proxy-request state list in debugging (-X) mode
+#
+debug_proxy_request {
+ if("%{debug_attr:proxy-request:}" == '') {
+ noop
+ }
+}
+
+#
+# Outputs the contents of the main lists in debugging (-X) mode
+#
+debug_all {
+ debug_control
+ debug_request
+ debug_coa
+ debug_reply
+ debug_session_state
+}
diff --git a/raddb/policy.d/dhcp b/raddb/policy.d/dhcp
new file mode 100644
index 0000000..1752acb
--- /dev/null
+++ b/raddb/policy.d/dhcp
@@ -0,0 +1,327 @@
+# Assign common DHCP reply packet options
+dhcp_common {
+ # The contents here are invented. Change them!
+ update reply {
+ &DHCP-Domain-Name-Server = 127.0.0.1
+ &DHCP-Domain-Name-Server += 127.0.0.2
+ &DHCP-Subnet-Mask = 255.255.255.0
+ &DHCP-Router-Address = 192.0.2.1
+ &DHCP-Broadcast-Address = 192.0.2.255
+ &DHCP-IP-Address-Lease-Time = 7200
+ &DHCP-DHCP-Server-Identifier = &control:DHCP-DHCP-Server-Identifier
+ }
+}
+
+# Lookup DHCP group based options. This policy allows for membership
+# of multiple groups so can cover the ISC concepts of "group" and "class"
+# To use this enable the "dhcp_files" module
+#dhcp_group_options {
+# foreach &request:DHCP-Group-Name {
+# dhcp_set_group_options
+# }
+#}
+
+# Policy to override DHCP-Network-Subnet
+#
+# Some networks have a "shared-network" or "multinet" configuration (as
+# defined by some other DHCP servers) in which multiple IP subnets may
+# co-exist in a single Layer 2 network (or VLAN).
+#
+# In enterprise environments this is often for the purpose of providing loose
+# segregation between classes of devices such as local network-attached
+# storage or IP telephony. There are valid reasons why each of the subnets is
+# not seperately VLANed, such as to enable the use of ICMP redirects to avoid
+# hairpinning of cross-subnet traffic via a gateway.
+#
+# In ISP environments this is a common configuration for edge networks whose
+# access is provided by DOCSIS cable modems that share a VLAN with the devices
+# they provide a service to but are seperately addressed.
+#
+# Where it is necessary to force the selection of a particular subnet for a
+# device, multiple pools must be configured for each subnet and referenced
+# with unique identifiers in the *network-specific* section of
+# mods-config/files/dhcp.
+#
+# By default DHCP-Network-Subnet is populated such that it normally
+# refers to the Layer 2 network from which the DHCP query originates - we
+# cannot know the intended subnet for the device without additional input to
+# the policy.
+#
+# Override DHCP-Network-Subnet to be an address within the desired
+# network to force selection of a particular address pool and/or network
+# parameters.
+#
+# Note: If each subnet within a network is equally valid for the DHCP requests
+# originating from that network then you do not need to call this policy,
+# rather look at the examples concerning dhcp_subnet in
+# mods-config/files/dhcp instead, which use a single pool containing addresses
+# from all subnets then set the correct subnet-specific options based on the
+# randomly assigned IP address.
+#
+#dhcp_override_network {
+# if (&DHCP-Vendor-Class-Identifier && &DHCP-Vendor-Class-Identifier == "SIP100")
+# update request {
+# DHCP-Network-Subnet := 10.10.0.0
+# }
+# }
+#}
+
+
+# Policy that calls the files instance of the same name after first making
+# DHCP-Network-Subnet specific to the allocated IP address of the client.
+#dhcp_subnet {
+# update {
+# &DHCP-Network-Subnet := "%{%{reply:DHCP-Your-IP-Address}:-%{DHCP-Client-IP-Address}}"
+# }
+#
+# # Call the dhcp_subnet instance of the files module
+# dhcp_subnet
+#}
+
+# Assign compatibility data to request for sqlippool for DHCP Request
+dhcp_sqlippool_request {
+
+ #
+ # During initial address selection (DORA) the REQUEST is broadcast and
+ # requested-ip must be provided. We revoke any active offers for addresses
+ # not matching the requested-ip, i.e. those made by other servers when
+ # processing the DISCOVER.
+ #
+ # If there is only a single server then this optimisation can be disabled.
+ #
+ if (&DHCP-Requested-IP-Address) {
+ update request {
+ &Acct-Status-Type := Start
+ }
+ dhcp_sqlippool.accounting
+ }
+
+ # Extend an existing offer or active lease
+ update request {
+ &Acct-Status-Type := Alive
+ }
+ dhcp_sqlippool.accounting {
+ notfound = return
+ }
+
+ update reply {
+ &DHCP-Your-IP-Address := "%{%{DHCP-Requested-IP-Address}:-%{DHCP-Client-IP-Address}}"
+ }
+
+}
+
+# Assign compatibility data to request for sqlippool for DHCP Release
+dhcp_sqlippool_release {
+
+ # Do some minor hacks to the request so that it looks
+ # like a RADIUS Accounting Stop request to the SQL IP Pool module.
+ update request {
+ &Acct-Status-Type = Stop
+ }
+
+ # Call the actual module in accounting context
+ dhcp_sqlippool.accounting
+
+}
+
+# Assign compatibility data to request for sqlippool for DHCP Decline
+dhcp_sqlippool_decline {
+
+ # Do a minor hack to the request so that it looks
+ # like a RADIUS Accounting Off request to the SQL IP Pool module.
+ update request {
+ &Acct-Status-Type = Accounting-Off
+ }
+
+ # Call the actual module in accounting context
+ dhcp_sqlippool.accounting
+
+}
+
+# Example policy for fetching option data from SQL
+dhcp_policy_sql {
+
+ #
+ # Network-specific options
+ #
+
+ #
+ # We want to lookup the Layer 2 network specific DHCP options to
+ # include in the reply. For this we need a stable identifier for the
+ # network from which the request is originating (based on
+ # DHCP-Network-Subnet) which can be used as the lookup key
+ # (DHCP-SQL-Option-Identifier) for the network options.
+ #
+ # Here we fabricate an example for the purpose of placing all
+ # configuration elements into SQL. We use a PostgreSQL query that
+ # returns the network identifier in the row containing the smallest
+ # enclosing CIDR, which assumes a schema such as the following:
+ #
+ # CREATE TABLE fr_network_to_identifier (network CIDR, network_id TEXT)
+ #
+ # Note: An rlm_files based lookup of the network_identifier (as per
+ # the examples in the dhcp virtual server) may be preferable to an ad
+ # hoc SQL query assuming that the network topology does not change
+ # frequently.
+ #
+# update control {
+# &control:Tmp-String-0 := "%{dhcp_sql:SELECT network_id \
+# FROM fr_network_to_identifier \
+# WHERE '%{DHCP-Network-Subnet}'::inet << network \
+# ORDER BY MASKLEN(network) DESC LIMIT 1;}"
+# }
+
+ #
+ # Use the network identifer to lookup the options specific to the
+ # originating network, using "network" context. Common network
+ # settings can be placed into a group and shared, with individual
+ # networks mapped to one or more option groups.
+ #
+ # - Place network-specific options in the dhcpreply table with
+ # "context = 'network'".
+ # - Add "Fall-Through := Yes" to the network options in the dhcpreply
+ # table to trigger group lookups for the network, which are
+ # disabled by default.
+ # - Place "identifier = <network_id>, groupname = <group>,
+ # priority = <priority>, context = 'network'" in the dhcpgroup
+ # table to map a network to a shared set of network options.
+ # - Place group-specific options in the dhcpgroupreply table with
+ # "context = 'network'".
+ #
+ # Note: In "shared-network" or "multinet" topologies you can instead
+ # just set all of the network options once in the subnet-specific
+ # options (after obtaining an IP address), below.
+ #
+# update control {
+# &DHCP-SQL-Option-Context := "network"
+# &DHCP-SQL-Option-Identifier := &control:Tmp-String-0
+# }
+# dhcp_sql.authorize
+
+
+ #
+ # Allocate IPs from the DHCP pool in SQL.
+ #
+ # Here we simply reuse the network_id (obtained previously) as the
+ # Pool-Name.
+ #
+# update control {
+# &Pool-Name := &control:Tmp-String-0
+# }
+# dhcp_sqlippool
+
+
+ #
+ # Subnet-specific options
+ #
+
+ #
+ # In "shared-network" or "multinet" topologies (in which a Layer 2
+ # network has a single pool that contains addresses from multiple
+ # subnets) it is necessary to set subnet-specific options based on the
+ # address that has just been allocated.
+ #
+ # Again, for this we need to derive a stable identifier for the subnet
+ # to which the IP address we are issuing belongs that will serve as a
+ # lookup key for the network options.
+ #
+ # Continuing our previous example, we can use a PostgreSQL query to
+ # find the subnet identifer in the row with the closest enclosing
+ # CIDR, which assumes a schema such as the following:
+ #
+ # CREATE TABLE fr_subnet_to_identifier (subnet CIDR, subnet_id TEXT)
+ #
+ # Note: An rlm_files based lookup of the subnet_identifier (as per the
+ # examples in the dhcp virtual server) is preferable to an ad hoc SQL
+ # query assuming that the network topology does not change frequently.
+ #
+# update control {
+# &control:Tmp-String-0 := "%{dhcp_sql:SELECT subnet_id \
+# FROM fr_subnet_to_identifier \
+# WHERE '%{reply:DHCP-Your-IP-Address}'::inet << subnet \
+# ORDER BY MASKLEN(subnet) DESC LIMIT 1;}"
+# }
+
+ #
+ # Use the subnet identifer to lookup the options specific to the
+ # subnet for the IP we are allocating, using "subnet" context. Common
+ # subnet settings can be placed into a group and shared, with
+ # individual subnets mapped to one or more option groups.
+ #
+ # - Place subnet-specific options in the dhcpreply table with
+ # "context = 'subnet'".
+ # - Add "Fall-Through := Yes" to the subnet options in the dhcpreply
+ # table to trigger group lookups for the subnet, which are
+ # disabled by default.
+ # - Place "identifier = <subnet_id>, groupname = <group>,
+ # priority = <priority>, context = 'subnet'" in the dhcpgroup
+ # table to map a subnet to a shared set of subnet options.
+ # - Place group-specific options in the dhcpgroupreply table with
+ # "context = 'subnet'".
+ #
+# update control {
+# &DHCP-SQL-Option-Context := "subnet"
+# &DHCP-SQL-Option-Identifier := &control:Tmp-String-0
+# }
+# dhcp_sql.authorize
+
+
+ #
+ # Host-specific and group-specific options
+ #
+
+ # "Groups" conventionally differentiate devices based on manual
+ # groupings using a device-specific identifier such as the MAC
+ # address.
+ #
+ # - Place host-specific options in the dhcpreply table with
+ # "context = 'group'".
+ # - Add "Fall-Through := Yes" to the device options in the dhcpreply
+ # table to trigger group lookups, which are disabled by default.
+ # - Place "identifier = <MAC-Address>, groupname = <group>,
+ # priority = <priority>, context='group'" in the dhcpgroup table
+ # to map a device to its groups.
+ # - Place group-specific options in the dhcpgroupreply table with
+ # "context = 'group'".
+ #
+# update control {
+# &DHCP-SQL-Option-Context := "group"
+# &DHCP-SQL-Option-Identifier := &request:DHCP-Client-Hardware-Address
+# }
+# dhcp_sql.authorize
+
+
+ #
+ # Class/subclass-specific options
+ #
+
+ #
+ # "Classes" conventionally differentiate devices based on all or part
+ # of one or more DHCP request options, or any combination of
+ # information that is available in the request or has already looked
+ # up from some datastore.
+ #
+ # Create multiple instances of the following block, one for each
+ # class. Differentiate between classes by setting
+ # DHCP-SQL-Option-Context uniquely.
+ #
+ # - Place "subclass"-specific options (i.e. each member of a class)
+ # in the dhcpreply table with "context = <class-name>".
+ # - For class-level options common to every member of a class,
+ # either:
+ # - Duplicate the options for each member of the subclass.
+ # or:
+ # - Add "Fall-Through := Yes" to each members options to trigger
+ # group lookups, which are disabled by default.
+ # - Map each member of the class to a group in the dhcpgroup
+ # table with context = '<class-name>';
+ # - Create the corresponding class in the dhcpgroupreply table
+ # with "context = '<class-name>'".
+ #
+# update control {
+# &DHCP-SQL-Option-Context := "class-vci-substring"
+# &DHCP-SQL-Option-Identifier := "%{substring %{request:DHCP-Vendor-Class-Identifier} 5 4}"
+# }
+# dhcp_sql.authorize
+
+}
diff --git a/raddb/policy.d/eap b/raddb/policy.d/eap
new file mode 100644
index 0000000..c8dac22
--- /dev/null
+++ b/raddb/policy.d/eap
@@ -0,0 +1,54 @@
+#
+# Forbid all EAP types. Enable this by putting "forbid_eap"
+# into the "authorize" section.
+#
+forbid_eap {
+ if (&EAP-Message) {
+ reject
+ }
+}
+
+#
+# Forbid all non-EAP types outside of an EAP tunnel.
+#
+permit_only_eap {
+ if (!&EAP-Message) {
+ # We MAY be inside of a TTLS tunnel.
+ # PEAP and EAP-FAST require EAP inside of
+ # the tunnel, so this check is OK.
+ # If so, then there MUST be an outer EAP message.
+ if (!&outer.request || !&outer.request:EAP-Message) {
+ reject
+ }
+ }
+}
+
+#
+# Remove Reply-Message from response if were doing EAP
+#
+# Be RFC 3579 2.6.5 compliant - EAP-Message and Reply-Message should
+# not be present in the same response.
+#
+remove_reply_message_if_eap {
+ if (&reply:EAP-Message && &reply:Reply-Message) {
+ update reply {
+ &Reply-Message !* ANY
+ }
+ }
+ else {
+ noop
+ }
+}
+
+verify_tls_client_common_name {
+ #
+ # If the User-Name is anonymized, then don't check it.
+ #
+ # But if User-Name is realm AND there's a certificate name, then check
+ # if they match. This is not always the case, but it is the case
+ # often enough that it matters.
+ #
+ if ((&User-Name !~ /^@/) && &TLS-Client-Cert-Common-Name && (&TLS-Client-Cert-Common-Name != &User-Name)) {
+ reject
+ }
+}
diff --git a/raddb/policy.d/filter b/raddb/policy.d/filter
new file mode 100644
index 0000000..ff8f531
--- /dev/null
+++ b/raddb/policy.d/filter
@@ -0,0 +1,211 @@
+#
+# Example of forbidding all attempts to login via
+# realms.
+#
+deny_realms {
+ if (&User-Name && (&User-Name =~ /@|\\/)) {
+ reject
+ }
+}
+
+#
+# Filter the username
+#
+# Force some sanity on User-Name. This helps to avoid issues
+# issues where the back-end database is "forgiving" about
+# what constitutes a user name.
+#
+filter_username {
+ if (&User-Name) {
+ #
+ # reject mixed case e.g. "UseRNaMe"
+ #
+ #if (&User-Name != "%{tolower:%{User-Name}}") {
+ # reject
+ #}
+
+ #
+ # reject all whitespace
+ # e.g. "user@ site.com", or "us er", or " user", or "user "
+ #
+ if (&User-Name =~ / /) {
+ update request {
+ &Module-Failure-Message += 'Rejected: User-Name contains whitespace'
+ }
+ reject
+ }
+
+ #
+ # reject Multiple @'s
+ # e.g. "user@site.com@site.com"
+ #
+ if (&User-Name =~ /@[^@]*@/ ) {
+ update request {
+ &Module-Failure-Message += 'Rejected: Multiple @ in User-Name'
+ }
+ reject
+ }
+
+ #
+ # reject double dots
+ # e.g. "user@site..com"
+ #
+ if (&User-Name =~ /\.\./ ) {
+ update request {
+ &Module-Failure-Message += 'Rejected: User-Name contains multiple ..s'
+ }
+ reject
+ }
+
+ #
+ # must have at least 1 string-dot-string after @
+ # e.g. "user@site.com"
+ #
+ if ((&User-Name =~ /@/) && (&User-Name !~ /@(.+)\.(.+)$/)) {
+ update request {
+ &Module-Failure-Message += 'Rejected: Realm does not have at least one dot separator'
+ }
+ reject
+ }
+
+ #
+ # Realm ends with a dot
+ # e.g. "user@site.com."
+ #
+ if (&User-Name =~ /\.$/) {
+ update request {
+ &Module-Failure-Message += 'Rejected: Realm ends with a dot'
+ }
+ reject
+ }
+
+ #
+ # Realm begins with a dot
+ # e.g. "user@.site.com"
+ #
+ if (&User-Name =~ /@\./) {
+ update request {
+ &Module-Failure-Message += 'Rejected: Realm begins with a dot'
+ }
+ reject
+ }
+ }
+}
+
+#
+# Filter the User-Password
+#
+# Some equipment sends passwords with embedded zeros.
+# This policy filters them out.
+#
+filter_password {
+ if (&User-Password && \
+ (&User-Password != "%{string:User-Password}")) {
+ update request {
+ &Tmp-String-0 := "%{string:User-Password}"
+ &User-Password := "%{string:Tmp-String-0}"
+ &Tmp-String-0 !* ""
+ }
+ }
+}
+
+filter_inner_identity {
+ #
+ # No names, reject.
+ #
+ if (!&outer.request:User-Name || !&User-Name) {
+ update request {
+ Module-Failure-Message = "User-Name is required for tunneled authentication"
+ }
+ reject
+ }
+
+ #
+ # Do detailed checks only if the inner and outer
+ # NAIs are different.
+ #
+ # If the NAIs are the same, it violates user privacy,
+ # but is allowed.
+ #
+ if (&outer.request:User-Name != &User-Name) {
+ #
+ # Get the outer realm.
+ #
+ if (&outer.request:User-Name =~ /@([^@]+)$/) {
+ update request {
+ Outer-Realm-Name = "%{1}"
+ }
+
+ #
+ # When we have an outer realm name, the user portion
+ # MUST either be empty, or begin with "anon".
+ #
+ # We don't check for the full "anonymous", because
+ # some vendors don't follow the standards.
+ #
+ if (&outer.request:User-Name !~ /^(anon|@)/) {
+ update request {
+ Module-Failure-Message = "User-Name is not anonymized"
+ }
+ reject
+ }
+ }
+
+ #
+ # There's no outer realm. The outer NAI is different from the
+ # inner NAI. The User-Name MUST be anonymized.
+ #
+ # Otherwise, you could log in as outer "bob", and inner "doug",
+ # and we'd have no idea which one was correct.
+ #
+ elsif (&outer.request:User-Name !~ /^anon/) {
+ update request {
+ Module-Failure-Message = "User-Name is not anonymized"
+ }
+ reject
+ }
+
+ #
+ # Get the inner realm.
+ #
+ if (&User-Name =~ /@([^@]+)$/) {
+ update request {
+ Inner-Realm-Name = "%{1}"
+ }
+
+ #
+ # Note that we do EQUALITY checks for realm names.
+ # There is no simple way to do case insensitive checks
+ # on internationalized domain names. There is no reason
+ # to allow outer "anonymous@EXAMPLE.COM" and inner
+ # "user@example.com". The user should enter the same
+ # realm for both identities.
+ #
+ # If the inner realm isn't the same as the outer realm,
+ # the inner realm MUST be a subdomain of the outer realm.
+ #
+ if (&Outer-Realm-Name && \
+ (&Inner-Realm-Name != &Outer-Realm-Name) && \
+ (&Inner-Realm-Name !~ /\.%{Outer-Realm-Name}$/)) {
+ update request {
+ Module-Failure-Message = "Inner realm '%{Inner-Realm-Name}' and outer realm '%{Outer-Realm-Name}' are not from the same domain."
+ }
+ reject
+ }
+
+ #
+ # It's OK to have an inner realm and no outer realm.
+ #
+ # That won't work for roaming, but the local RADIUS server
+ # can still authenticate the user.
+ #
+ }
+
+ #
+ # It's OK to have an outer realm and no inner realm.
+ #
+ # It will work for roaming, and the local RADIUS server
+ # can authenticate the user without the realm.
+ #
+ }
+}
diff --git a/raddb/policy.d/moonshot-targeted-ids b/raddb/policy.d/moonshot-targeted-ids
new file mode 100644
index 0000000..98ae4a1
--- /dev/null
+++ b/raddb/policy.d/moonshot-targeted-ids
@@ -0,0 +1,249 @@
+#
+# The following policies generate targeted IDs for ABFAB (Moonshot)
+#
+# This policy requires that the UUID package is installed on your platform
+# and that this is called from the inner-tunnel
+#
+# The following string attributes need to exist in the UKERNA dictionary
+# Moonshot-Host-TargetedId (138)
+# Moonshot-Realm-TargetedId (139)
+# Moonshot-TR-COI-TargetedId (140)
+# Moonshot-MSTID-GSS-Acceptor (141)
+# Moonshot-MSTID-Namespace (142)
+# Moonshot-MSTID-TargetedId (143)
+#
+# These attributes should also be listed in the attr_filter policies
+# post-proxy and pre-proxy when you use attribute filtering:
+# Moonshot-Host-TargetedId =* ANY,
+# Moonshot-Realm-TargetedId =* ANY,
+# Moonshot-TR-COI-TargetedId =* ANY,
+#
+
+#
+# targeted_id_salt definition
+# This salt serves the purpose of protecting targeted IDs against
+# dictionary attacks, therefore should be chosen as a "random"
+# string and kept secret.
+#
+# If you use special characters %, { and }, escape them with a \ first
+#
+targeted_id_salt = 'changeme'
+
+#
+# Moonshot namespaces
+# These namespaces are used for UUID generation.
+# They should not be changed by implementors
+#
+moonshot_host_namespace = 'a574a04e-b7ff-4850-aa24-a8599c7de1c6'
+moonshot_realm_namespace = 'dea5f26d-a013-4444-977d-d09fc990d2e6'
+moonshot_coi_namespace = '145d7e7e-7d54-43ee-bbcb-3c6ad9428247'
+
+
+# This policy generates a host-specific TargetedId
+#
+moonshot_host_tid.post-auth {
+ # retrieve or generate a UUID for Moonshot-Host-TargetedId
+ if (&outer.request:GSS-Acceptor-Host-Name) {
+ # prep some variables (used regardless of SQL backing or not!)
+ update control {
+ Moonshot-MSTID-GSS-Acceptor := "%{tolower:%{outer.request:GSS-Acceptor-Host-Name}}"
+ Moonshot-MSTID-Namespace := "${policy.moonshot_host_namespace}"
+ }
+
+ # if you want to use SQL-based backing, remove the comment from
+ # this line. You also have to configure and enable the
+ # moonshot-targeted-ids sql module in mods-enabled.
+ #
+# moonshot_get_targeted_id
+
+ # generate a UUID for Moonshot-Host-TargetedId
+ if (!&control:Moonshot-MSTID-TargetedId) {
+ # generate the TID
+ moonshot_make_targeted_id
+
+ # if you want to store your TargetedId in SQL-based backing,
+ # remove the comment from this line. You also have to configure
+ # and enable the moonshot-targeted-ids sql module in mods-enabled.
+ #
+# moonshot_tid_sql
+ }
+
+ # set the actual TargetedId in the session-state list
+ if (&control:Moonshot-MSTID-TargetedId) {
+ update outer.session-state {
+ Moonshot-Host-TargetedId := &control:Moonshot-MSTID-TargetedId
+ }
+ update control {
+ Moonshot-MSTID-TargetedId !* ANY
+ }
+ }
+
+ # Sanitise the control list to remove the internal attributes
+ update control {
+ Moonshot-MSTID-GSS-Acceptor !* ANY
+ Moonshot-MSTID-Namespace !* ANY
+ }
+ }
+}
+
+# This policy generates a realm-specific TargetedId
+#
+moonshot_realm_tid.post-auth {
+ # retrieve or generate a UUID for Moonshot-Realm-TargetedId
+ if (&outer.request:GSS-Acceptor-Realm-Name) {
+ # prep some variables (used regardless of SQL backing or not!)
+ update control {
+ Moonshot-MSTID-GSS-Acceptor := "%{tolower:%{outer.request:GSS-Acceptor-Realm-Name}}"
+ Moonshot-MSTID-Namespace := "${policy.moonshot_realm_namespace}"
+ }
+
+ # if you want to use SQL-based backing, remove the comment from
+ # this line. You also have to configure and enable the
+ # moonshot-targeted-ids sql module in mods-enabled.
+ #
+# moonshot_get_targeted_id
+
+ # generate a UUID for Moonshot-Realm-TargetedId
+ if (!&control:Moonshot-MSTID-TargetedId) {
+ # generate the TID
+ moonshot_make_targeted_id
+
+ # if you want to store your TargetedId in SQL-based backing,
+ # remove the comment from this line. You also have to configure
+ # and enable the moonshot-targeted-ids sql module in mods-enabled.
+ #
+# moonshot_tid_sql
+ }
+
+ # set the actual TargetedId in the session-state list
+ if (&control:Moonshot-MSTID-TargetedId) {
+ update outer.session-state {
+ Moonshot-Realm-TargetedId := &control:Moonshot-MSTID-TargetedId
+ }
+ update control {
+ Moonshot-MSTID-TargetedId !* ANY
+ }
+ }
+
+ # Sanitise the control list to remove the internal attributes
+ update control {
+ Moonshot-MSTID-GSS-Acceptor !* ANY
+ Moonshot-MSTID-Namespace !* ANY
+ }
+ }
+}
+
+# This policy generates a COI-specific targeted ID
+#
+moonshot_coi_tid.post-auth {
+ # retrieve or generate a UUID for Moonshot-TR-COI-TargetedId
+ if (&outer.request:Trust-Router-COI) {
+ # prep some variables (used regardless of SQL backing or not!)
+ update control {
+ Moonshot-MSTID-GSS-Acceptor := "%{tolower:%{outer.request:Trust-Router-COI}}"
+ Moonshot-MSTID-Namespace := "${policy.moonshot_coi_namespace}"
+ }
+
+ # if you want to use SQL-based backing, remove the comment from
+ # this line. You also have to configure and enable the
+ # moonshot-targeted-ids sql module in mods-enabled.
+ #
+# moonshot_get_targeted_id
+
+ # generate a UUID for Moonshot-TR-COI-TargetedId
+ if (!&control:Moonshot-MSTID-TargetedId) {
+ # generate the TID
+ moonshot_make_targeted_id
+
+ # if you want to store your TargetedId in SQL-based backing,
+ # remove the comment from this line. You also have to configure
+ # and enable the moonshot-targeted-ids sql module in mods-enabled.
+ #
+# moonshot_tid_sql
+ }
+
+ # set the actual TargetedId in the session-state list
+ if (&control:Moonshot-MSTID-TargetedId) {
+ update outer.session-state {
+ Moonshot-TR-COI-TargetedId := &control:Moonshot-MSTID-TargetedId
+ }
+ update control {
+ Moonshot-MSTID-TargetedId !* ANY
+ }
+ }
+
+ # Sanitise the control list to remove the internal attributes
+ update control {
+ Moonshot-MSTID-GSS-Acceptor !* ANY
+ Moonshot-MSTID-Namespace !* ANY
+ }
+ }
+}
+
+# This is the generic generation policy. It requires moonshot_host_tid, moonshot_realm_tid, or moonshot_coi_tid to set variables
+#
+moonshot_make_targeted_id.post-auth {
+ # uses variables set in the control list
+ #
+ if (&control:Moonshot-MSTID-Namespace && &control:Moonshot-MSTID-GSS-Acceptor) {
+ # targeted id = (uuid -v 5 [namespace] [username][salt][GSS acceptor value])@[IdP realm name]
+ #
+ if ("%{echo:/usr/bin/uuid -v 5 %{control:Moonshot-MSTID-Namespace} %{tolower:%{User-Name}}${policy.targeted_id_salt}%{control:Moonshot-MSTID-GSS-Acceptor}}" =~ /^([^ ]+)([ ]*)$/) {
+ update control {
+ Moonshot-MSTID-TargetedId := "%{1}@%{tolower:%{request:Realm}}"
+ }
+ if (&control:Moonshot-MSTID-TargetedId =~ /([\%\{\}]+)/) {
+ update control {
+ Moonshot-MSTID-TargetedId !* ANY
+ }
+ update outer.session-state {
+ Module-Failure-Message = 'Invalid TargetedId generated, check your targeted_id_salt!'
+ }
+ reject
+ }
+ }
+ else {
+ # we simply return the 'echo' error message as the Module-Failure-Message, usually a lack of 'uuid'
+ reject
+ }
+ }
+ else {
+ # Our variables were not set, so we'll throw an error because there's no point in continuing!
+ update outer.session-state {
+ Module-Failure-Message = 'Required variables for moonshot_make_targeted_id not set!'
+ }
+ reject
+ }
+}
+
+# This is the generic retrieval policy. It requires moonshot_host_tid, moonshot_realm_tid, or moonshot_coi_tid to set variables
+#
+moonshot_get_targeted_id.post-auth {
+ # uses variables set in the control list
+ #
+ if (&control:Moonshot-MSTID-Namespace && &control:Moonshot-MSTID-GSS-Acceptor) {
+ # retrieve the TargetedId
+ #
+ update control {
+ Moonshot-MSTID-TargetedId := "%{moonshot_tid_sql:\
+ SELECT targeted_id FROM moonshot_targeted_ids \
+ WHERE gss_acceptor = '%{control:Moonshot-MSTID-GSS-Acceptor}' \
+ AND namespace = '%{control:Moonshot-MSTID-Namespace}' \
+ AND username = '%{tolower:%{User-Name}}'}"
+ }
+
+ # if the value is empty, there's no point in setting it and delete it from the control list!
+ if (&control:Moonshot-MSTID-TargetedId == '') {
+ update control {
+ Moonshot-MSTID-TargetedId !* ANY
+ }
+ }
+ }
+ else {
+ # Our variables were not set, so we'll throw an error because there's no point in continuing!
+ update outer.session-state {
+ Module-Failure-Message = 'Required variables for moonshot_get_targeted_id not set!'
+ }
+ reject
+ }
+}
diff --git a/raddb/policy.d/operator-name b/raddb/policy.d/operator-name
new file mode 100644
index 0000000..6d042d4
--- /dev/null
+++ b/raddb/policy.d/operator-name
@@ -0,0 +1,46 @@
+#
+# The following policies are for the Operator-Name
+# configuration.
+#
+# The policies below can be called as just 'operator-name' (not
+# operator-name.authorize etc..) from the various config sections.
+#
+
+# If you require that the Operator-Name be set
+# for local clients then call the 'operator-name' policy
+# in the authorize section of the virtual-server for your clients in clients.conf
+
+# To inject an Operator-Name whilst proxying, call the
+# 'operator-name' policy in the pre-proxy section of the virtual server
+# No need to call this if you have already enabled this in
+# the authorize section.
+
+#
+# We assume that clients can have the operator-name definition
+# in the client.conf, e.g.
+# client xxxx {
+# ...
+# Operator-Name = 1your.domain
+# }
+# If this parameter is found for a client, then we add
+# an Operator-Name attribute
+#
+operator-name.authorize {
+ if ("%{client:Operator-Name}") {
+ update request {
+ &Operator-Name = "%{client:Operator-Name}"
+ }
+ }
+}
+
+#
+# Before proxing the client add an Operator-Name
+# attribute identifying this site if the operator-name is found for this client
+#
+operator-name.pre-proxy {
+ if (("%{request:Packet-Type}" == 'Access-Request') && "%{client:Operator-Name}") {
+ update proxy-request {
+ &Operator-Name := "%{client:Operator-Name}"
+ }
+ }
+}
diff --git a/raddb/policy.d/rfc7542 b/raddb/policy.d/rfc7542
new file mode 100644
index 0000000..84a5c17
--- /dev/null
+++ b/raddb/policy.d/rfc7542
@@ -0,0 +1,46 @@
+#
+# The following policy is for RFC7542-style bang path
+# management.
+#
+# It hands control from the standard 'suffix' realm
+# processor to the 'bangpath' processer, allowing the
+# definition of specific routing information in the
+# decoration of the User-Name.
+#
+# Use this with caution. In particular, read the following
+# RFC document sections for reasons why you shouldn't use
+# this, and also why this is used:
+#
+# 1. https://tools.ietf.org/html/rfc4282#section-2.7
+# 2. https://tools.ietf.org/html/rfc7542#section-3.3.1
+#
+# $Id$
+#
+
+# This is a |-separated list of realms this specific service
+# is responsible for. We cannot read this from the proxy.conf
+# file, so we turn this into an 'or list' regex.
+# Examples: rfc7542_realms = 'example.com'
+# rfc7542_realms = 'example.com|another.net|this.org'
+#
+rfc7542_realms = 'changeme'
+
+# This policy checks the User-Name attribute whether it is in
+# RFC7542 bang-path format. If it is, it lets the bangpath realm
+# processor handle it, otherwise it leaves it for suffix to handle
+#
+rfc7542.authorize {
+ # Format: not_local_realm!...@local_realm: Handle with bangpath
+ if ( (&request:User-Name =~ /(.+)!(.*)\@(${policy.rfc7542_realms})/) && \
+ !(&request:User-Name =~ /(${policy.rfc7542_realms})!(.*)\@(.+)/) ) {
+ bangpath
+ updated
+ }
+
+ # Format: local_realm!...@not_local_realm: Handle with bangpath
+ elsif ( (&request:User-Name =~ /(${policy.rfc7542_realms})!(.*)\@(.+)/) && \
+ !(&request:User-Name =~ /(.+)!(.*)\@(${policy.rfc7542_realms})/) ) {
+ bangpath
+ updated
+ }
+}
diff --git a/raddb/proxy.conf b/raddb/proxy.conf
new file mode 100644
index 0000000..26f620c
--- /dev/null
+++ b/raddb/proxy.conf
@@ -0,0 +1,872 @@
+# -*- text -*-
+##
+## proxy.conf -- proxy radius and realm configuration directives
+##
+## $Id$
+
+#######################################################################
+#
+# Proxy server configuration
+#
+# This entry controls the servers behaviour towards ALL other servers
+# to which it sends proxy requests.
+#
+proxy server {
+ #
+ # Note that as of 2.0, the "synchronous", "retry_delay",
+ # "retry_count", and "dead_time" have all been deprecated.
+ # For backwards compatibility, they are are still accepted
+ # by the server, but they ONLY apply to the old-style realm
+ # configuration. i.e. realms with "authhost" and/or "accthost"
+ # entries.
+ #
+ # i.e. "retry_delay" and "retry_count" have been replaced
+ # with per-home-server configuration. See the "home_server"
+ # example below for details.
+ #
+ # i.e. "dead_time" has been replaced with a per-home-server
+ # "revive_interval". We strongly recommend that this not
+ # be used, however. The new method is much better.
+
+ #
+ # In 2.0, the server is always "synchronous", and setting
+ # "synchronous = no" is impossible. This simplifies the
+ # server and increases the stability of the network.
+ # However, it means that the server (i.e. proxy) NEVER
+ # originates packets. It proxies packets ONLY when it receives
+ # a packet or a re-transmission from the NAS. If the NAS never
+ # re-transmits, the proxy never re-transmits, either. This can
+ # affect fail-over, where a packet does *not* fail over to a
+ # second home server.. because the NAS never retransmits the
+ # packet.
+ #
+ # If you need to set "synchronous = no", please send a
+ # message to the list <freeradius-users@lists.freeradius.org>
+ # explaining why this feature is vital for your network.
+
+ #
+ # If a realm exists, but there are no live home servers for
+ # it, we can fall back to using the "DEFAULT" realm. This is
+ # most useful for accounting, where the server can proxy
+ # accounting requests to home servers, but if they're down,
+ # use a DEFAULT realm that is LOCAL (i.e. accthost = LOCAL),
+ # and then store the packets in the "detail" file. That data
+ # can be later proxied to the home servers by radrelay, when
+ # those home servers come back up again.
+
+ # Setting this to "yes" may have issues for authentication.
+ # i.e. If you are proxying for two different ISP's, and then
+ # act as a general dial-up for Gric. If one of the first two
+ # ISP's has their RADIUS server go down, you do NOT want to
+ # proxy those requests to GRIC. Instead, you probably want
+ # to just drop the requests on the floor. In that case, set
+ # this value to 'no'.
+ #
+ # allowed values: {yes, no}
+ #
+ default_fallback = no
+
+ #
+ # Whether or not we allow dynamic home servers.
+ #
+ # This setting should be "no" by default. If set to "yes",
+ # it can slow the server down, due to mutex locking across
+ # multiple threads.
+ #
+ # Dynamic servers will work ONLY with the "directory"
+ # configuration below.
+ #
+# dynamic = yes
+
+ #
+ # The directory which contains dynamic home servers. Each
+ # file in the directory should be a normal "home_server"
+ # definitions. This directory does not exist by default.
+ #
+ # e.g: The content of home_servers/example.com should be
+ # a home server definition.
+ #
+ # The name of the home server MUST be the same as the
+ # filename.
+ #
+ # Each home server must be set to only one type. e.g.
+ # "type = auth", and not "type = auth+acct"
+ #
+ # For example:
+ #
+ # home_server example.com {
+ # type = auth
+ # ipaddr = ...
+ # ...
+ # }
+ #
+ # For complete documentation, please see
+ #
+ # doc/configuration/dynamic_home_servers.md
+ #
+# directory = ${confdir}/home_servers
+
+}
+
+#######################################################################
+#
+# Configuration for the proxy realms.
+#
+# As of 2.0, the "realm" configuration has changed. Instead of
+# specifying "authhost" and "accthost" in a realm section, the home
+# servers are specified separately in a "home_server" section. For
+# backwards compatibility, you can still use the "authhost" and
+# "accthost" directives. If you only have one home server for a
+# realm, it is easier to use the old-style configuration.
+#
+# However, if you have multiple servers for a realm, we STRONGLY
+# suggest moving to the new-style configuration.
+#
+#
+# Load-balancing and failover between home servers is handled via
+# a "home_server_pool" section.
+#
+# Finally, The "realm" section defines the realm, some options, and
+# indicates which server pool should be used for the realm.
+#
+# This change means that simple configurations now require multiple
+# sections to define a realm. However, complex configurations
+# are much simpler than before, as multiple realms can share the same
+# server pool.
+#
+# That is, realms point to server pools, and server pools point to
+# home servers. Multiple realms can point to one server pool. One
+# server pool can point to multiple home servers. Each home server
+# can appear in one or more pools.
+#
+# See sites-available/tls for an example of configuring home servers,
+# pools, and realms with TLS.
+#
+
+######################################################################
+#
+# This section defines a "Home Server" which is another RADIUS
+# server that gets sent proxied requests. In earlier versions
+# of FreeRADIUS, home servers were defined in "realm" sections,
+# which was awkward. In 2.0, they have been made independent
+# from realms, which is better for a number of reasons.
+#
+# You can proxy to a specific home server by doing:
+#
+# update control {
+# Home-Server-Name = "name of home server"
+# }
+#
+home_server localhost {
+ #
+ # Home servers can be sent Access-Request packets
+ # or Accounting-Request packets.
+ #
+ # Allowed values are:
+ # auth - Handles Access-Request packets
+ # acct - Handles Accounting-Request packets
+ # auth+acct - Handles Access-Request packets at "port",
+ # and Accounting-Request packets at "port + 1"
+ # coa - Handles CoA-Request and Disconnect-Request packets.
+ # See also raddb/sites-available/originate-coa
+ type = auth
+
+ #
+ # Configure ONE OF the following entries:
+ #
+ # IPv4 address
+ #
+ ipaddr = 127.0.0.1
+
+ # OR IPv6 address
+ # ipv6addr = ::1
+
+ # OR virtual server
+ # virtual_server = foo
+
+ # Note that while both ipaddr and ipv6addr will accept
+ # both addresses and host names, we do NOT recommend
+ # using host names. When you specify a host name, the
+ # server has to do a DNS lookup to find the IP address
+ # of the home server. If the DNS server is slow or
+ # unresponsive, it means that FreeRADIUS will NOT be
+ # able to determine the address, and will therefore NOT
+ # start.
+ #
+ # Also, the mapping of host name to address is done ONCE
+ # when the server starts. If DNS is later updated to
+ # change the address, FreeRADIUS will NOT discover that
+ # until after a re-start, or a HUP.
+ #
+ # If you specify a virtual_server here, then requests
+ # will be proxied internally to that virtual server.
+ # These requests CANNOT be proxied again, however. The
+ # intent is to have the local server handle packets
+ # when all home servers are dead.
+ #
+ # Unlike proxying to a regular home server, requests
+ # proxied to a virtual server will be passed through
+ # pre-proxy and post-proxy sections in the
+ # destination virtual server, rather than those in
+ # the virtual server currently processing the request.
+ # See also the sample "realm" configuration, below.
+ #
+ # None of the rest of the home_server configuration is used
+ # for the "virtual_server" configuration.
+
+ #
+ # The port to which packets are sent.
+ #
+ # Usually 1812 for type "auth", and 1813 for type "acct".
+ # Older servers may use 1645 and 1646.
+ # Use 3799 for type "coa"
+ #
+ port = 1812
+
+ #
+ # The transport protocol.
+ #
+ # If unspecified, defaults to "udp", which is the traditional
+ # RADIUS transport. It may also be "tcp", in which case TCP
+ # will be used to talk to this home server.
+ #
+ # When home servers are put into pools, the pool can contain
+ # home servers with both UDP and TCP transports.
+ #
+ #proto = udp
+
+ #
+ # The shared secret use to "encrypt" and "sign" packets between
+ # FreeRADIUS and the home server.
+ #
+ # The secret can be any string, up to 8k characters in length.
+ #
+ # Control codes can be entered vi octal encoding,
+ # e.g. "\101\102" == "AB"
+ # Quotation marks can be entered by escaping them,
+ # e.g. "foo\"bar"
+ # Spaces or other "special" characters can be entered
+ # by putting quotes around the string.
+ # e.g. "foo bar"
+ # "foo;bar"
+ #
+ secret = testing123
+
+ ############################################################
+ #
+ # The rest of the configuration items listed here are optional,
+ # and do not have to appear in every home server definition.
+ #
+ ############################################################
+
+ #
+ # You can optionally specify the source IP address used when
+ # proxying requests to this home server. When the src_ipaddr
+ # it set, the server will automatically create a proxy
+ # listener for that IP address.
+ #
+ # If you specify this field for one home server, you will
+ # likely need to specify it for ALL home servers.
+ #
+ # If you don't care about the source IP address, leave this
+ # entry commented.
+ #
+# src_ipaddr = 127.0.0.1
+
+ #
+ # If the home server does not respond to a request within
+ # this time, the server marks the request as timed out.
+ # After "response_timeouts", the home server is marked
+ # as being "zombie", and "zombie_period" starts.
+ #
+ # The response window can be a number between 0.001 and 60.000
+ # Values on the low end are discouraged, as they will likely
+ # not work due to limitations of operating system timers.
+ #
+ # The default response window is large because responses may
+ # be slow, especially when proxying across the Internet.
+ #
+ # Useful range of values: 5 to 60
+ response_window = 20
+
+ #
+ # Start "zombie_period" after this many responses have
+ # timed out.
+ #
+# response_timeouts = 1
+
+ #
+ # If the home server does not respond to ANY packets during
+ # the "zombie period", it will be considered to be dead.
+ #
+ # A home server that is marked "zombie" will be used for
+ # proxying as a low priority. If there are live servers,
+ # they will always be preferred to a zombie. Requests will
+ # be proxied to a zombie server ONLY when there are no
+ # live servers.
+ #
+ # Any request that is proxied to a home server will continue
+ # to be sent to that home server until the home server is
+ # marked dead. At that point, it will fail over to another
+ # server, if a live server is available. If none is available,
+ # then the "post-proxy-type fail" handler will be called.
+ #
+ # If "status_check" below is something other than "none", then
+ # the server will start sending status checks at the start of
+ # the zombie period. It will continue sending status checks
+ # until the home server is marked "alive".
+ #
+ # Useful range of values: 20 to 120
+ zombie_period = 40
+
+ ############################################################
+ #
+ # As of 2.0, FreeRADIUS supports RADIUS layer "status
+ # checks". These are used by a proxy server to see if a home
+ # server is alive.
+ #
+ # These status packets are sent ONLY if the proxying server
+ # believes that the home server is dead. They are NOT sent
+ # if the proxying server believes that the home server is
+ # alive. They are NOT sent if the proxying server is not
+ # proxying packets.
+ #
+ # If the home server responds to the status check packet,
+ # then it is marked alive again, and is returned to use.
+ #
+ ############################################################
+
+ #
+ # Some home servers do not support status checks via the
+ # Status-Server packet. Others may not have a "test" user
+ # configured that can be used to query the server, to see if
+ # it is alive. For those servers, we have NO WAY of knowing
+ # when it becomes alive again. Therefore, after the server
+ # has been marked dead, we wait a period of time, and mark
+ # it alive again, in the hope that it has come back to
+ # life.
+ #
+ # If it has NOT come back to life, then FreeRADIUS will wait
+ # for "zombie_period" before marking it dead again. During
+ # the "zombie_period", ALL AUTHENTICATIONS WILL FAIL, because
+ # the home server is still dead. There is NOTHING that can
+ # be done about this, other than to enable the status checks,
+ # as documented below.
+ #
+ # e.g. if "zombie_period" is 40 seconds, and "revive_interval"
+ # is 300 seconds, the for 40 seconds out of every 340, or about
+ # 10% of the time, all authentications will fail.
+ #
+ # If the "zombie_period" and "revive_interval" configurations
+ # are set smaller, than it is possible for up to 50% of
+ # authentications to fail.
+ #
+ # As a result, we recommend enabling status checks, and
+ # we do NOT recommend using "revive_interval".
+ #
+ # The "revive_interval" is used ONLY if the "status_check"
+ # entry below is "none". Otherwise, it will not be used,
+ # and should be deleted.
+ #
+ # Useful range of values: 10 to 3600
+ revive_interval = 120
+
+ #
+ # The proxying server (i.e. this one) can do periodic status
+ # checks to see if a dead home server has come back alive.
+ #
+ # If set to "none", then the other configuration items listed
+ # below are not used, and the "revive_interval" time is used
+ # instead.
+ #
+ # If set to "status-server", the Status-Server packets are
+ # sent. Many RADIUS servers support Status-Server. If a
+ # server does not support it, please contact the server
+ # vendor and request that they add it. With status-server if
+ # the home server is marked as a zombie and a status-server
+ # response is received, it will be immediately marked as live.
+ #
+ # This prevents spurious failovers in federations such as
+ # eduroam, where intermediary proxy servers may be functional
+ # but the servers of a home institution may not be,
+ #
+ # If set to "request", then Access-Request, or Accounting-Request
+ # packets are sent, depending on the "type" entry above (auth/acct).
+ #
+ # Allowed values: none, status-server, request
+ status_check = status-server
+
+ #
+ # If the home server does not support Status-Server packets,
+ # then the server can still send Access-Request or
+ # Accounting-Request packets, with a pre-defined user name.
+ #
+ # This practice is NOT recommended, as it may potentially let
+ # users gain network access by using these "test" accounts!
+ #
+ # If it is used, we recommend that the home server ALWAYS
+ # respond to these Access-Request status checks with
+ # Access-Reject. The status check just needs an answer, it
+ # does not need an Access-Accept.
+ #
+ # For Accounting-Request status checks, only the username
+ # needs to be set. The rest of the accounting attribute are
+ # set to default values. The home server that receives these
+ # accounting packets SHOULD NOT treat them like normal user
+ # accounting packets. i.e It should probably NOT log them to
+ # a database.
+ #
+ # username = "test_user_please_reject_me"
+ # password = "this is really secret"
+
+ #
+ # Configure the interval between sending status check packets.
+ #
+ # Setting it too low increases the probability of spurious
+ # fail-over and fallback attempts.
+ #
+ # Useful range of values: 6 to 120
+ check_interval = 30
+
+ #
+ # Wait "check_timeout" seconds for a reply to a status check
+ # packet.
+ #
+ check_timeout = 4
+
+ #
+ # Configure the number of status checks in a row that the
+ # home server needs to respond to before it is marked alive.
+ #
+ # If you want to mark a home server as alive after a short
+ # time period of being responsive, it is best to use a small
+ # "check_interval", and a large value for
+ # "num_answers_to_alive". Using a long "check_interval" and
+ # a small number for "num_answers_to_alive" increases the
+ # probability of spurious fail-over and fallback attempts.
+ #
+ # Useful range of values: 3 to 10
+ num_answers_to_alive = 3
+
+ #
+ # Limit the total number of outstanding packets to the home
+ # server.
+ #
+ # if ((#request sent) - (#requests received)) > max_outstanding
+ # then stop sending more packets to the home server
+ #
+ # This lets us gracefully fall over when the home server
+ # is overloaded.
+ max_outstanding = 65536
+
+ #
+ # The configuration items in the next sub-section are used ONLY
+ # when "type = coa". It is ignored for all other type of home
+ # servers.
+ #
+ # See RFC 5080 for the definitions of the following terms.
+ # RAND is a function (internal to FreeRADIUS) returning
+ # random numbers between -0.1 and +0.1
+ #
+ # First Re-transmit occurs after:
+ #
+ # RT = IRT + RAND*IRT
+ #
+ # Subsequent Re-transmits occur after:
+ #
+ # RT = 2 * RTprev + RAND * RTprev
+ #
+ # Re-transmits are capped at:
+ #
+ # if (MRT && (RT > MRT)) RT = MRT + RAND * MRT
+ #
+ # For a maximum number of attempts: MRC
+ #
+ # For a maximum (total) period of time: MRD.
+ #
+ coa {
+ # Initial retransmit interval: 1..5
+ irt = 2
+
+ # Maximum Retransmit Timeout: 1..30 (0 == no maximum)
+ mrt = 16
+
+ # Maximum Retransmit Count: 1..20 (0 == retransmit forever)
+ mrc = 5
+
+ # Maximum Retransmit Duration: 5..60
+ mrd = 30
+ }
+
+ #
+ # Connection limiting for home servers with "proto = tcp".
+ #
+ # This section is ignored for other home servers.
+ #
+ limit {
+ #
+ # Limit the number of TCP connections to the home server.
+ #
+ # The default is 16.
+ # Setting this to 0 means "no limit"
+ max_connections = 16
+
+ #
+ # Limit the total number of requests sent over one
+ # TCP connection. After this number of requests, the
+ # connection will be closed. Any new packets that are
+ # proxied to the home server will result in a new TCP
+ # connection being made.
+ #
+ # Setting this to 0 means "no limit"
+ max_requests = 0
+
+ #
+ # The lifetime, in seconds, of a TCP connection. After
+ # this lifetime, the connection will be closed.
+ #
+ # Setting this to 0 means "forever".
+ lifetime = 0
+
+ #
+ # The idle timeout, in seconds, of a TCP connection.
+ # If no packets have been sent over the connection for
+ # this time, the connection will be closed.
+ #
+ # Setting this to 0 means "no timeout".
+ idle_timeout = 0
+ }
+
+}
+
+# Sample virtual home server.
+#
+#
+#home_server virtual.example.com {
+# virtual_server = virtual.example.com
+#}
+
+######################################################################
+#
+# This section defines a pool of home servers that is used
+# for fail-over and load-balancing. In earlier versions of
+# FreeRADIUS, fail-over and load-balancing were defined per-realm.
+# As a result, if a server had 5 home servers, each of which served
+# the same 10 realms, you would need 50 "realm" entries.
+#
+# In version 2.0, you would need 5 "home_server" sections,
+# 10 'realm" sections, and one "home_server_pool" section to tie the
+# two together.
+#
+# You can proxy to a specific home server pool by doing:
+#
+# update control {
+# Home-Server-Pool = "name of pool"
+# }
+#
+home_server_pool my_auth_failover {
+ #
+ # The type of this pool controls how home servers are chosen.
+ #
+ # fail-over - the request is sent to the first live
+ # home server in the list. i.e. If the first home server
+ # is marked "dead", the second one is chosen, etc.
+ #
+ # load-balance - the least busy home server is chosen,
+ # where "least busy" is counted by taking the number of
+ # requests sent to that home server, and subtracting the
+ # number of responses received from that home server.
+ #
+ # If there are two or more servers with the same low
+ # load, then one of those servers is chosen at random.
+ # This configuration is most similar to the old
+ # "round-robin" method, though it is not exactly the same.
+ #
+ # Note that load balancing does not work well with EAP,
+ # as EAP requires packets for an EAP conversation to be
+ # sent to the same home server. The load balancing method
+ # does not keep state in between packets, meaning that
+ # EAP packets for the same conversation may be sent to
+ # different home servers. This will prevent EAP from
+ # working.
+ #
+ # For non-EAP authentication methods, and for accounting
+ # packets, we recommend using "load-balance". It will
+ # ensure the highest availability for your network.
+ #
+ # client-balance - the home server is chosen by hashing the
+ # source IP address of the packet. If that home server
+ # is down, the next one in the list is used, just as
+ # with "fail-over".
+ #
+ # There is no way of predicting which source IP will map
+ # to which home server.
+ #
+ # This configuration is most useful to do simple load
+ # balancing for EAP sessions, as the EAP session will
+ # always be sent to the same home server.
+ #
+ # client-port-balance - the home server is chosen by hashing
+ # the source IP address and source port of the packet.
+ # If that home server is down, the next one in the list
+ # is used, just as with "fail-over".
+ #
+ # This method provides slightly better load balancing
+ # for EAP sessions than "client-balance". However, it
+ # also means that authentication and accounting packets
+ # for the same session MAY go to different home servers.
+ #
+ # keyed-balance - the home server is chosen by hashing (FNV)
+ # the contents of the Load-Balance-Key attribute from the
+ # control items. The request is then sent to home server
+ # chosen by taking:
+ #
+ # server = (hash % num_servers_in_pool).
+ #
+ # If there is no Load-Balance-Key in the control items,
+ # the load balancing method is identical to "load-balance".
+ #
+ # For most non-EAP authentication methods, The User-Name
+ # attribute provides a good key. An "unlang" policy can
+ # be used to copy the User-Name to the Load-Balance-Key
+ # attribute. This method may not work for EAP sessions,
+ # as the User-Name outside of the TLS tunnel is often
+ # static, e.g. "anonymous@realm".
+ #
+ #
+ # The default type is fail-over.
+ type = fail-over
+
+ #
+ # A virtual_server may be specified here. If so, the
+ # "pre-proxy" and "post-proxy" sections from the destination
+ # virtual server are run when the request is proxied and when
+ # a response is received.
+ #
+ # This lets you have one policy for all requests that are proxied
+ # to a home server. This policy is completely independent of
+ # any policies used to receive, or process the request.
+ #
+ #virtual_server = pre_post_proxy_for_pool
+
+ #
+ # Next, a list of one or more home servers. The names
+ # of the home servers are NOT the hostnames, but the names
+ # of the sections. (e.g. home_server foo {...} has name "foo".
+ #
+ # Note that ALL home servers listed here have to be of the same
+ # type. i.e. they all have to be "auth", or they all have to
+ # be "acct", or the all have to be "auth+acct".
+ #
+ home_server = localhost
+
+ # Additional home servers can be listed.
+ # There is NO LIMIT to the number of home servers that can
+ # be listed, though using more than 10 or so will become
+ # difficult to manage.
+ #
+ # home_server = foo.example.com
+ # home_server = bar.example.com
+ # home_server = baz.example.com
+ # home_server = ...
+
+
+ #
+ # If ALL home servers are dead, then this "fallback" home server
+ # is used. If set, it takes precedence over any realm-based
+ # fallback, such as the DEFAULT realm.
+ #
+ # For reasons of stability, this home server SHOULD be a virtual
+ # server. Otherwise, the fallback may itself be dead!
+ #
+ # Note: When packets are proxied to this fallback home server,
+ # if it is a virtual server, the pre-proxy and post-proxy sections
+ # from the destination virtual server will be run instead of those
+ # in the current virtual server.
+ #
+ #fallback = virtual.example.com
+}
+
+######################################################################
+#
+#
+# This section defines a new-style "realm". Note the in version 2.0,
+# there are many fewer configuration items than in 1.x for a realm.
+#
+# Automatic proxying is done via the "realms" module (see "man
+# rlm_realm"). To manually proxy the request put this entry in the
+# "users" file:
+
+#
+#
+#DEFAULT Proxy-To-Realm := "realm_name"
+#
+#
+realm example.com {
+ #
+ # Realms point to pools of home servers.
+#
+ # For authentication, the "auth_pool" configuration item
+ # should point to a "home_server_pool" that was previously
+ # defined. All of the home servers in the "auth_pool" must
+ # be of type "auth".
+ #
+ # For accounting, the "acct_pool" configuration item
+ # should point to a "home_server_pool" that was previously
+ # defined. All of the home servers in the "acct_pool" must
+ # be of type "acct".
+ #
+ # If you have a "home_server_pool" where all of the home servers
+ # are of type "auth+acct", you can just use the "pool"
+ # configuration item, instead of specifying both "auth_pool"
+ # and "acct_pool".
+
+ auth_pool = my_auth_failover
+# acct_pool = acct
+
+ # The server can proxy CoA packets based on the Operator-Name
+ # attribute. This requires that the "suffix" module be
+ # listed in the "recv-coa" section.
+ #
+ # See raddb/sites-available/coa
+ #
+# coa_pool = name_of_coa_pool
+
+ #
+ # Normally, when an incoming User-Name is matched against the
+ # realm, the realm name is "stripped" off, and the "stripped"
+ # user name is used to perform matches.
+ #
+ # e.g. User-Name = "bob@example.com" will result in two new
+ # attributes being created by the "realms" module:
+ #
+ # Stripped-User-Name = "bob"
+ # Realm = "example.com"
+ #
+ # The Stripped-User-Name is then used as a key in the "users"
+ # file, for example.
+ #
+ # If you do not want this to happen, uncomment "nostrip" below.
+ #
+ # Note that if the system is doing EAP, you MUST set the "nostrip"
+ # option for realms used in EAP. Otherwise EAP will fail.
+ #
+ # nostrip
+
+ # There are no more configuration entries for a realm.
+}
+
+
+#
+# This is a sample entry for iPass.
+# Note that you have to define "ipass_auth_pool" and
+# "ipass_acct_pool", along with home_servers for them, too.
+#
+#realm IPASS {
+# nostrip
+#
+# auth_pool = ipass_auth_pool
+# acct_pool = ipass_acct_pool
+#}
+
+#
+# This realm is used mainly to cancel proxying. You can have
+# the "realm suffix" module configured to proxy all requests for
+# a realm, and then later cancel the proxying, based on other
+# configuration.
+#
+# For example, you want to terminate PEAP or EAP-TTLS locally,
+# you can add the following to the "users" file:
+#
+# DEFAULT EAP-Type == PEAP, Proxy-To-Realm := LOCAL
+#
+realm LOCAL {
+ # If we do not specify a server pool, the realm is LOCAL, and
+ # requests are not proxied to it.
+}
+
+#
+# This realm is for requests which don't have an explicit realm
+# prefix or suffix. User names like "bob" will match this one.
+#
+#realm NULL {
+# authhost = radius.example.com:1600
+# accthost = radius.example.com:1601
+# secret = testing123
+#}
+
+#
+# This realm is for ALL OTHER requests.
+#
+#realm DEFAULT {
+# authhost = radius.example.com:1600
+# accthost = radius.example.com:1601
+# secret = testing123
+#}
+
+
+# This realm "proxies" requests internally to a virtual server.
+# The pre-proxy and post-proxy sections from the destination
+# virtual server are run rather than those in the current
+# virtual server. The destination virtual server then receives
+# the request, and replies, just as with any other packet.
+#
+# Once proxied internally like this, the request CANNOT be proxied
+# internally or externally.
+#
+# Realms are almost always domain names, and therefore realm names
+# are compared in a case-insensitive fashion.
+#
+#realm virtual.example.com {
+# virtual_server = virtual.example.com
+#}
+#
+
+#
+# Regular expressions may also be used as realm names. If these are used,
+# then the "find matching realm" process is as follows:
+#
+# 1) Look for a non-regex realm with an *exact* match for the name.
+# If found, it is used in preference to any regex matching realm.
+#
+# 2) Look for a regex realm, in the order that they are listed
+# in the configuration files. Any regex match is performed in
+# a case-insensitive fashion.
+#
+# 3) If no realm is found, return the DEFAULT realm, if any.
+#
+# The order of the realms matters in step (2). For example, defining
+# two realms ".*\.example.net$" and ".*\.test\.example\.net$" will result in
+# the second realm NEVER matching. This is because all of the realms
+# which match the second regex also match the first one. Since the
+# first regex matches, it is returned.
+#
+# The solution is to list the realms in the opposite order,. e.g.
+# ".*\.test\.example.net$", followed by ".*\.example\.net$".
+#
+#
+# Some helpful rules:
+#
+# - always place a '~' character at the start of the realm name.
+# This signifies that it is a regex match, and not an exact match
+# for the realm.
+#
+# - place the regex in double quotes. This helps the configuration
+# file parser ignore any "special" characters in the regex.
+# Yes, this rule is different than the normal "unlang" rules for
+# regular expressions. That may be fixed in a future release.
+#
+# - If you are matching domain names, put a '$' at the end of the regex
+# that matches the domain name. This tells the regex matching code
+# that the realm ENDS with the domain name, so it does not match
+# realms with the domain name in the middle. e.g. "~.*\.example\.net"
+# will match "test.example.netFOO", which is likely not what you want.
+# Using "~(.*\.)example\.net$" is better.
+#
+# The more regex realms that are defined, the more time it takes to
+# process them. You should define as few regex realms as possible
+# in order to maximize server performance.
+#
+#realm "~(.*\.)*example\.net$" {
+# auth_pool = my_auth_failover
+#}
diff --git a/raddb/radiusd.conf.in b/raddb/radiusd.conf.in
new file mode 100644
index 0000000..366dce4
--- /dev/null
+++ b/raddb/radiusd.conf.in
@@ -0,0 +1,902 @@
+# -*- text -*-
+##
+## radiusd.conf -- FreeRADIUS server configuration file - @RADIUSD_VERSION_STRING@
+##
+## http://www.freeradius.org/
+## $Id$
+##
+
+######################################################################
+#
+# The format of this (and other) configuration file is
+# documented in "man unlang". There are also READMEs in many
+# subdirectories:
+#
+# raddb/README.rst
+# How to upgrade from v2.
+#
+# raddb/mods-available/README.rst
+# How to use mods-available / mods-enabled.
+# All of the modules are in individual files,
+# along with configuration items and full documentation.
+#
+# raddb/sites-available/README
+# virtual servers, "listen" sections, clients, etc.
+# The "sites-available" directory contains many
+# worked examples of common configurations.
+#
+# raddb/certs/README.md
+# How to create certificates for EAP or RadSec.
+#
+# Every configuration item in the server is documented
+# extensively in the comments in the example configuration
+# files.
+#
+# Before editing this (or any other) configuration file, PLEASE
+# read "man radiusd". See the section titled DEBUGGING. It
+# outlines a method where you can quickly create the
+# configuration you want, with minimal effort.
+#
+# Run the server in debugging mode, and READ the output.
+#
+# $ radiusd -X
+#
+# We cannot emphasize this point strongly enough. The vast
+# majority of problems can be solved by carefully reading the
+# debugging output, which includes warnings about common issues,
+# and suggestions for how they may be fixed.
+#
+# There may be a lot of output, but look carefully for words like:
+# "warning", "error", "reject", or "failure". The messages there
+# will usually be enough to guide you to a solution.
+#
+# More documentation on "radiusd -X" is available on the wiki:
+# https://wiki.freeradius.org/radiusd-X
+#
+# If you are going to ask a question on the mailing list, then
+# explain what you are trying to do, and include the output from
+# debugging mode (radiusd -X). Failure to do so means that all
+# of the responses to your question will be people telling you
+# to "post the output of radiusd -X".
+#
+# Guidelines for posting to the mailing list are on the wiki:
+# https://wiki.freeradius.org/list-help
+#
+# Please read those guidelines before posting to the list.
+#
+# Further documentation is available in the "doc" directory
+# of the server distribution, or on the wiki at:
+# https://wiki.freeradius.org/
+#
+# New users to RADIUS should read the Technical Guide. That guide
+# explains how RADIUS works, how FreeRADIUS works, and what each
+# part of a RADIUS system does. It is not just "configure FreeRADIUS"!
+# https://networkradius.com/doc/FreeRADIUS-Technical-Guide.pdf
+#
+# More documentation on dictionaries, modules, unlang, etc. is also
+# available on the Network RADIUS web site:
+# https://networkradius.com/freeradius-documentation/
+#
+
+######################################################################
+
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+sysconfdir = @sysconfdir@
+localstatedir = @localstatedir@
+sbindir = @sbindir@
+logdir = @logdir@
+raddbdir = @raddbdir@
+radacctdir = @radacctdir@
+
+#
+# name of the running server. See also the "-n" command-line option.
+name = radiusd
+
+# Location of config and logfiles.
+confdir = ${raddbdir}
+modconfdir = ${confdir}/mods-config
+certdir = ${confdir}/certs
+cadir = ${confdir}/certs
+run_dir = ${localstatedir}/run/${name}
+
+# Should likely be ${localstatedir}/lib/radiusd
+db_dir = ${raddbdir}
+
+#
+# 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 = @libdir@
+
+# 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}/${name}.pid
+
+# panic_action: Command to execute if the server dies unexpectedly.
+#
+# FOR PRODUCTION SYSTEMS, ACTIONS SHOULD ALWAYS EXIT.
+# AN INTERACTIVE ACTION MEANS THE SERVER IS NOT RESPONDING TO REQUESTS.
+# AN INTERACTICE ACTION MEANS THE SERVER WILL NOT RESTART.
+#
+# THE SERVER MUST NOT BE ALLOWED EXECUTE UNTRUSTED PANIC ACTION CODE
+# PATTACH CAN BE USED AS AN ATTACK VECTOR.
+#
+# The panic action is a command which will be executed if the server
+# receives a fatal, non user generated signal, i.e. SIGSEGV, SIGBUS,
+# SIGABRT or SIGFPE.
+#
+# This can be used to start an interactive debugging session so
+# that information regarding the current state of the server can
+# be acquired.
+#
+# The following string substitutions are available:
+# - %e The currently executing program e.g. /sbin/radiusd
+# - %p The PID of the currently executing program e.g. 12345
+#
+# Standard ${} substitutions are also allowed.
+#
+# An example panic action for opening an interactive session in GDB would be:
+#
+#panic_action = "gdb %e %p"
+#
+# Again, don't use that on a production system.
+#
+# An example panic action for opening an automated session in GDB would be:
+#
+#panic_action = "gdb -silent -x ${raddbdir}/panic.gdb %e %p 2>&1 | tee ${logdir}/gdb-${name}-%p.log"
+#
+# That command can be used on a production system.
+#
+
+# max_request_time: The maximum time (in seconds) to handle a request.
+#
+# Requests which take more time than this to process may be killed, and
+# 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 30
+#
+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 = 16384
+
+# 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
+
+#
+# Run a "Post-Auth-Type Client-Lost" section. This ONLY happens when
+# the server sends an Access-Challenge, and then client does not
+# respond to it. The goal is to allow administrators to log
+# something when the client does not respond.
+#
+# See sites-available/default, "Post-Auth-Type Client-Lost" for more
+# information.
+#
+#postauth_client_lost = no
+
+#
+# Logging section. The various "log_*" configuration items
+# will eventually be moved here.
+#
+log {
+ #
+ # Destination for log messages. This can be one of:
+ #
+ # files - log to "file", as defined below.
+ # syslog - to syslog (see also the "syslog_facility", below.
+ # stdout - standard output
+ # stderr - standard error.
+ #
+ # The command-line option "-X" over-rides this option, and forces
+ # logging to go to stdout.
+ #
+ destination = files
+
+ #
+ # Highlight important messages sent to stderr and stdout.
+ #
+ # Option will be ignored (disabled) if output if TERM is not
+ # an xterm or output is not to a TTY.
+ #
+ colourise = yes
+
+ #
+ # The logging messages for the server are appended to the
+ # tail of this file if destination == "files"
+ #
+ # If the server is running in debugging mode, this file is
+ # NOT used.
+ #
+ file = ${logdir}/radius.log
+
+ #
+ # Which syslog facility to use, if ${destination} == "syslog"
+ #
+ # The exact values permitted here are OS-dependent. You probably
+ # don't want to change this.
+ #
+ syslog_facility = daemon
+
+ # Log the full User-Name attribute, as it was found in the request.
+ #
+ # allowed values: {no, yes}
+ #
+ stripped_names = no
+
+ # Log all (accept and reject) authentication results to the log file.
+ #
+ # This is the same as setting "auth_accept = yes" and
+ # "auth_reject = yes"
+ #
+ # allowed values: {no, yes}
+ #
+ auth = no
+
+ # Log Access-Accept results to the log file.
+ #
+ # This is only used if "auth = no"
+ #
+ # allowed values: {no, yes}
+ #
+# auth_accept = no
+
+ # Log Access-Reject results to the log file.
+ #
+ # This is only used if "auth = no"
+ #
+ # allowed values: {no, yes}
+ #
+# auth_reject = no
+
+ # Log passwords with the authentication requests.
+ # auth_badpass - logs password if it's rejected
+ # auth_goodpass - logs password if it's correct
+ #
+ # allowed values: {no, yes}
+ #
+ auth_badpass = no
+ auth_goodpass = no
+
+ # Log additional text at the end of the "Login OK" messages.
+ # for these to work, the "auth" and "auth_goodpass" or "auth_badpass"
+ # configurations above have to be set to "yes".
+ #
+ # The strings below are dynamically expanded, which means that
+ # you can put anything you want in them. However, note that
+ # this expansion can be slow, and can negatively impact server
+ # performance.
+ #
+# msg_goodpass = ""
+# msg_badpass = ""
+
+ # The message when the user exceeds the Simultaneous-Use limit.
+ #
+ msg_denied = "You are already logged in - access denied"
+
+ # Suppress "secret" attributes when printing them in debug mode.
+ #
+ # Secrets are NOT tracked across xlat expansions. If your
+ # configuration puts secrets into other strings, they will
+ # still get printed.
+ #
+ # Setting this to "yes" means that the server prints
+ #
+ # <<< secret >>>
+ #
+ # instead of the value, for attriburtes which contain secret
+ # information. e.g. User-Name, Tunnel-Password, etc.
+ #
+ # This configuration is disabled by default. It is extremely
+ # important for administrators to be able to debug user logins
+ # by seeing what is actually being sent.
+ #
+# suppress_secrets = no
+}
+
+# The program to execute to do concurrency checks.
+checkrad = ${sbindir}/checkrad
+
+#
+# ENVIRONMENT VARIABLES
+#
+# You can reference environment variables using an expansion like
+# `$ENV{PATH}`. However it is sometimes useful to be able to also set
+# environment variables. This section lets you do that.
+#
+# The main purpose of this section is to allow administrators to keep
+# RADIUS-specific configuration in the RADIUS configuration files.
+# For example, if you need to set an environment variable which is
+# used by a module. You could put that variable into a shell script,
+# but that's awkward. Instead, just list it here.
+#
+# Note that these environment variables are set AFTER the
+# configuration file is loaded. So you cannot set FOO here, and
+# expect to reference it via `$ENV{FOO}` in another configuration file.
+# You should instead just use a normal configuration variable for
+# that.
+#
+ENV {
+ #
+ # Set environment varable `FOO` to value '/bar/baz'.
+ #
+ # NOTE: Note that you MUST use '='. You CANNOT use '+=' to append
+ # values.
+ #
+# FOO = '/bar/baz'
+
+ #
+ # Delete environment variable `BAR`.
+ #
+# BAR
+
+ #
+ # `LD_PRELOAD` is special. It is normally set before the
+ # application runs, and is interpreted by the dynamic linker.
+ # Which means you cannot set it inside of an application, and
+ # expect it to load libraries.
+ #
+ # Since this functionality is useful, we extend it here.
+ #
+ # You can set
+ #
+ # LD_PRELOAD = /path/to/library.so
+ #
+ # and the server will load the named libraries. Multiple
+ # libraries can be loaded by specificing multiple individual
+ # `LD_PRELOAD` entries.
+ #
+ #
+# LD_PRELOAD = /path/to/library1.so
+# LD_PRELOAD = /path/to/library2.so
+}
+
+# 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 {
+ # chroot: directory where the server does "chroot".
+ #
+ # The chroot is done very early in the process of starting
+ # the server. After the chroot has been performed it
+ # switches to the "user" listed below (which MUST be
+ # specified). If "group" is specified, it switches to that
+ # group, too. Any other groups listed for the specified
+ # "user" in "/etc/group" are also added as part of this
+ # process.
+ #
+ # The current working directory (chdir / cd) is left
+ # *outside* of the chroot until all of the modules have been
+ # initialized. This allows the "raddb" directory to be left
+ # outside of the chroot. Once the modules have been
+ # initialized, it does a "chdir" to ${logdir}. This means
+ # that it should be impossible to break out of the chroot.
+ #
+ # If you are worried about security issues related to this
+ # use of chdir, then simply ensure that the "raddb" directory
+ # is inside of the chroot, and be sure to do "cd raddb"
+ # BEFORE starting the server.
+ #
+ # If the server is statically linked, then the only files
+ # that have to exist in the chroot are ${run_dir} and
+ # ${logdir}. If you do the "cd raddb" as discussed above,
+ # then the "raddb" directory has to be inside of the chroot
+ # directory, too.
+ #
+# chroot = /path/to/chroot/directory
+
+ # 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
+ # privileges ) 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 radius'.
+ #
+ # 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.
+ #
+ # The server will also try to use "initgroups" to read
+ # /etc/groups. It will join all groups where "user" is a
+ # member. This can allow for some finer-grained access
+ # controls.
+ #
+# user = radius
+# group = radius
+
+ # 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 = no
+
+ #
+ # 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.
+ #
+ # This number can be a decimal, e.g. 3.4
+ #
+ # Useful ranges: 1 to 5
+ reject_delay = 1
+
+ #
+ # status_server: Whether or not the server will respond
+ # to Status-Server requests.
+ #
+ # When sent a Status-Server message, the server responds with
+ # an Access-Accept or Accounting-Response packet.
+ #
+ # This is mainly useful for administrators who want to "ping"
+ # the server, without adding test users, or creating fake
+ # accounting packets.
+ #
+ # It's also useful when a NAS marks a RADIUS server "dead".
+ # The NAS can periodically "ping" the server with a Status-Server
+ # packet. If the server responds, it must be alive, and the
+ # NAS can start using it for real requests.
+ #
+ # See also raddb/sites-available/status
+ #
+ status_server = yes
+
+@openssl_version_check_config@
+}
+
+# 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 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 clients.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
+
+ # When the server receives a packet, it places it onto an
+ # internal queue, where the worker threads (configured above)
+ # pick it up for processing. The maximum size of that queue
+ # is given here.
+ #
+ # When the queue is full, any new packets will be silently
+ # discarded.
+ #
+ # The most common cause of the queue being full is that the
+ # server is dependent on a slow database, and it has received
+ # a large "spike" of traffic. When that happens, there is
+ # very little you can do other than make sure the server
+ # receives less traffic, or make sure that the database can
+ # handle the load.
+ #
+# max_queue_size = 65536
+
+ # Clean up old threads periodically. For no reason other than
+ # it might be useful.
+ #
+ # '0' is a special value meaning 'infinity', or 'the servers never
+ # exit'
+ max_requests_per_server = 0
+
+ # Automatically limit the number of accounting requests.
+ # This configuration item tracks how many requests per second
+ # the server can handle. It does this by tracking the
+ # packets/s received by the server for processing, and
+ # comparing that to the packets/s handled by the child
+ # threads.
+ #
+
+ # If the received PPS is larger than the processed PPS, *and*
+ # the queue is more than half full, then new accounting
+ # requests are probabilistically discarded. This lowers the
+ # number of packets that the server needs to process. Over
+ # time, the server will "catch up" with the traffic.
+ #
+ # Throwing away accounting packets is usually safe and low
+ # impact. The NAS will retransmit them in a few seconds, or
+ # even a few minutes. Vendors should read RFC 5080 Section 2.2.1
+ # to see how accounting packets should be retransmitted. Using
+ # any other method is likely to cause network meltdowns.
+ #
+ auto_limit_acct = no
+}
+
+######################################################################
+#
+# SNMP notifications. Uncomment the following line to enable
+# snmptraps. Note that you MUST also configure the full path
+# to the "snmptrap" command in the "trigger.conf" file.
+#
+#$INCLUDE trigger.conf
+
+# 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
+ # for an example.
+ #
+
+ #
+ # Some modules have ordering issues. e.g. "sqlippool" uses
+ # the configuration from "sql". In that case, the "sql"
+ # module must be read off of disk before the "sqlippool".
+ # However, the directory inclusion below just reads the
+ # directory from start to finish. Which means that the
+ # modules are read off of disk randomly.
+ #
+ # You can list individual modules *before* the directory
+ # inclusion. Those modules will be loaded first. Then, when
+ # the directory is read, those modules will be skipped and
+ # not read twice.
+ #
+# $INCLUDE mods-enabled/sql
+
+ #
+ # All modules are in ther mods-enabled/ directory. Files
+ # matching the regex /[a-zA-Z0-9_.]+/ are read. The
+ # modules are initialized ONLY if they are referenced in a
+ # processing section, such as authorize, authenticate,
+ # accounting, pre/post-proxy, etc.
+ #
+ $INCLUDE mods-enabled/
+}
+
+# Instantiation
+#
+# This section sets the instantiation order of the modules. listed
+# here will get started up BEFORE the sections like authorize,
+# authenticate, etc. get examined.
+#
+# This section is not strictly needed. When a section like authorize
+# refers to a module, the module is automatically loaded and
+# initialized. However, some modules may not be listed in any of the
+# processing sections, so they should be listed here.
+#
+# Also, listing modules here ensures that you have control over
+# the order in which they are initialized. If one module needs
+# something defined by another module, you can list them in order
+# here, and ensure that the configuration will be OK.
+#
+# After the modules listed here have been loaded, all of the modules
+# in the "mods-enabled" directory will be loaded. Loading the
+# "mods-enabled" directory means that unlike Version 2, you usually
+# don't need to list modules here.
+#
+instantiate {
+ #
+ # We list the counter module here so that it registers
+ # the check_name attribute before any module which sets
+ # it
+# daily
+
+ # subsections here can be thought of as "virtual" modules.
+ #
+ # e.g. If you have two redundant SQL servers, and you want to
+ # use them in the authorize and accounting sections, you could
+ # place a "redundant" block in each section, containing the
+ # exact same text. Or, you could uncomment the following
+ # lines, and list "redundant_sql" in the authorize and
+ # accounting sections.
+ #
+ # The "virtual" module defined here can also be used with
+ # dynamic expansions, under a few conditions:
+ #
+ # * The section is "redundant", or "load-balance", or
+ # "redundant-load-balance"
+ # * The section contains modules ONLY, and no sub-sections
+ # * all modules in the section are using the same rlm_
+ # driver, e.g. They are all sql, or all ldap, etc.
+ #
+ # When those conditions are satisfied, the server will
+ # automatically register a dynamic expansion, using the
+ # name of the "virtual" module. In the example below,
+ # it will be "redundant_sql". You can then use this expansion
+ # just like any other:
+ #
+ # update reply {
+ # Filter-Id := "%{redundant_sql: ... }"
+ # }
+ #
+ # In this example, the expansion is done via module "sql1",
+ # and if that expansion fails, using module "sql2".
+ #
+ # For best results, configure the "pool" subsection of the
+ # module so that "retry_delay" is non-zero. That will allow
+ # the redundant block to quickly ignore all "down" SQL
+ # databases. If instead we have "retry_delay = 0", then
+ # every time the redundant block is used, the server will try
+ # to open a connection to every "down" database, causing
+ # problems.
+ #
+ #redundant redundant_sql {
+ # sql1
+ # sql2
+ #}
+}
+
+######################################################################
+#
+# Policies are virtual modules, similar to those defined in the
+# "instantiate" section above.
+#
+# Defining a policy in one of the policy.d files means that it can be
+# referenced in multiple places as a *name*, rather than as a series of
+# conditions to match, and actions to take.
+#
+# Policies are something like subroutines in a normal language, but
+# they cannot be called recursively. They MUST be defined in order.
+# If policy A calls policy B, then B MUST be defined before A.
+#
+######################################################################
+policy {
+ $INCLUDE policy.d/
+}
+
+######################################################################
+#
+# Load virtual servers.
+#
+# This next $INCLUDE line loads files in the directory that
+# match the regular expression: /[a-zA-Z0-9_.]+/
+#
+# It allows you to define new virtual servers simply by placing
+# a file into the raddb/sites-enabled/ directory.
+#
+$INCLUDE sites-enabled/
+
+######################################################################
+#
+# All of the other configuration sections like "authorize {}",
+# "authenticate {}", "accounting {}", have been moved to the
+# the file:
+#
+# raddb/sites-available/default
+#
+# This is the "default" virtual server that has the same
+# configuration as in version 1.0.x and 1.1.x. The default
+# installation enables this virtual server. You should
+# edit it to create policies for your local site.
+#
+# For more documentation on virtual servers, see:
+#
+# raddb/sites-available/README
+#
+######################################################################
diff --git a/raddb/radrelay.conf.in b/raddb/radrelay.conf.in
new file mode 100644
index 0000000..b707b34
--- /dev/null
+++ b/raddb/radrelay.conf.in
@@ -0,0 +1,170 @@
+# -*- text -*-
+##
+## radrelay.conf -- FreeRADIUS server configuration file.
+##
+## Use with: radiusd -n radrelay
+##
+## http://www.freeradius.org/
+## $Id$
+##
+
+######################################################################
+#
+# This file is a sample configuration that replaces the old
+# "radrelay" program. It is a *minimal* configuration that
+# does little more than read the detail file, and proxy the
+# packets to a home server. If you need it to do more than
+# just replace radrelay, you will need to add additional
+# configuration.
+#
+# See raddb/sites-available/copy-acct-to-home-server for a
+# more complete example. That example is intended to be run
+# as part of a larger radius configuration, where the server
+# also listens on ports 1812, etc. The example given here
+# is a minimal example that has ONLY radrelay functionality.
+#
+# See radiusd.conf for a complete description of the configuration
+# parameters used here.
+#
+######################################################################
+
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+sysconfdir = @sysconfdir@
+localstatedir = @localstatedir@
+sbindir = @sbindir@
+logdir = @logdir@
+raddbdir = @raddbdir@
+radacctdir = @radacctdir@
+
+#
+# name of the running server. See also the "-n" command-line option.
+#
+name = radrelay
+
+#
+# Generic configuration
+#
+confdir = ${raddbdir}
+run_dir = ${localstatedir}/run/${name}
+libdir = @libdir@
+pidfile = ${run_dir}/${name}.pid
+
+#
+# Request handling configuration
+#
+max_request_time = 30
+cleanup_delay = 5
+max_requests = 65536
+
+#
+# Logging section.
+#
+log {
+ destination = files
+ file = ${logdir}/${name}.log
+}
+
+#
+# Security configuration
+#
+security {
+ max_attributes = 200
+
+ # reject_delay && status_server don't apply when we are
+ # only reading accounting packets from the detail file
+
+@openssl_version_check_config@
+}
+
+#
+# If you need more modules, add them here.
+#
+modules {
+ $INCLUDE ${confdir}/mods-enabled/always
+}
+
+#
+# If you need to instantiate modules, add them here.
+#
+instantiate {
+}
+
+#
+# Configuration of home servers, etc.
+#
+proxy_requests = yes
+
+#
+# See proxy.conf for additional home server configuration.
+#
+home_server home1 {
+ type = acct
+
+ #
+ # This directive replaces the "-r" command-line option
+ # in radrelay
+ #
+ ipaddr = 192.0.2.20
+
+ port = 1812
+
+ #
+ # This directive replaces the "-i" command-line option
+ # in radrelay
+ #
+# src_ipaddr = 192.0.2.1
+
+ #
+ # This directive replaces the "-s", "-S", and "-n" command-line
+ # options in radrelay
+ #
+ secret = testing123
+}
+
+#
+# List one or more home servers here for fail-over, load-balancing, etc.
+#
+home_server_pool radrelay {
+ type = fail-over
+ home_server = home1
+}
+
+#
+# A dummy realm.
+#
+realm radrelay {
+ acct_pool = radrelay
+}
+
+server radrelay {
+ #
+ # Read the detail file.
+ #
+ listen {
+ type = detail
+
+ #
+ # The filename here should be the same as the one used by the
+ # main radiusd program. It writes the file using the "detail"
+ # module (see raddb/modules/detail).
+ #
+ filename = ${radacctdir}/detail
+ load_factor = 90
+ }
+
+ #
+ # See also raddb/sites-available/copy-acct-to-home-server
+ # for additional description.
+ #
+ preacct {
+ #
+ # Proxy the packet using the given realm.
+ # Note that we do not use the realm for anything else such
+ # as prefix/suffix stripping or comparisons.
+ #
+ update control {
+ Proxy-To-Realm := "radrelay"
+ }
+ }
+}
diff --git a/raddb/sites-available/README b/raddb/sites-available/README
new file mode 100644
index 0000000..0805a75
--- /dev/null
+++ b/raddb/sites-available/README
@@ -0,0 +1,333 @@
+1. Virtual Servers.
+
+ FreeRADIUS supports virtual servers. The virtual servers do NOT have
+to be set up with the "sites-available" and "sites-enabled"
+directories. You can still have one "radiusd.conf" file, and put the
+server configuration there:
+
+ ...
+ server {
+ authorize {
+ ...
+ }
+ authenticate {
+ ...
+ }
+ ...
+ }
+ ...
+
+ The power of virtual servers lies in their ability to separate
+policies. A policy can be placed into a virtual server, where it is
+guaranteed to affect only the requests that are passed through that
+virtual server. In 1.x, the policies were global, and it sometimes
+took much effort to write a policy so that it only applied in certain
+limited situations.
+
+
+2. What do we mean by "virtual server"?
+
+
+ A virtual server is a (nearly complete) RADIUS server, just like a
+configuration for FreeRADIUS 1.x. However, FreeRADIUS can now run
+multiple virtual servers at the same time. The virtual servers can
+even proxy requests to each other!
+
+ The simplest way to create a virtual server is to take the all of
+the request processing sections from radius.conf, ("authorize" ,
+"authenticate", etc.) and wrap them in a "server {}" block, as above.
+
+ You can create another virtual server by:
+
+ 1) defining a new "server foo {...}" section in radiusd.conf
+ 2) Putting the normal "authorize", etc. sections inside of it
+ 3) Adding a "listen" section *inside* of the "server" section.
+
+ e.g.
+
+ ...
+ server foo {
+ listen {
+ ipaddr = 127.0.0.1
+ port = 2000
+ type = auth
+ }
+
+ authorize {
+ update control {
+ Cleartext-Password := "bob"
+ }
+ pap
+ }
+
+ authenticate {
+ pap
+ }
+ }
+ ...
+
+ With that text added to "radiusd.conf", run the server in debugging
+mode (radiusd -X), and in another terminal window, type:
+
+$ radtest bob bob localhost:2000 0 testing123
+
+ You should see the server return an Access-Accept.
+
+
+3. Capabilities and limitations
+
+
+ The only sub-sections that can appear in a virtual server section
+are:
+
+ listen
+ client
+ authorize
+ authenticate
+ post-auth
+ pre-proxy
+ post-proxy
+ preacct
+ accounting
+ session
+
+ All other configuration parameters (modules, etc.) are global.
+
+ Inside of a virtual server, the authorize, etc. sections have their
+normal meaning, and can contain anything that an authorize section
+could contain in 1.x.
+
+ When a "listen" section is inside of a virtual server definition, it
+means that all requests sent to that IP/port will be processed through
+the virtual server. There cannot be two "listen" sections with the
+same IP address and port number.
+
+ When a "client" section is inside of a virtual server definition, it
+means that that client is known only to the "listen" sections that are
+also inside of that virtual server. Not only is this client
+definition available only to this virtual server, but the details of
+the client configuration is also available only to this virtual
+server.
+
+ i.e. Two virtual servers can listen on different IP address and
+ports, but both can have a client with IP address 127.0.0.1. The
+shared secret for that client can be different for each virtual
+server.
+
+
+4. More complex "listen" capabilities
+
+ The "listen" sections have a few additional configuration items that
+were not in 1.x, and were not mentioned above. These configuration
+items enable almost any mapping of IP / port to clients to virtual
+servers.
+
+ The configuration items are:
+
+ virtual_server = <name>
+
+ If set, all requests sent to this IP / port are processed
+ through the named virtual server.
+
+ This directive can be used only for "listen" sections
+ that are global. i.e. It CANNOT be used if the
+ "listen" section is inside of a virtual server.
+
+ clients = <name>
+
+ If set, the "listen" section looks for a "clients" section:
+
+ clients <name> {
+ ...
+ }
+
+ It looks inside of that named "clients" section for
+ "client" subsections, at least one of which must
+ exist. Each client in that section is added to the
+ list of known clients for this IP / port. No other
+ clients are known.
+
+ If it is set, it over-rides the list of clients (if
+ any) in the same virtual server. Note that the
+ clients are NOT additive!
+
+ If it is not set, then the clients from the current
+ virtual server (if any) are used. If there are no
+ clients in this virtual server, then the global
+ clients are used.
+
+ i.e. The most specific directive is used:
+ * configuration in this "listen" section
+ * clients in the same virtual server
+ * global clients
+
+ The directives are also *exclusive*, not *additive*.
+ If you have one client in a virtual server, and
+ another client referenced from a "listen" section,
+ then that "listen" section will ONLY use the second
+ client. It will NOT use both clients.
+
+
+5. More complex "client" capabilities
+
+ The "client" sections have a few additional configuration items that
+were not in 1.x, and were not mentioned above. These configuration
+items enable almost any mapping of IP / port to clients to virtual
+servers.
+
+ The configuration items are:
+
+ virtual_server = <name>
+
+ If set, all requests from this client are processed
+ through the named virtual server.
+
+ This directive can be used only for "client" sections
+ that are global. i.e. It CANNOT be used if the
+ "client" section is inside of a virtual server.
+
+ If the "listen" section has a "server" entry, and a matching
+client is found ALSO with a "server" entry, then the clients server is
+used for that request.
+
+
+6. Worked examples
+
+
+ Listening on one socket, and mapping requests from two clients to
+two different servers.
+
+ listen {
+ ...
+ }
+ client one {
+ ...
+ virtual_server = server_one
+ }
+ client two {
+ ...
+ virtual_server = server_two
+ }
+ server server_one {
+ authorize {
+ ...
+ }
+ ...
+ }
+ server server_two {
+ authorize {
+ ...
+ }
+ ...
+ }
+
+ This could also be done as:
+
+
+ listen {
+ ...
+ virtual_server = server_one
+ }
+ client one {
+ ...
+ }
+ client two {
+ ...
+ virtual_server = server_two
+ }
+ server server_one {
+ authorize {
+ ...
+ }
+ ...
+ }
+ server server_two {
+ authorize {
+ ...
+ }
+ ...
+ }
+
+ In this case, the default server for the socket is "server_one", so
+there is no need to set that in the client "one" configuration. The
+"server_two" configuration for client "two" over-rides the default
+setting for the socket.
+
+ Note that the following configuration will NOT work:
+
+ listen {
+ ...
+ virtual_server = server_one
+ }
+ client one {
+ ...
+ }
+ server server_one {
+ authorize {
+ ...
+ }
+ ...
+ }
+ server server_two {
+ client two {
+ ...
+ }
+ authorize {
+ ...
+ }
+ ...
+ }
+
+ In this example, client "two" is hidden inside of the virtual
+server, where the "listen" section cannot find it.
+
+
+7. Outlined examples
+
+ This section outlines a number of examples, with alternatives.
+
+ One server, multiple sockets
+ - multiple "listen" sections in a "server" section
+
+ one server per client
+ - define multiple servers
+ - have a global "listen" section
+ - have multiple global "clients", each with "virtual_server = X"
+
+ two servers, each with their own sockets
+ - define multiple servers
+ - put "client" sections into each "server"
+ - put a "listen" section into each "server"
+
+ Each server can list the same client IP, and the secret
+ can be different
+
+ two sockets, sharing a list of clients, but pointing to different servers
+ - define global "listen" sections
+ - in each, set "virtual_server = X"
+ - in each, set "clients = Y"
+ - define "clients Y" section, containing multiple clients.
+
+ This also means that you can have a third socket, which
+ doesn't share any of these clients.
+
+
+8. How to decide what to do
+
+
+ If you want *completely* separate policies for a socket or a client,
+then create a separate virtual server. Then, map the request to that
+server by setting configuration entries in a "listen" section or in a
+"client" section.
+
+ Start off with the common cases first. If most of the clients
+and/or sockets get a particular policy, make that policy the default.
+Configure it without paying attention to the sockets or clients you
+want to add later, and without adding a second virtual server. Once
+it works, then add the second virtual server.
+
+ If you want to re-use the previously defined sockets with the second
+virtual server, then you will need one or more global "client"
+sections. Those clients will contain a "virtual_server = ..." entry
+that will direct requests from those clients to the appropriate
+virtual server.
diff --git a/raddb/sites-available/abfab-tls b/raddb/sites-available/abfab-tls
new file mode 100644
index 0000000..b8d0626
--- /dev/null
+++ b/raddb/sites-available/abfab-tls
@@ -0,0 +1,118 @@
+#
+# Example configuration for ABFAB listening on TLS.
+#
+# $Id$
+#
+listen {
+ ipaddr = *
+ port = 2083
+ type = auth
+ proto = tcp
+
+ tls {
+ tls_min_version = "1.2"
+ private_key_password = whatever
+
+ # Moonshot tends to distribute certs separate from keys
+ private_key_file = ${certdir}/server.key
+ certificate_file = ${certdir}/server.pem
+ ca_file = ${cadir}/ca.pem
+ dh_file = ${certdir}/dh
+ fragment_size = 8192
+ ca_path = ${cadir}
+ cipher_list = "DEFAULT"
+ cache {
+ enable = no
+ lifetime = 24 # hours
+ name = "abfab-tls"
+ # persist_dir = ${logdir}/abfab-tls
+ }
+ require_client_cert = yes
+ verify {
+ }
+
+ psk_query = "%{psksql:select hex(key) from psk_keys where keyid = '%{TLS-PSK-Identity}'}"
+ }
+
+ virtual_server = abfab-idp
+ clients = radsec-abfab
+}
+
+# There needs to be a separated "listen" section for IPv6.
+# Typically it will be identical to the IPv4 one above, but there might be
+# some differences (e.g. if a different certificate or port is desired)
+listen {
+ ipaddr = ::
+ port = 2083
+ type = auth
+ proto = tcp
+
+ tls {
+ tls_min_version = "1.2"
+ private_key_password = whatever
+
+ # Moonshot tends to distribute certs separate from keys
+ private_key_file = ${certdir}/server.key
+ certificate_file = ${certdir}/server.pem
+ ca_file = ${cadir}/ca.pem
+ dh_file = ${certdir}/dh
+ fragment_size = 8192
+ ca_path = ${cadir}
+ cipher_list = "DEFAULT"
+ cache {
+ enable = no
+ lifetime = 24 # hours
+ name = "abfab-tls"
+ # persist_dir = ${logdir}/abfab-tls
+ }
+ require_client_cert = yes
+ verify {
+ }
+
+ psk_query = "%{psksql:select hex(key) from psk_keys where keyid = '%{TLS-PSK-Identity}'}"
+ }
+
+ virtual_server = abfab-idp
+ clients = radsec-abfab
+}
+
+clients radsec-abfab {
+ #
+ # Allow all clients, but require TLS.
+ # This client stanza will match other RP proxies from other
+ # realms established via the trustrouter. In general
+ # additional client stanzas are also required for local services.
+ #
+ client default {
+ ipaddr = 0.0.0.0/0
+ proto = tls
+ }
+
+ client default_ip6 {
+ ipaddr = ::/0
+ proto = tls
+ }
+
+ # An example local service
+ # client service_1 {
+ # ipaddr = 192.0.2.20
+ # # You should either set gss_acceptor_host_name below
+ # # or set up policy to confirm that a client claims
+ # # the right acceptor hostname when using ABFAB. If
+ # # set, the RADIUS server will confirm that all
+ # # requests have this value for the acceptor host name
+ # gss_acceptor_host_name = "server.example.com"
+ # # If set, this acceptor realm name will be included.
+ # # Foreign realms will typically reject a request if this is not
+ # # properly set.
+ # gss_acceptor_realm_name = "example.com"
+ # # Additionally, trust_router_coi can be set; if set
+ # # it will override the default_community in the realm
+ # # module
+ # trust_router_coi = "community1.example.net"
+ # # In production depployments it is important to set
+ # # up certificate verification so that even if
+ # # clients spoof IP addresses, one client cannot
+ # # impersonate another.
+ # }
+}
diff --git a/raddb/sites-available/abfab-tr-idp b/raddb/sites-available/abfab-tr-idp
new file mode 100644
index 0000000..be98568
--- /dev/null
+++ b/raddb/sites-available/abfab-tr-idp
@@ -0,0 +1,198 @@
+#
+# This file represents a server that is implementing an identity
+# provider for GSS-EAP (RFC 7055) using the trust router
+# protocol for dynamic realm discovery. Any ABFAB identity
+# provider is also an ABFAB relying party proxy.
+#
+# This file does not include a TLS listener; see abfab-tls for a simple
+# example of a RADSEC listener for ABFAB.
+#
+# $Id$
+#
+
+server abfab-idp {
+authorize {
+ psk_authorize
+ abfab_client_check
+ filter_username
+ preprocess
+
+ # If you intend to use CUI and you require that the Operator-Name
+ # be set for CUI generation and you want to generate CUI also
+ # for your local clients then uncomment the operator-name
+ # below and set the operator-name for your clients in clients.conf
+# operator-name
+
+ #
+ # If you want to generate CUI for some clients that do not
+ # send proper CUI requests, then uncomment the
+ # cui below and set "add_cui = yes" for these clients in clients.conf
+# cui
+
+ #
+ # Do RFC 7542 bang path routing. If you want to only do standard
+ # RADIUS NAI routing, comment out the below line.
+ rfc7542
+
+ # Standard RADIUS NAI routing
+ if (!updated) {
+ suffix {
+ updated = 1
+ noop = reject
+ }
+ }
+
+ eap {
+ ok = return
+ }
+
+ expiration
+ logintime
+}
+
+authenticate {
+ #
+ # Allow EAP authentication.
+ eap
+}
+
+# Post-Authentication
+# Once we KNOW that the user has been authenticated, there are
+# additional steps we can take.
+post-auth {
+ #
+ # For EAP-TTLS and PEAP, add the cached attributes to the reply.
+ # The "session-state" attributes are automatically cached when
+ # an Access-Challenge is sent, and automatically retrieved
+ # when an Access-Request is received.
+ #
+ # The session-state attributes are automatically deleted after
+ # an Access-Reject or Access-Accept is sent.
+ #
+ # If both session-state and reply contain a User-Name attribute, remove
+ # the one in the reply if it is just a copy of the one in the request, so
+ # we don't end up with two User-Name attributes.
+
+ if (session-state:User-Name && reply:User-Name && request:User-Name && (reply:User-Name == request:User-Name)) {
+ update reply {
+ &User-Name !* ANY
+ }
+ }
+ update {
+ &reply: += &session-state:
+ }
+
+ # Create the CUI value and add the attribute to Access-Accept.
+ # Uncomment the line below if *returning* the CUI.
+# cui
+
+ #
+ # If you want to have a log of authentication replies,
+ # un-comment the following line, and enable the
+ # 'detail reply_log' module.
+# reply_log
+
+ #
+ # After authenticating the user, do another SQL query.
+ #
+ # See "Authentication Logging Queries" in `mods-config/sql/main/$driver/queries.conf`
+ -sql
+
+ #
+ # Un-comment the following if you want to modify the user's object
+ # in LDAP after a successful login.
+ #
+# ldap
+
+ # For Exec-Program and Exec-Program-Wait
+ exec
+ # Remove reply message if the response contains an EAP-Message
+ remove_reply_message_if_eap
+ # Access-Reject packets are sent through the REJECT sub-section of the
+ # post-auth section.
+ #
+ # Add the ldap module name (or instance) if you have set
+ # 'edir = yes' in the ldap module configuration
+ #
+ Post-Auth-Type REJECT {
+ # log failed authentications in SQL, too.
+ -sql
+ attr_filter.access_reject
+
+ # Insert EAP-Failure message if the request was
+ # rejected by policy instead of because of an
+ # authentication failure And already has an EAP message
+ # For non-ABFAB, we insert the failure all the time, but for ABFAB
+ # It's more desirable to preserve reply-message when we can
+ if (&reply:Eap-Message) {
+ eap
+ }
+
+ # Remove reply message if the response contains an EAP-Message
+ remove_reply_message_if_eap
+ }
+}
+#
+# 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 {
+ # Before proxing the request add an Operator-Name attribute identifying
+ # if the operator-name is found for this client.
+ # No need to uncomment this if you have already enabled this in
+ # the authorize section.
+# operator-name
+
+ # The client requests the CUI by sending a CUI attribute
+ # containing one zero byte.
+ # Uncomment the line below if *requesting* the CUI.
+# cui
+
+ # Uncomment the following line if you want to change attributes
+ # as defined in the preproxy_users file.
+# files
+
+ # Uncomment the following line if you want to filter requests
+ # sent to remote servers based on the rules defined in the
+ # 'attrs.pre-proxy' file.
+# attr_filter.pre-proxy
+
+ # If you want to have a log of packets proxied to a home
+ # server, un-comment the following line, and the
+ # 'detail pre_proxy_log' section, above.
+# pre_proxy_log
+}
+#
+# 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 want to have a log of replies from a home server,
+ # un-comment the following line, and the 'detail post_proxy_log'
+ # section, above.
+# post_proxy_log
+
+ # Uncomment the following line if you want to filter replies from
+ # remote proxies based on the rules defined in the 'attrs' file.
+# attr_filter.post-proxy
+
+ #
+ # If you are proxying 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/raddb/sites-available/aws-nlb b/raddb/sites-available/aws-nlb
new file mode 100644
index 0000000..acea81e
--- /dev/null
+++ b/raddb/sites-available/aws-nlb
@@ -0,0 +1,46 @@
+# -*- text -*-
+######################################################################
+#
+# A sample virtual server which handles "health checks" from Amazon
+# elastic load balancer.
+#
+# https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-healthchecks.html
+#
+# In the Amazon system, configure "proto" as "tcp", and "port" as the port
+# given below in the "listen" section.
+#
+# $Id$
+#
+server aws-nlb {
+
+#
+# This should be the IP address of the Amazon load balancer.
+#
+# If TCP checks come from multiple IP addresses, just list each IP in a separate "client" section.
+#
+client aws-nlb {
+ ipaddr = 192.0.2.1
+ proto = tcp
+ secret = "this-will-never-be-used"
+}
+
+#
+# Listen on a port. Don't use 80, as that requires root permissions,
+# and you don't want to run radiusd as root.
+#
+listen {
+ type = status
+ proto = tcp
+ ipaddr = *
+ port = 8000
+}
+
+#
+# This will never get used, but it's here just in case we actually
+# get sent RADIUS packets.
+#
+authorize {
+ reject
+}
+
+}
diff --git a/raddb/sites-available/buffered-sql b/raddb/sites-available/buffered-sql
new file mode 100644
index 0000000..74574ac
--- /dev/null
+++ b/raddb/sites-available/buffered-sql
@@ -0,0 +1,161 @@
+# -*- text -*-
+######################################################################
+#
+# In 2.0.0, radrelay functionality is integrated into the
+# server core. This virtual server gives an example of
+# using radrelay functionality inside of the server.
+#
+# In this example, the detail file is read, and the data
+# is put into SQL. This configuration is used when a RADIUS
+# server on this machine is receiving accounting packets,
+# and writing them to the detail file.
+#
+# The purpose of this virtual server is to de-couple the storage
+# of long-term accounting data in SQL from "live" information
+# needed by the RADIUS server as it is running.
+#
+# The benefit of this approach is that for a busy server, the
+# overhead of performing SQL queries may be significant. Also,
+# if the SQL databases are large (as is typical for ones storing
+# months of data), the INSERTs and UPDATEs may take a relatively
+# long time. Rather than slowing down the RADIUS server by
+# having it interact with a database, you can just log the
+# packets to a detail file, and then read that file later at a
+# time when the RADIUS server is typically lightly loaded.
+#
+# If you use on virtual server to log to the detail file,
+# and another virtual server (i.e. this one) to read from
+# the detail file, then this process will happen automatically.
+# A sudden spike of RADIUS traffic means that the detail file
+# will grow in size, and the server will be able to handle
+# large volumes of traffic quickly. When the traffic dies down,
+# the server will have time to read the detail file, and insert
+# the data into a long-term SQL database.
+#
+# $Id$
+#
+######################################################################
+
+server buffered-sql {
+ listen {
+ type = detail
+
+ # The location where the detail file is located.
+ # This should be on local disk, and NOT on an NFS
+ # mounted location!
+ #
+ # On most systems, this should support file globbing
+ # e.g. "${radacctdir}/detail-*:*"
+ # This lets you write many smaller detail files as in
+ # the example in radiusd.conf: ".../detail-%Y%m%d:%H"
+ # Writing many small files is often better than writing
+ # one large file. File globbing also means that with
+ # a common naming scheme for detail files, then you can
+ # have many detail file writers, and only one reader.
+ #
+ filename = "${radacctdir}/detail-*"
+
+ #
+ # The server can read accounting packets from the
+ # detail file much more quickly than those packets
+ # can be written to a database. If the database is
+ # overloaded, then bad things can happen.
+ #
+ # The server will keep track of how long it takes to
+ # process an entry from the detail file. It will
+ # then pause between handling entries. This pause
+ # allows databases to "catch up", and gives the
+ # server time to notice that other packets may have
+ # arrived.
+ #
+ # The pause is calculated dynamically, to ensure that
+ # the load due to reading the detail files is limited
+ # to a small percentage of CPU time. The
+ # "load_factor" configuration item is a number
+ # between 1 and 100. The server will try to keep the
+ # percentage of time taken by "detail" file entries
+ # to "load_factor" percentage of the CPU time.
+ #
+ # If the "load_factor" is set to 100, then the server
+ # will read packets as fast as it can, usually
+ # causing databases to go into overload.
+ #
+ load_factor = 10
+
+ #
+ # Set the interval for polling the detail file.
+ # If the detail file doesn't exist, the server will
+ # wake up, and poll for it every N seconds.
+ #
+ # Useful range of values: 1 to 60
+ #
+ poll_interval = 1
+
+ #
+ # Set the retry interval for when the home server
+ # does not respond. The current packet will be
+ # sent repeatedly, at this interval, until the
+ # home server responds.
+ #
+ # Useful range of values: 5 to 30
+ #
+ retry_interval = 30
+
+ #
+ # Track progress through the detail file. When the detail
+ # file is large, and the server is re-started, it will
+ # read from the START of the file.
+ #
+ # Setting "track = yes" means it will skip packets which
+ # have already been processed. The default is "no".
+ #
+ # track = yes
+
+ #
+ # In some circumstances it may be desirable for the
+ # server to start up, process a detail file, and
+ # immediately quit. To do this enable the "one_shot"
+ # option below.
+ #
+ # Do not enable this for normal server operation. The
+ # default is "no".
+ #
+ # one_shot = no
+ }
+
+ #
+ # Pre-accounting. Decide which accounting type to use.
+ #
+ preacct {
+ preprocess
+
+ #
+ # Ensure that we have a semi-unique identifier for every
+ # request, and many NAS boxes are broken.
+ acct_unique
+
+ #
+ # Read the 'acct_users' file. This isn't always
+ # necessary, and can be deleted if you do not use it.
+ files
+ }
+
+ #
+ # Accounting. Log the accounting data.
+ #
+ accounting {
+ #
+ # Log traffic to an SQL database.
+ #
+ # See "Accounting queries" in mods-config/sql/main/$driver/queries.conf
+ # sql
+
+
+ # Cisco VoIP specific bulk accounting
+ # pgsql-voip
+
+ }
+
+ # The requests are not being proxied, so no pre/post-proxy
+ # sections are necessary.
+}
diff --git a/raddb/sites-available/challenge b/raddb/sites-available/challenge
new file mode 100644
index 0000000..c3aeb08
--- /dev/null
+++ b/raddb/sites-available/challenge
@@ -0,0 +1,123 @@
+#
+# This file gives an example of using Challenge-Response
+#
+# In this example, the user logs in with a password, which has
+# to be "hello". The server will send them a challenge
+# consisting of a random number 0..9. The user has to respond
+# with that number.
+#
+#
+# $Id$
+#
+listen {
+ type = auth
+ ipaddr = *
+ port = 2000
+ virtual_server = challenge
+}
+
+server challenge {
+authorize {
+ #
+ # OTP requires a password.
+ #
+ if (!User-Password) {
+ reject
+ }
+
+ #
+ # If there's no State attribute, then this is the first
+ # request from the user.
+ #
+ if (!State) {
+ #
+ # Set the authentication to use step 1.
+ update control {
+ Auth-Type := Step1
+
+ #
+ # For testing we will just set the password to "hello".
+ #
+ # Normally the password comes from "ldap" or "sql".
+ #
+ Cleartext-Password := "hello"
+
+# ldap
+# sql
+# ...
+ }
+ }
+ else {
+ #
+ # Check that the password looks like an OTP
+ #
+ if (User-Password !~ /[0-9]{6}/) {
+ reject
+ }
+
+ #
+ # Set the authentication to use step 2.
+ # Set the "known good" password to the number
+ # saved in the session-state list.
+ #
+ update control {
+ Auth-Type := Step2
+
+ #
+ # For testing, ensure that the user enters the same password.
+ #
+ # Normally this section should look up a TOTP-Secret, and
+ #
+ Cleartext-Password := &session-state:Tmp-Integer-0
+
+ #
+ # Normally this section should also set &control:TOTP-Secret, too.
+ #
+ TOTP-Password := &User-Password
+ }
+ }
+}
+
+authenticate {
+ Auth-Type Step1 {
+ # If the password doesn't match, the user is rejected
+ # immediately.
+ pap
+
+ #
+ # For testing, just use a 6 digit random OTP.
+ #
+ update session-state {
+ Tmp-Integer-0 := "%{randstr:nnnnnn}"
+ }
+
+ #
+ # For testing, tell the user what OTP to enter.
+ #
+ # Don't do this in production...
+ #
+ update reply {
+ Reply-Message := "Please enter OTP %{session-state:Tmp-Integer-0}"
+ }
+
+ #
+ # Send an Access-Challenge.
+ # See raddb/policy.d/control for the definition
+ # of "challenge"
+ #
+ challenge
+ }
+
+ Auth-Type Step2 {
+ #
+ # For testing, do PAP authentication with the password.
+ #
+ pap
+
+ #
+ # Normally you'd do TOTP checks via the TOTP module.
+ #
+# totp
+ }
+}
+}
diff --git a/raddb/sites-available/channel_bindings b/raddb/sites-available/channel_bindings
new file mode 100644
index 0000000..b9f0ac7
--- /dev/null
+++ b/raddb/sites-available/channel_bindings
@@ -0,0 +1,17 @@
+#
+# A virtual server which is used to validate channel-bindings.
+#
+# $Id$
+#
+server channel_bindings {
+ #
+ # Only the "authorize" section is needed.
+ #
+ authorize {
+ # In general this section should include a policy for each type
+ # of channel binding that may be in use. For example each lower
+ # layer such as GSS-EAP (RFC 7055) or IEEE 802.11I is likely to
+ # need a separate channel binding policy.
+ abfab_channel_bindings
+ }
+}
diff --git a/raddb/sites-available/check-eap-tls b/raddb/sites-available/check-eap-tls
new file mode 100644
index 0000000..d367463
--- /dev/null
+++ b/raddb/sites-available/check-eap-tls
@@ -0,0 +1,135 @@
+# This virtual server allows EAP-TLS to reject access requests
+# based on some attributes of the certificates involved.
+#
+# To use this virtual server, you must enable it in the tls
+# section of mods-enabled/eap as well as adding a link to this
+# file in sites-enabled/.
+#
+#
+# Value-pairs that are available for checking include:
+#
+# TLS-Client-Cert-Subject
+# TLS-Client-Cert-Issuer
+# TLS-Client-Cert-Common-Name
+# TLS-Client-Cert-Subject-Alt-Name-Email
+#
+# To see a full list of attributes, run the server in debug mode
+# with this virtual server configured, and look at the attributes
+# passed in to this virtual server.
+#
+#
+# This virtual server is also useful when using EAP-TLS as it is
+# only called once, just before the final Accept is about to be
+# returned from eap, whereas the outer authorize section is called
+# multiple times for each challenge / response. For this reason,
+# here may be a good location to put authentication logging, and
+# modules that check for further authorization, especially if they
+# hit external services such as sql or ldap.
+
+
+server check-eap-tls {
+
+
+# Authorize - this is the only section required.
+#
+# To accept the access request, set Auth-Type = Accept, otherwise
+# set it to Reject.
+
+authorize {
+
+ #
+ # By default, we just accept the request:
+ #
+ update config {
+ &Auth-Type := Accept
+ }
+
+
+ #
+ # Check the client certificate matches a string, and reject otherwise
+ #
+
+# if ("%{TLS-Client-Cert-Common-Name}" == 'client.example.com') {
+# update config {
+# &Auth-Type := Accept
+# }
+# }
+# else {
+# update config {
+# &Auth-Type := Reject
+# }
+# update reply {
+# &outer.Reply-Message := "Your certificate is not valid."
+# }
+# }
+
+
+ #
+ # Check the client certificate common name against the supplied User-Name
+ #
+# if (&User-Name == "host/%{TLS-Client-Cert-Common-Name}") {
+# update config {
+# &Auth-Type := Accept
+# }
+# }
+# else {
+# update config {
+# &Auth-Type := Reject
+# }
+# }
+
+
+ #
+ # This is a convenient place to call LDAP, for example, when using
+ # EAP-TLS, as it will only be called once, after all certificates as
+ # part of the EAP-TLS challenge process have been verified.
+ #
+ # An example could be to use LDAP to check that the connecting host, as
+ # well as presenting a valid certificate, is also in a group based on
+ # the User-Name (assuming this contains the service principal name).
+ # Settings such as the following could be used in the ldap module
+ # configuration:
+ #
+ # basedn = "dc=example, dc=com"
+ # filter = "(servicePrincipalName=%{User-Name})"
+ # base_filter = "(objectClass=computer)"
+ # groupname_attribute = cn
+ # groupmembership_filter = "(&(objectClass=group)(member=%{control:Ldap-UserDn}))"
+
+# ldap
+
+ # Now let's test membership of an LDAP group (the ldap bind user will
+ # need permission to read this group membership):
+
+# if (!(Ldap-Group == "Permitted-Laptops")) {
+# update config {
+# &Auth-Type := Reject
+# }
+# }
+
+ # or, to be more specific, you could use the group's full DN:
+ # if (!(Ldap-Group == "CN=Permitted-Laptops,OU=Groups,DC=example,DC=org")) {
+
+
+ #
+ # This may be a better place to call the files modules when using
+ # EAP-TLS, as it will only be called once, after the challenge-response
+ # iteration has completed.
+ #
+
+# files
+
+
+ #
+ # Log all request attributes, plus TLS certificate details, to the
+ # auth_log file. Again, this is just once per connection request, so
+ # may be preferable than in the outer authorize section. It is
+ # suggested that 'auth_log' also be in the outer post-auth and
+ # Post-Auth REJECT sections to log reply packet details, too.
+ #
+
+ auth_log
+
+}
+}
+
diff --git a/raddb/sites-available/coa b/raddb/sites-available/coa
new file mode 100644
index 0000000..c10f88e
--- /dev/null
+++ b/raddb/sites-available/coa
@@ -0,0 +1,49 @@
+# -*- text -*-
+######################################################################
+#
+# Sample virtual server for receiving a CoA or Disconnect-Request packet.
+#
+
+# Listen on the CoA port.
+#
+# This uses the normal set of clients, with the same secret as for
+# authentication and accounting.
+#
+listen {
+ type = coa
+ ipaddr = *
+ port = 3799
+ virtual_server = coa
+}
+
+server coa {
+ # When a packet is received, it is processed through the
+ # recv-coa section. This applies to *both* CoA-Request and
+ # Disconnect-Request packets.
+ recv-coa {
+ # CoA && Disconnect packets can be proxied in the same
+ # way as authentication or accounting packets.
+ # Just set Proxy-To-Realm, or Home-Server-Pool, and the
+ # packets will be proxied.
+
+ # Do proxying based on realms here. You don't need
+ # "IPASS" or "ntdomain", as the proxying is based on
+ # the Operator-Name attribute. It contains the realm,
+ # and ONLY the realm (prefixed by a '1')
+ suffix
+
+ # Insert your own policies here.
+ ok
+ }
+
+ # 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 {
+ # Sample module.
+ ok
+ }
+
+ # You can use pre-proxy and post-proxy sections here, too.
+ # They will be processed for sending && receiving proxy packets.
+}
diff --git a/raddb/sites-available/coa-relay b/raddb/sites-available/coa-relay
new file mode 100644
index 0000000..7dac7b1
--- /dev/null
+++ b/raddb/sites-available/coa-relay
@@ -0,0 +1,366 @@
+# -*- text -*-
+######################################################################
+#
+# This virtual server simplifies the process of sending CoA-Request or
+# Disconnect-Request packets to a NAS.
+#
+# This virtual server will receive CoA-Request or Disconnect-Request
+# packets that contain *minimal* identifying information. e.g. Just
+# a User-Name, or maybe just an Acct-Session-Id attribute. It will
+# look up that information in a database in order to find the rest of
+# the session data. e.g. NAS-IP-Address, NAS-Identifier, NAS-Port,
+# etc. That information will be added to the packet, which will then
+# be sent to the NAS.
+#
+# This process is useful because NASes require the CoA packets to
+# contain "session identification" attributes in order to to do CoA
+# or Disconnect. If the attributes aren't in the packet, then the
+# NAS will NAK the request. This NAK happens even if you ask to
+# disconnect "User-Name = bob", and there is only one session with a
+# "bob" active.
+#
+# Using this virtual server makes the CoA or Disconnect process
+# easier. Just tell FreeRADIUS to disconnect "User-Name = bob", and
+# FreeRADIUS will take care of adding the "session identification"
+# attributes.
+#
+# The process is as follows:
+#
+# - A CoA/Disconnect-Request is received by FreeRADIUS.
+# - The radacct table is searched for active sessions that match each of
+# the provided identifier attributes: User-Name, Acct-Session-Id. The
+# search returns the owning NAS and Acct-Unique-Id for the matching
+# session/s.
+# - The original CoA/Disconnect-Request content is written to a detail file
+# with custom attributes representing the NAS and Acct-Session-Id.
+# - A detail reader follows the file and originates CoA/Disconenct-Requests
+# containing the original content, relayed to the corresponding NAS for
+# each session using the custom attributes.
+#
+# This simplifies scripting directly against a set of NAS devices since a
+# script need only send a single CoA/Disconnect to FreeRADIUS which will
+# then:
+#
+# - Lookup all active sessions belonging to a user, in the case that only a
+# User-Name attribute is provided in the request
+# - Handle routing of the request to the correct NAS, in the case of a
+# multi-NAS setup
+#
+# For example, to disconnect a specific session:
+#
+# $ echo 'Acct-Session-Id = "769df3 312343"' | \
+# radclient 127.0.0.1 disconnect testing123
+#
+# To perform a CoA update of all active sessions belonging to a user:
+#
+# $ cat <<EOF | radclient 127.0.0.1 coa testing123
+# User-Name = bob
+# Cisco-AVPair = "subscriber:sub-qos-policy-out=q_out_uncapped"
+# EOF
+#
+# In addition to configuring and activating this site, a detail
+# writer module must be configured in mods-enabled:
+#
+# detail detail_coa {
+# filename = ${radacctdir}/detail_coa
+# escape_filenames = no
+# permissions = 0600
+# header = "%t"
+# locking = yes
+# }
+#
+
+
+# Listen on a local CoA port.
+#
+# This uses the normal set of clients, with the same secret as for
+# authentication and accounting.
+#
+listen {
+ type = coa
+ ipaddr = 127.0.0.1
+ port = 3799
+ virtual_server = coa
+}
+
+#
+# Receive CoA/Disconnect, lookup sessions, write them to a detail file
+#
+server coa {
+ #
+ # When a packet is received, it is processed through the
+ # recv-coa section. This applies to *both* CoA-Request and
+ # Disconnect-Request packets.
+ #
+ recv-coa {
+ #
+ # Lookup all active sessions matching User-Name and/or
+ # Acct-Session-Id and write each session (which includes to
+ # owning NAS and session ID) to a detail file.
+ #
+ # Returns a single result in the format:
+ #
+ # NasIpAddress1#AcctSessionId1|NasIPAddress2#AcctSessionId2|...
+ #
+ # i.e. each session is separated by '|', and attributes
+ # within a session are separated by '#'
+ #
+ # You will likely have to update the SELECT to add in
+ # any other "session identification" attributes
+ # needed by the NAS. These may include NAS-Port,
+ # NAS-Identifier, etc. Only the NAS vendor knows
+ # what these attributes are unfortunately, so we
+ # cannot give more detailed advice here.
+ #
+ update control {
+
+ #
+ # Example MySQL lookup
+ #
+# Tmp-String-0 := "%{sql:SELECT IFNULL(GROUP_CONCAT(CONCAT(nasipaddress,'#',acctsessionid) separator '|'),'') FROM (SELECT * FROM radacct WHERE ('%{User-Name}'='' OR UserName='%{User-Name}') AND ('%{Acct-Session-Id}'='' OR acctsessionid = '%{Acct-Session-Id}') AND AcctStopTime IS NULL) a}"
+
+ #
+ # Example PostgreSQL lookup
+ #
+# Tmp-String-0 := "%{sql:SELECT STRING_AGG(CONCAT(nasipaddress,'#',acctsessionid),'|') FROM (SELECT * FROM radacct WHERE ('%{User-Name}'='' OR UserName='%{User-Name}') AND ('%{Acct-Session-Id}'='' OR acctsessionid = '%{Acct-Session-Id}') AND AcctStopTime IS NULL) a}"
+
+ }
+
+ #
+ # Split the string and split into pieces.
+ #
+ if (&control:Tmp-String-0 != "" && "%{explode:&control:Tmp-String-0 |}") {
+ foreach &control:Tmp-String-0 {
+ if ("%{Foreach-Variable-0}" =~ /([^#]*)#(.*)/) {
+ update request {
+ CoA-Packet-Type := "%{Packet-Type}"
+
+ #
+ # Or use CoA-Packet-DST-IPv6-Address
+ # for IPv6 address.
+ #
+ CoA-Packet-DST-IP-Address := "%{1}"
+
+ CoA-Acct-Session-Id := "%{2}"
+
+ #
+ # Add any other attributes here.
+ #
+
+ # Set the CoA/Disconnect port
+ CoA-Packet-DST-Port := 1700
+
+ # SQL-User-Name was left over
+ # from the xlat
+ SQL-User-Name !* ANY
+
+ # Uncomment if the NAS does not
+ # expect User-Name
+ #User-Name !* ANY
+
+ }
+
+ #
+ # If we're sending a CoA packet, send it out.
+ #
+ if ((CoA-Packet-DST-IP-Address || CoA-Packet-DST-IPv6-Address) && \
+ CoA-Acct-Session-Id != "") {
+ detail_coa.accounting
+ }
+ }
+ }
+ } else {
+ # No sessions found
+ reject
+ }
+
+ }
+}
+
+#
+# Detail file reader that processes the queue of CoA/Disconnect requests
+#
+server coa-buffered-reader {
+ listen {
+ #
+ # See sites-available/buffered-sql for more details on
+ # all the options available for the detail reader.
+ #
+ type = detail
+ filename = "${radacctdir}/detail_coa"
+ load_factor = 90
+ track = yes
+ }
+
+ #
+ # For historical reasons packets from the detail file reader are
+ # processed through the "accounting" section.
+ #
+ accounting {
+ switch &CoA-Packet-Type {
+ case "Disconnect-Request" {
+ update {
+ # Include given attributes
+ disconnect: += request:[*]
+
+ disconnect:Packet-DST-Port := \
+ &CoA-Packet-DST-Port
+
+ disconnect:Acct-Session-Id := \
+ &CoA-Acct-Session-Id
+
+ # Some NASs want these, others don't
+ disconnect:Event-Timestamp := "%l"
+ disconnect:Message-Authenticator := 0x00
+
+ #
+ # Remove attributes which will confuse the NAS
+ #
+ # The NAS will "helpfully" NAK the packet
+ # if it contains attributes which are NOT
+ # "session identification" attributes.
+ #
+ # Those attributes should be listed here.
+ #
+ disconnect:Acct-Delay-Time !* ANY
+ disconnect:Proxy-State !* ANY
+ }
+
+ if (CoA-Packet-DST-IP-Address) {
+ update {
+ disconnect:Packet-DST-IP-Address := \
+ &CoA-Packet-DST-IP-Address
+ }
+ } else {
+ update {
+ disconnect:Packet-DST-IPv6-Address := \
+ &CoA-Packet-DST-IPv6-Address
+ }
+ }
+ }
+
+ case "CoA-Request" {
+ update {
+ # Include given attributes
+ coa: += request:[*]
+
+ coa:Packet-DST-Port := \
+ &CoA-Packet-DST-Port
+
+ coa:Acct-Session-Id := \
+ &CoA-Acct-Session-Id
+
+ # Some NASs want these, others don't
+ coa:Event-Timestamp := "%l"
+ coa:Message-Authenticator := 0x00
+
+ #
+ # Remove attributes which will confuse the NAS
+ #
+ # The NAS will "helpfully" NAK the packet
+ # if it contains attributes which are NOT
+ # "session identification" attributes.
+ #
+ # Those attributes should be listed here.
+ #
+ coa:Acct-Delay-Time !* ANY
+ coa:Proxy-State !* ANY
+ }
+
+ if (CoA-Packet-DST-IP-Address) {
+ update {
+ coa:Packet-DST-IP-Address := \
+ &CoA-Packet-DST-IP-Address
+ }
+ } else {
+ update {
+ coa:Packet-DST-IPv6-Address := \
+ &CoA-Packet-DST-IPv6-Address
+ }
+ }
+
+ }
+ }
+
+ #
+ # ACK the CoA / Disconnect packet.
+ #
+ ok
+ }
+}
+
+
+# The CoA packet is in the "proxy-request" attribute list.
+# The CoA reply (if any) is in the "proxy-reply" attribute list.
+#
+server originate-coa-relay {
+ #
+ # Handle the responses here.
+ #
+ post-proxy {
+ switch &proxy-reply:Packet-Type {
+ case CoA-ACK {
+ ok
+ }
+
+ case CoA-NAK {
+ # the NAS didn't like the CoA request
+ ok
+ }
+
+ case Disconnect-ACK {
+ ok
+ }
+
+ case Disconnect-NAK {
+ # the NAS didn't like the Disconnect request
+ ok
+ }
+
+ # Invalid packet type. This shouldn't happen.
+ case {
+ fail
+ }
+ }
+
+ #
+ # These methods are run when there is NO response
+ # to the request.
+ #
+ Post-Proxy-Type Fail-CoA {
+ ok
+ }
+
+ Post-Proxy-Type Fail-Disconnect {
+ ok
+ }
+ }
+}
+
+
+#
+# Homeserver CoA / Disconnect endpoints
+#
+# See proxy.conf for more details on configuring a home_server and
+# home_server_pool.
+#
+home_server coa-nas1 {
+ type = coa
+
+ # Update these to match your NAS
+ ipaddr = 192.0.2.1
+ port = 1700
+ secret = testing1234
+
+ coa {
+ irt = 2
+ mrt = 16
+ mrc = 5
+ mrd = 30
+ }
+}
+home_server_pool coa-nas1 {
+ type = fail-over
+ home_server = coa-nas1
+ virtual_server = originate-coa-relay
+}
diff --git a/raddb/sites-available/control-socket b/raddb/sites-available/control-socket
new file mode 100644
index 0000000..97ba9ef
--- /dev/null
+++ b/raddb/sites-available/control-socket
@@ -0,0 +1,92 @@
+# -*- text -*-
+######################################################################
+#
+# Control socket interface.
+#
+# In the future, we will add username/password checking for
+# connections to the control socket. We will also add
+# command authorization, where the commands entered by the
+# administrator are run through a virtual server before
+# they are executed.
+#
+# For now, anyone who has permission to connect to the socket
+# has nearly complete control over the server. Be warned!
+#
+# This functionality is NOT enabled by default.
+#
+# See also the "radmin" program, which is used to communicate
+# with the server over the control socket.
+#
+# $Id$
+#
+######################################################################
+listen {
+ #
+ # Listen on the control socket.
+ #
+ type = control
+
+ #
+ # Socket location.
+ #
+ # This file is created with the server's uid and gid.
+ # It's permissions are r/w for that user and group, and
+ # no permissions for "other" users. These permissions form
+ # minimal security, and should not be relied on.
+ #
+ socket = ${run_dir}/${name}.sock
+
+ #
+ # Peercred auth
+ #
+ # By default the server users the peercred feature of unix
+ # sockets to get the UID and GID of the user connecting to
+ # the socket. You may choose to disable this functionality
+ # and rely on the file system for enforcing permissions.
+ #
+ # On most Unix systems, the permissions set on the socket
+ # are not enforced, but the ones on the directory containing
+ # the socket are.
+ #
+ # To use filesystem permissions you should create a new
+ # directory just to house the socket file, and set
+ # appropriate permissions on that.
+ #
+# peercred = no
+# socket = ${run_dir}/control/${name}.sock
+
+ #
+ # The following two parameters perform authentication and
+ # authorization of connections to the control socket.
+ #
+ # If not set, then ANYONE can connect to the control socket,
+ # and have complete control over the server. This is likely
+ # not what you want.
+ #
+ # One, or both, of "uid" and "gid" should be set. If set, the
+ # corresponding value is checked. Unauthorized users result
+ # in an error message in the log file, and the connection is
+ # closed.
+ #
+
+ #
+ # Name of user that is allowed to connect to the control socket.
+ #
+# uid = radius
+
+ #
+ # Name of group that is allowed to connect to the control socket.
+ #
+# gid = radius
+
+ #
+ # Access mode.
+ #
+ # This can be used to give *some* administrators access to
+ # monitor the system, but not to change it.
+ #
+ # ro = read only access (default)
+ # rw = read/write access.
+ #
+# mode = rw
+}
diff --git a/raddb/sites-available/copy-acct-to-home-server b/raddb/sites-available/copy-acct-to-home-server
new file mode 100644
index 0000000..cd085e0
--- /dev/null
+++ b/raddb/sites-available/copy-acct-to-home-server
@@ -0,0 +1,202 @@
+# -*- text -*-
+######################################################################
+#
+# In 2.0.0, radrelay functionality is integrated into the
+# server core. This virtual server gives an example of
+# using radrelay functionality inside of the server.
+#
+# In this example, the detail file is read, and the packets
+# are proxied to a home server. You will have to configure
+# realms, home_server_pool, and home_server in proxy.conf
+# for this to work.
+#
+# The purpose of this virtual server is to enable duplication
+# of information across a load-balanced, or fail-over set of
+# servers. For example, if a group of clients lists two
+# home servers (primary, secondary), then RADIUS accounting
+# messages will go only to one server at a time. This file
+# configures a server (primary, secondary) to send copies of
+# the accounting information to each other.
+#
+# That way, each server has the same set of information, and
+# can make the same decision about the user.
+#
+# $Id$
+#
+######################################################################
+
+server copy-acct-to-home-server {
+ listen {
+ type = detail
+
+ #
+ # See sites-available/buffered-sql for more details on
+ # all the options available for the detail reader.
+ #
+
+ ######################################################
+ #
+ # !!!! WARNING !!!!
+ #
+ # The detail file reader acts just like a NAS.
+ #
+ # This means that if accounting fails, the packet
+ # is re-tried FOREVER. It is YOUR responsibility
+ # to write an accounting policy that returns "ok"
+ # if the packet was processed properly, "fail" on
+ # a database error, AND "ok" if you want to ignore
+ # the packet (e.g. no Acct-Status-Type).
+ #
+ # Neither the detail file write OR the detail file
+ # reader look at the contents of the packets. They
+ # just either dump the packet verbatim to the file,
+ # or read it verbatim from the file and pass it to
+ # the server.
+ #
+ ######################################################
+
+
+ # The location where the detail file is located.
+ # This should be on local disk, and NOT on an NFS
+ # mounted location!
+ #
+ # On most systems, this should support file globbing
+ # e.g. "${radacctdir}/detail-*:*"
+ # This lets you write many smaller detail files as in
+ # the example in radiusd.conf: ".../detail-%Y%m%d:%H"
+ # Writing many small files is often better than writing
+ # one large file. File globbing also means that with
+ # a common naming scheme for detail files, then you can
+ # have many detail file writers, and only one reader.
+ #
+ # Do NOT copy the "filename" configuration from the
+ # "detail" module here. It won't work. Instead, use
+ # file globbing (or wildcards), such as:
+ #
+ # filename = ${radacctdir}/reader1/detail-*
+ #
+ filename = ${radacctdir}/detail
+
+ #
+ # The server can read accounting packets from the
+ # detail file much more quickly than those packets
+ # can be written to a database. If the database is
+ # overloaded, then bad things can happen.
+ #
+ # The server will keep track of how long it takes to
+ # process an entry from the detail file. It will
+ # then pause between handling entries. This pause
+ # allows databases to "catch up", and gives the
+ # server time to notice that other packets may have
+ # arrived.
+ #
+ # The pause is calculated dynamically, to ensure that
+ # the load due to reading the detail files is limited
+ # to a small percentage of CPU time. The
+ # "load_factor" configuration item is a number
+ # between 1 and 100. The server will try to keep the
+ # percentage of time taken by "detail" file entries
+ # to "load_factor" percentage of the CPU time.
+ #
+ # If the "load_factor" is set to 100, then the server
+ # will read packets as fast as it can, usually
+ # causing databases to go into overload.
+ #
+ load_factor = 10
+
+ #
+ # Track progress through the detail file. When the detail
+ # file is large, and the server is re-started, it will
+ # read from the START of the file.
+ #
+ # Setting "track = yes" means it will skip packets which
+ # have already been processed. The default is "no".
+ #
+ # track = yes
+
+ }
+
+ #
+ # Pre-accounting. Decide which accounting type to use.
+ #
+ preacct {
+ preprocess
+
+ # Since we're just proxying, we don't need acct_unique.
+
+ #
+ # 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.
+# IPASS
+# suffix
+# ntdomain
+
+ #
+ # Edit proxy.conf to add a "home_server" section,
+ # which points to the other server.
+ #
+ # Then set that home_server name here.
+ #
+ update control {
+ Home-Server-Name := "name_of_home_server_from_proxy.conf"
+ }
+
+ #
+ # Read the 'acct_users' file. This isn't always
+ # necessary, and can be deleted if you do not use it.
+ files
+ }
+
+ #
+ # Accounting. Log the accounting data.
+ #
+ accounting {
+ #
+ # Since we're proxying, we don't log anything
+ # locally. Ensure that the accounting section
+ # "succeeds" by forcing an "ok" return.
+ ok
+ }
+
+
+ #
+ # 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 {
+
+ # If you want to have a log of packets proxied to a home
+ # server, un-comment the following line, and the
+ # 'detail pre_proxy_log' section in radiusd.conf.
+ # pre_proxy_log
+ }
+
+ #
+ # 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 want to have a log of replies from a home
+ # server, un-comment the following line, and the
+ # 'detail post_proxy_log' section in radiusd.conf.
+ # post_proxy_log
+
+
+ # Uncomment the following line if you want to filter
+ # replies from remote proxies based on the rules
+ # defined in the 'attrs' file.
+
+ # attr_filter
+ }
+}
diff --git a/raddb/sites-available/decoupled-accounting b/raddb/sites-available/decoupled-accounting
new file mode 100644
index 0000000..abf455c
--- /dev/null
+++ b/raddb/sites-available/decoupled-accounting
@@ -0,0 +1,139 @@
+# -*- text -*-
+######################################################################
+#
+# This is a sample configuration for "decoupled" accounting.
+# "Decoupled" accounting is where the accounting packets are
+# NOT written "live" to the back-end database. This method
+# can only be used if you are not interested in "live"
+# accounting. i.e. Where you can tolerate delays that may be
+# a few seconds, before accounting packets get written to
+# the DB.
+#
+# Oddly enough, this method can speed up the processing of
+# accounting packets, as all database activity is serialized.
+#
+# This file is NOT meant to be used as-is. It needs to be
+# edited to match your local configuration.
+#
+# $Id$
+#
+######################################################################
+
+# Define a virtual server to write the accounting packets.
+# Any "listen" section that listens on an accounting port should
+# set "virtual_server = write-detail.example.com
+server write_detail.example.com {
+ accounting {
+ #
+ # Write the "detail" files.
+ #
+ # See raddb/modules/detail.example.com for more info.
+ detail.example.com
+ }
+
+ # That's it!
+}
+
+# Define a virtual server to process the accounting packets.
+server read-detail.example.com {
+ # Read accounting packets from the detail file(s) for
+ # the home server.
+ listen {
+ type = detail
+ filename = "${radacctdir}/detail.example.com/detail-*:*"
+ load_factor = 10
+ track = yes
+ }
+
+ # All packets read from the detail file are processed through
+ # the preacct && accounting sections.
+ #
+ # The following text is copied verbatim from sites-available/default.
+ # You should edit it for your own local configuration.
+
+#
+# Pre-accounting. Decide which accounting type to use.
+#
+preacct {
+ preprocess
+
+ #
+ # Ensure that we have a semi-unique identifier for every
+ # request, and many NAS boxes are broken.
+ acct_unique
+
+ #
+ # 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.
+# IPASS
+ suffix
+# ntdomain
+
+ #
+ # Read the 'acct_users' file
+ files
+}
+
+#
+# Accounting. Log the accounting data.
+#
+accounting {
+ #
+ # Create a 'detail'ed log of the packets.
+ # Note that accounting requests which are proxied
+ # are also logged in the detail file.
+ detail
+# daily
+
+ # Update the wtmp file
+ #
+ # If you don't use "radlast", you can delete this line.
+ unix
+
+ #
+ # For Simultaneous-Use tracking.
+ #
+ # Due to packet losses in the network, the data here
+ # may be incorrect. There is little we can do about it.
+ radutmp
+# sradutmp
+
+ #
+ # Return an address to the IP Pool when we see a stop record.
+ #
+ # Ensure that &control:Pool-Name is set to determine which
+ # pool of IPs are used.
+# sqlippool
+
+ #
+ # Log traffic to an SQL database.
+ #
+ # NOTE! You will have to ensure that any accounting packets
+ # NOT handled by the SQL module (e.g. "stop with zero session length"
+ # result in the accounting section still returning "ok".
+ #
+ # Otherwise, the server will think that the accounting packet
+ # was NOT handled properly, and will keep trying to process it
+ # through this virtual server!
+ #
+ # See "Accounting queries" in `mods-config/sql/main/$driver/queries.conf`
+# sql
+
+ # Cisco VoIP specific bulk accounting
+# pgsql-voip
+
+ # Filter attributes from the accounting response.
+ attr_filter.accounting_response
+
+ #
+ # See "Autz-Type Status-Server" for how this works.
+ #
+# Acct-Type Status-Server {
+#
+# }
+}
+}
diff --git a/raddb/sites-available/default b/raddb/sites-available/default
new file mode 100644
index 0000000..78b7ae7
--- /dev/null
+++ b/raddb/sites-available/default
@@ -0,0 +1,1159 @@
+######################################################################
+#
+# As of 2.0.0, FreeRADIUS supports virtual hosts using the
+# "server" section, and configuration directives.
+#
+# Virtual hosts should be put into the "sites-available"
+# directory. Soft links should be created in the "sites-enabled"
+# directory to these files. This is done in a normal installation.
+#
+# If you are using 802.1X (EAP) authentication, please see also
+# the "inner-tunnel" virtual server. You will likely have to edit
+# that, too, for authentication to work.
+#
+# $Id$
+#
+######################################################################
+#
+# Read "man radiusd" before editing this file. See the section
+# titled DEBUGGING. It outlines a method where you can quickly
+# obtain the configuration you want, without running into
+# trouble. See also "man unlang", which documents the format
+# of this file.
+#
+# This configuration is designed to work in the widest possible
+# set of circumstances, with the widest possible number of
+# authentication methods. This means that in general, you should
+# need to make very few changes to this file.
+#
+# The best way to configure the server for your local system
+# is to CAREFULLY edit this file. Most attempts to make large
+# edits to this file will BREAK THE SERVER. Any edits should
+# be small, and tested by running the server with "radiusd -X".
+# Once the edits have been verified to work, save a copy of these
+# configuration files somewhere. (e.g. as a "tar" file). Then,
+# make more edits, and test, as above.
+#
+# There are many "commented out" references to modules such
+# as ldap, sql, etc. These references serve as place-holders.
+# If you need the functionality of that module, then configure
+# it in radiusd.conf, and un-comment the references to it in
+# this file. In most cases, those small changes will result
+# in the server being able to connect to the DB, and to
+# authenticate users.
+#
+######################################################################
+
+server default {
+#
+# If you want the server to listen on additional addresses, or on
+# additional ports, you can use multiple "listen" sections.
+#
+# Each section make the server listen for only one type of packet,
+# therefore authentication and accounting have to be configured in
+# different sections.
+#
+# The server ignore all "listen" section if you are using '-i' and '-p'
+# on the command line.
+#
+listen {
+ # Type of packets to listen for.
+ # Allowed values are:
+ # auth listen for authentication packets
+ # acct listen for accounting packets
+ # auth+acct listen for both authentication and accounting packets
+ # proxy IP to use for sending proxied packets
+ # detail Read from the detail file. For examples, see
+ # raddb/sites-available/copy-acct-to-home-server
+ # status listen for Status-Server packets. For examples,
+ # see raddb/sites-available/status
+ # coa listen for CoA-Request and Disconnect-Request
+ # packets. For examples, see the file
+ # raddb/sites-available/coa
+ #
+ type = auth
+
+ # Note: "type = proxy" lets you control the source IP used for
+ # proxying packets, with some limitations:
+ #
+ # * A proxy listener CANNOT be used in a virtual server section.
+ # * You should probably set "port = 0".
+ # * Any "clients" configuration will be ignored.
+ #
+ # See also proxy.conf, and the "src_ipaddr" configuration entry
+ # in the sample "home_server" section. When you specify the
+ # source IP address for packets sent to a home server, the
+ # proxy listeners are automatically created.
+
+ # ipaddr/ipv4addr/ipv6addr - IP address on which to listen.
+ # If multiple ones are listed, only the first one will
+ # be used, and the others will be ignored.
+ #
+ # The configuration options accept the following syntax:
+ #
+ # ipv4addr - IPv4 address (e.g.192.0.2.3)
+ # - wildcard (i.e. *)
+ # - hostname (radius.example.com)
+ # Only the A record for the host name is used.
+ # If there is no A record, an error is returned,
+ # and the server fails to start.
+ #
+ # ipv6addr - IPv6 address (e.g. 2001:db8::1)
+ # - wildcard (i.e. *)
+ # - hostname (radius.example.com)
+ # Only the AAAA record for the host name is used.
+ # If there is no AAAA record, an error is returned,
+ # and the server fails to start.
+ #
+ # ipaddr - IPv4 address as above
+ # - IPv6 address as above
+ # - wildcard (i.e. *), which means IPv4 wildcard.
+ # - hostname
+ # If there is only one A or AAAA record returned
+ # for the host name, it is used.
+ # If multiple A or AAAA records are returned
+ # for the host name, only the first one is used.
+ # If both A and AAAA records are returned
+ # for the host name, only the A record is used.
+ #
+ # ipv4addr = *
+ # ipv6addr = *
+ ipaddr = *
+
+ # Port on which to listen.
+ # Allowed values are:
+ # integer port number (1812)
+ # 0 means "use /etc/services for the proper port"
+ port = 0
+
+ # Some systems support binding to an interface, in addition
+ # to the IP address. This feature isn't strictly necessary,
+ # but for sites with many IP addresses on one interface,
+ # it's useful to say "listen on all addresses for eth0".
+ #
+ # If your system does not support this feature, you will
+ # get an error if you try to use it.
+ #
+# interface = eth0
+
+ # Per-socket lists of clients. This is a very useful feature.
+ #
+ # The name here is a reference to a section elsewhere in
+ # radiusd.conf, or clients.conf. Having the name as
+ # a reference allows multiple sockets to use the same
+ # set of clients.
+ #
+ # If this configuration is used, then the global list of clients
+ # is IGNORED for this "listen" section. Take care configuring
+ # this feature, to ensure you don't accidentally disable a
+ # client you need.
+ #
+ # See clients.conf for the configuration of "per_socket_clients".
+ #
+# clients = per_socket_clients
+
+ #
+ # Set the default UDP receive buffer size. In most cases,
+ # the default values set by the kernel are fine. However, in
+ # some cases the NASes will send large packets, and many of
+ # them at a time. It is then possible to overflow the
+ # buffer, causing the kernel to drop packets before they
+ # reach FreeRADIUS. Increasing the size of the buffer will
+ # avoid these packet drops.
+ #
+# recv_buff = 65536
+
+ #
+ # Connection limiting for sockets with "proto = tcp".
+ #
+ # This section is ignored for other kinds of sockets.
+ #
+ limit {
+ #
+ # Limit the number of simultaneous TCP connections to the socket
+ #
+ # The default is 16.
+ # Setting this to 0 means "no limit"
+ max_connections = 16
+
+ # The per-socket "max_requests" option does not exist.
+
+ #
+ # The lifetime, in seconds, of a TCP connection. After
+ # this lifetime, the connection will be closed.
+ #
+ # Setting this to 0 means "forever".
+ lifetime = 0
+
+ #
+ # The idle timeout, in seconds, of a TCP connection.
+ # If no packets have been received over the connection for
+ # this time, the connection will be closed.
+ #
+ # Setting this to 0 means "no timeout".
+ #
+ # We STRONGLY RECOMMEND that you set an idle timeout.
+ #
+ idle_timeout = 30
+ }
+}
+
+#
+# This second "listen" section is for listening on the accounting
+# port, too.
+#
+listen {
+ ipaddr = *
+# ipv6addr = ::
+ port = 0
+ type = acct
+# interface = eth0
+# clients = per_socket_clients
+
+ limit {
+ # The number of packets received can be rate limited via the
+ # "max_pps" configuration item. When it is set, the server
+ # tracks the total number of packets received in the previous
+ # second. If the count is greater than "max_pps", then the
+ # new packet is silently discarded. This helps the server
+ # deal with overload situations.
+ #
+ # The packets/s counter is tracked in a sliding window. This
+ # means that the pps calculation is done for the second
+ # before the current packet was received. NOT for the current
+ # wall-clock second, and NOT for the previous wall-clock second.
+ #
+ # Useful values are 0 (no limit), or 100 to 10000.
+ # Values lower than 100 will likely cause the server to ignore
+ # normal traffic. Few systems are capable of handling more than
+ # 10K packets/s.
+ #
+ # It is most useful for accounting systems. Set it to 50%
+ # more than the normal accounting load, and you can be sure that
+ # the server will never get overloaded
+ #
+# max_pps = 0
+
+ # Only for "proto = tcp". These are ignored for "udp" sockets.
+ #
+# idle_timeout = 0
+# lifetime = 0
+# max_connections = 0
+ }
+}
+
+# IPv6 versions of the above - read their full config to understand options
+listen {
+ type = auth
+ ipv6addr = :: # any. ::1 == localhost
+ port = 0
+# interface = eth0
+# clients = per_socket_clients
+ limit {
+ max_connections = 16
+ lifetime = 0
+ idle_timeout = 30
+ }
+}
+
+listen {
+ ipv6addr = ::
+ port = 0
+ type = acct
+# interface = eth0
+# clients = per_socket_clients
+
+ limit {
+# max_pps = 0
+# idle_timeout = 0
+# lifetime = 0
+# max_connections = 0
+ }
+}
+
+# Authorization. First preprocess (hints and huntgroups files),
+# then realms, and finally look in the "users" file.
+#
+# Any changes made here should also be made to the "inner-tunnel"
+# virtual server.
+#
+# 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 {
+ #
+ # Take a User-Name, and perform some checks on it, for spaces and other
+ # invalid characters. If the User-Name appears invalid, reject the
+ # request.
+ #
+ # See policy.d/filter for the definition of the filter_username policy.
+ #
+ filter_username
+
+ #
+ # Some broken equipment sends passwords with embedded zeros.
+ # i.e. the debug output will show
+ #
+ # User-Password = "password\000\000"
+ #
+ # This policy will fix it to just be "password".
+ #
+# filter_password
+
+ #
+ # The preprocess module takes care of sanitizing some bizarre
+ # attributes in the request, and turning them into attributes
+ # which are more standard.
+ #
+ # It takes care of processing the 'raddb/mods-config/preprocess/hints'
+ # and the 'raddb/mods-config/preprocess/huntgroups' files.
+ preprocess
+
+ # If you intend to use CUI and you require that the Operator-Name
+ # be set for CUI generation and you want to generate CUI also
+ # for your local clients then uncomment the operator-name
+ # below and set the operator-name for your clients in clients.conf
+# operator-name
+
+ #
+ # If you want to generate CUI for some clients that do not
+ # send proper CUI requests, then uncomment the
+ # cui below and set "add_cui = yes" for these clients in clients.conf
+# cui
+
+ #
+ # If you want to have a log of authentication requests,
+ # un-comment the following line.
+# auth_log
+
+ #
+ # The chap module will set 'Auth-Type := CHAP' if we are
+ # handling a CHAP request and Auth-Type has not already been set
+ chap
+
+ #
+ # 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
+
+ #
+ # If you have a Cisco SIP server authenticating against
+ # FreeRADIUS, uncomment the following line, and the 'digest'
+ # line in the 'authenticate' section.
+ digest
+
+ #
+ # The WiMAX specification says that the Calling-Station-Id
+ # is 6 octets of the MAC. This definition conflicts with
+ # RFC 3580, and all common RADIUS practices. If you are using
+ # old style WiMAX (non LTE) the un-commenting the "wimax" module
+ # here means that it will fix the Calling-Station-Id attribute to
+ # the normal format as specified in RFC 3580 Section 3.21.
+ #
+ # If you are using WiMAX 2.1 (LTE) then un-commenting will allow
+ # the module to handle SQN resyncronisation. Prior to calling the
+ # module it is necessary to populate the following attributes
+ # with the relevant keys:
+ # control:WiMAX-SIM-Ki
+ # control:WiMAX-SIM-OPc
+ #
+ # If WiMAX-Re-synchronization-Info is found in the request then
+ # the module will attempt to extract SQN and store it in
+ # control:WiMAX-SIM-SQN. Also a copy of RAND is extracted to
+ # control:WiMAX-SIM-RAND.
+ #
+ # If the SIM cannot be authenticated using Ki and OPc then reject
+ # will be returned.
+# wimax
+
+ #
+ # Look for IPASS style 'realm/', and if not found, look for
+ # '@realm', and decide whether or not to proxy, based on
+ # that.
+# IPASS
+
+ #
+ # Look for realms in user@domain format
+ suffix
+# ntdomain
+
+ #
+ # This module takes care of EAP-MD5, EAP-TLS, and EAP-LEAP
+ # authentication.
+ #
+ # It also sets the EAP-Type attribute in the request
+ # attribute list to the EAP type from the packet.
+ #
+ # The EAP module returns "ok" or "updated" if it is not yet ready
+ # to authenticate the user. The configuration below checks for
+ # "ok", and stops processing the "authorize" section if so.
+ #
+ # Any LDAP and/or SQL servers will not be queried for the
+ # initial set of packets that go back and forth to set up
+ # TTLS or PEAP.
+ #
+ # The "updated" check is commented out for compatibility with
+ # previous versions of this configuration, but you may wish to
+ # uncomment it as well; this will further reduce the number of
+ # LDAP and/or SQL queries for TTLS or PEAP.
+ #
+ eap {
+ ok = return
+# updated = return
+ }
+
+ #
+ # Pull crypt'd passwords from /etc/passwd or /etc/shadow,
+ # using the system API's to get the password. If you want
+ # to read /etc/passwd or /etc/shadow directly, see the
+ # mods-available/passwd module.
+ #
+# unix
+
+ #
+ # Read the 'users' file. In v3, this is located in
+ # raddb/mods-config/files/authorize
+ files
+
+ #
+ # Look in an SQL database. The schema of the database
+ # is meant to mirror the "users" file.
+ #
+ # See "Authorization Queries" in mods-available/sql
+ -sql
+
+ #
+ # If you are using /etc/smbpasswd, and are also doing
+ # mschap authentication, the un-comment this line, and
+ # configure the 'smbpasswd' module.
+# smbpasswd
+
+ #
+ # The ldap module reads passwords from the LDAP database.
+ -ldap
+
+ #
+ # If you're using Active Directory and PAP, then uncomment
+ # the following lines, and the "Auth-Type LDAP" section below.
+ #
+ # This will let you do PAP authentication to AD.
+ #
+# if ((ok || updated) && User-Password && !control:Auth-Type) {
+# update control {
+# &Auth-Type := ldap
+# }
+# }
+
+ #
+ # Enforce daily limits on time spent logged in.
+# daily
+
+ #
+ expiration
+ logintime
+
+ #
+ # If no other module has claimed responsibility for
+ # authentication, then try to use PAP. This allows the
+ # other modules listed above to add a "known good" password
+ # to the request, and to do nothing else. The PAP module
+ # will then see that password, and use it to do PAP
+ # authentication.
+ #
+ # This module should be listed last, so that the other modules
+ # get a chance to set Auth-Type for themselves.
+ #
+ pap
+
+ #
+ # If "status_server = yes", then Status-Server messages are passed
+ # through the following section, and ONLY the following section.
+ # This permits you to do DB queries, for example. If the modules
+ # listed here return "fail", then NO response is sent.
+ #
+# Autz-Type Status-Server {
+#
+# }
+
+ #
+ # RADIUS/TLS (or RadSec) connections are processed through
+ # this section. See sites-available/tls, and the configuration
+ # item "check_client_connections" for more information.
+ #
+ # The request contains TLS client certificate attributes,
+ # and nothing else. The debug output will print which
+ # attributes are available on your system.
+ #
+ # If the section returns "ok" or "updated", then the
+ # connection is accepted. Otherwise the connection is
+ # terminated.
+ #
+ Autz-Type New-TLS-Connection {
+ ok
+ }
+}
+
+
+# Authentication.
+#
+#
+# This section lists which modules are available for authentication.
+# Note that it does NOT mean 'try each module in order'. It means
+# that a module from the 'authorize' section adds a configuration
+# attribute 'Auth-Type := FOO'. That authentication type is then
+# used to pick the appropriate module from the list below.
+#
+
+# In general, you SHOULD NOT set the Auth-Type attribute. The server
+# will figure it out on its own, and will do the right thing. The
+# most common side effect of erroneously setting the Auth-Type
+# attribute is that one authentication method will work, but the
+# others will not.
+#
+# The common reasons to set the Auth-Type attribute by hand
+# is to either forcibly reject the user (Auth-Type := Reject),
+# or to or forcibly accept the user (Auth-Type := Accept).
+#
+# Note that Auth-Type := Accept will NOT work with EAP.
+#
+# Please do not put "unlang" configurations into the "authenticate"
+# section. Put them in the "post-auth" section instead. That's what
+# the post-auth section is for.
+#
+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
+ }
+
+ #
+ # For old names, too.
+ #
+ mschap
+
+ #
+ # If you have a Cisco SIP server authenticating against
+ # FreeRADIUS, uncomment the following line, and the 'digest'
+ # line in the 'authorize' section.
+ digest
+
+ #
+ # Pluggable Authentication Modules.
+# pam
+
+ # Uncomment it if you want to use ldap for authentication
+ #
+ # Note that this means "check plain-text password against
+ # the ldap database", which means that EAP won't work,
+ # as it does not supply a plain-text password.
+ #
+ # We do NOT recommend using this. LDAP servers are databases.
+ # They are NOT authentication servers. FreeRADIUS is an
+ # authentication server, and knows what to do with authentication.
+ # LDAP servers do not.
+ #
+ # However, it is necessary for Active Directory, because
+ # Active Directory won't give the passwords to FreeRADIUS.
+ #
+# Auth-Type LDAP {
+# ldap
+# }
+
+ #
+ # Allow EAP authentication.
+ eap
+
+ #
+ # The older configurations sent a number of attributes in
+ # Access-Challenge packets, which wasn't strictly correct.
+ # If you want to filter out these attributes, uncomment
+ # the following lines.
+ #
+# Auth-Type eap {
+# eap {
+# handled = 1
+# }
+# if (handled && (Response-Packet-Type == Access-Challenge)) {
+# attr_filter.access_challenge.post-auth
+# handled # override the "updated" code from attr_filter
+# }
+# }
+}
+
+
+#
+# Pre-accounting. Decide which accounting type to use.
+#
+preacct {
+ preprocess
+
+ #
+ # Merge Acct-[Input|Output]-Gigawords and Acct-[Input-Output]-Octets
+ # into a single 64bit counter Acct-[Input|Output]-Octets64.
+ #
+# acct_counters64
+
+ #
+ # Session start times are *implied* in RADIUS.
+ # The NAS never sends a "start time". Instead, it sends
+ # a start packet, *possibly* with an Acct-Delay-Time.
+ # The server is supposed to conclude that the start time
+ # was "Acct-Delay-Time" seconds in the past.
+ #
+ # The code below creates an explicit start time, which can
+ # then be used in other modules. It will be *mostly* correct.
+ # Any errors are due to the 1-second resolution of RADIUS,
+ # and the possibility that the time on the NAS may be off.
+ #
+ # The start time is: NOW - delay - session_length
+ #
+
+# update request {
+# &FreeRADIUS-Acct-Session-Start-Time = "%{expr: %l - %{%{Acct-Session-Time}:-0} - %{%{Acct-Delay-Time}:-0}}"
+# }
+
+
+ #
+ # Ensure that we have a semi-unique identifier for every
+ # request, and many NAS boxes are broken.
+ acct_unique
+
+ #
+ # 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.
+# IPASS
+ suffix
+# ntdomain
+
+ #
+ # Read the 'acct_users' file
+ files
+}
+
+#
+# Accounting. Log the accounting data.
+#
+accounting {
+ # Update accounting packet by adding the CUI attribute
+ # recorded from the corresponding Access-Accept
+ # use it only if your NAS boxes do not support CUI themselves
+# cui
+ #
+ # Create a 'detail'ed log of the packets.
+ # Note that accounting requests which are proxied
+ # are also logged in the detail file.
+ detail
+# daily
+
+ # Update the wtmp file
+ #
+ # If you don't use "radlast", you can delete this line.
+ unix
+
+ #
+ # For Simultaneous-Use tracking.
+ #
+ # Due to packet losses in the network, the data here
+ # may be incorrect. There is little we can do about it.
+# radutmp
+# sradutmp
+
+ #
+ # Return an address to the IP Pool when we see a stop record.
+ #
+ # Ensure that &control:Pool-Name is set to determine which
+ # pool of IPs are used.
+# sqlippool
+
+ #
+ # Log traffic to an SQL database.
+ #
+ # See "Accounting queries" in mods-available/sql
+ -sql
+
+ #
+ # If you receive stop packets with zero session length,
+ # they will NOT be logged in the database. The SQL module
+ # will print a message (only in debugging mode), and will
+ # return "noop".
+ #
+ # You can ignore these packets by uncommenting the following
+ # three lines. Otherwise, the server will not respond to the
+ # accounting request, and the NAS will retransmit.
+ #
+# if (noop) {
+# ok
+# }
+
+ # Cisco VoIP specific bulk accounting
+# pgsql-voip
+
+ # For Exec-Program and Exec-Program-Wait
+ exec
+
+ # Filter attributes from the accounting response.
+ attr_filter.accounting_response
+
+ #
+ # See "Autz-Type Status-Server" for how this works.
+ #
+# Acct-Type Status-Server {
+#
+# }
+}
+
+
+# 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
+
+ #
+ # See "Simultaneous Use Checking Queries" in mods-available/sql
+# sql
+}
+
+
+# Post-Authentication
+# Once we KNOW that the user has been authenticated, there are
+# additional steps we can take.
+post-auth {
+ #
+ # If you need to have a State attribute, you can
+ # add it here. e.g. for later CoA-Request with
+ # State, and Service-Type = Authorize-Only.
+ #
+# if (!&reply:State) {
+# update reply {
+# State := "0x%{randstr:16h}"
+# }
+# }
+
+ #
+ # Reject packets where User-Name != TLS-Client-Cert-Common-Name
+ # There is no reason for users to lie about their names.
+ #
+ # In general, User-Name == EAP Identity == TLS-Client-Cert-Common-Name
+ #
+# verify_tls_client_common_name
+
+ #
+ # If there is no Stripped-User-Name in the request, AND we have a client cert,
+ # then create a Stripped-User-Name from the TLS client certificate information.
+ #
+ # Note that this policy MUST be edited for your local system!
+ # We do not know which fields exist in which certificate, as
+ # there is no standard here. There is no way for us to have
+ # a default configuration which "just works" everywhere. We
+ # can only make recommendations.
+ #
+ # The Stripped-User-Name is updated so that it is logged in
+ # the various "username" fields. This logging means that you
+ # can associate a particular session with a particular client
+ # certificate.
+ #
+# if (&EAP-Message && !&Stripped-User-Name && &TLS-Client-Cert-Serial) {
+# update request {
+# &Stripped-User-Name := "%{%{TLS-Client-Cert-Subject-Alt-Name-Email}:-%{%{TLS-Client-Cert-Common-Name}:-%{TLS-Client-Cert-Serial}}}"
+# }
+#
+ #
+ # Create a Class attribute which is a hash of a bunch
+ # of information which we hope exists. This
+ # attribute should be echoed back in
+ # Accounting-Request packets, which will let the
+ # administrator correlate authentication and
+ # accounting.
+ #
+# update reply {
+# Class += "%{md5:%{Calling-Station-Id}%{Called-Station-Id}%{TLS-Client-Cert-Subject-Alt-Name-Email}%{TLS-Client-Cert-Common-Name}%{TLS-Client-Cert-Serial}%{NAS-IPv6-Address}%{NAS-IP-Address}%{NAS-Identifier}%{NAS-Port}"
+# }
+#
+# }
+
+ #
+ # For EAP-TTLS and PEAP, add the cached attributes to the reply.
+ # The "session-state" attributes are automatically cached when
+ # an Access-Challenge is sent, and automatically retrieved
+ # when an Access-Request is received.
+ #
+ # The session-state attributes are automatically deleted after
+ # an Access-Reject or Access-Accept is sent.
+ #
+ # If both session-state and reply contain a User-Name attribute, remove
+ # the one in the reply if it is just a copy of the one in the request, so
+ # we don't end up with two User-Name attributes.
+
+ if (session-state:User-Name && reply:User-Name && request:User-Name && (reply:User-Name == request:User-Name)) {
+ update reply {
+ &User-Name !* ANY
+ }
+ }
+ update {
+ &reply: += &session-state:
+ }
+
+ #
+ # Refresh leases when we see a start or alive. Return an address to
+ # the IP Pool when we see a stop record.
+ #
+ # Ensure that &control:Pool-Name is set to determine which
+ # pool of IPs are used.
+# sqlippool
+
+
+ # Create the CUI value and add the attribute to Access-Accept.
+ # Uncomment the line below if *returning* the CUI.
+# cui
+
+ # Create empty accounting session to make simultaneous check
+ # more robust. See the accounting queries configuration in
+ # raddb/mods-config/sql/main/*/queries.conf for details.
+ #
+ # The "sql_session_start" policy is defined in
+ # raddb/policy.d/accounting. See that file for more details.
+# sql_session_start
+
+ #
+ # If you want to have a log of authentication replies,
+ # un-comment the following line, and enable the
+ # 'detail reply_log' module.
+# reply_log
+
+ #
+ # After authenticating the user, do another SQL query.
+ #
+ # See "Authentication Logging Queries" in mods-available/sql
+ -sql
+
+ #
+ # Un-comment the following if you want to modify the user's object
+ # in LDAP after a successful login.
+ #
+# ldap
+
+ # For Exec-Program and Exec-Program-Wait
+ exec
+
+ #
+ # In order to calcualate the various keys for old style WiMAX
+ # (non LTE) you will need to define the WiMAX NAI, usually via
+ #
+ # update request {
+ # &WiMAX-MN-NAI = "%{User-Name}"
+ # }
+ #
+ # If you want various keys to be calculated, you will need to
+ # update the reply with "template" values. The module will see
+ # this, and replace the template values with the correct ones
+ # taken from the cryptographic calculations. e.g.
+ #
+ # update reply {
+ # &WiMAX-FA-RK-Key = 0x00
+ # &WiMAX-MSK = "%{reply:EAP-MSK}"
+ # }
+ #
+ # You may want to delete the MS-MPPE-*-Keys from the reply,
+ # as some WiMAX clients behave badly when those attributes
+ # are included. See "raddb/modules/wimax", configuration
+ # entry "delete_mppe_keys" for more information.
+ #
+ # For LTE style WiMAX you need to populate the following with the
+ # relevant values:
+ # control:WiMAX-SIM-Ki
+ # control:WiMAX-SIM-OPc
+ # control:WiMAX-SIM-AMF
+ # control:WiMAX-SIM-SQN
+ #
+# wimax
+
+ # If there is a client certificate (EAP-TLS, sometimes PEAP
+ # and TTLS), then some attributes are filled out after the
+ # certificate verification has been performed. These fields
+ # MAY be available during the authentication, or they may be
+ # available only in the "post-auth" section.
+ #
+ # The first set of attributes contains information about the
+ # issuing certificate which is being used. The second
+ # contains information about the client certificate (if
+ # available).
+#
+# update reply {
+# Reply-Message += "%{TLS-Cert-Serial}"
+# Reply-Message += "%{TLS-Cert-Expiration}"
+# Reply-Message += "%{TLS-Cert-Subject}"
+# Reply-Message += "%{TLS-Cert-Issuer}"
+# Reply-Message += "%{TLS-Cert-Common-Name}"
+# Reply-Message += "%{TLS-Cert-Subject-Alt-Name-Email}"
+#
+# Reply-Message += "%{TLS-Client-Cert-Serial}"
+# Reply-Message += "%{TLS-Client-Cert-Expiration}"
+# Reply-Message += "%{TLS-Client-Cert-Subject}"
+# Reply-Message += "%{TLS-Client-Cert-Issuer}"
+# Reply-Message += "%{TLS-Client-Cert-Common-Name}"
+# Reply-Message += "%{TLS-Client-Cert-Subject-Alt-Name-Email}"
+# }
+
+ # Insert class attribute (with unique value) into response,
+ # aids matching auth and acct records, and protects against duplicate
+ # Acct-Session-Id. Note: Only works if the NAS has implemented
+ # RFC 2865 behaviour for the class attribute, AND if the NAS
+ # supports long Class attributes. Many older or cheap NASes
+ # only support 16-octet Class attributes.
+# insert_acct_class
+
+ # MacSEC requires the use of EAP-Key-Name. However, we don't
+ # want to send it for all EAP sessions. Therefore, the EAP
+ # modules put required data into the EAP-Session-Id attribute.
+ # This attribute is never put into a request or reply packet.
+ #
+ # Uncomment the next few lines to copy the required data into
+ # the EAP-Key-Name attribute
+# if (&reply:EAP-Session-Id) {
+# update reply {
+# EAP-Key-Name := &reply:EAP-Session-Id
+# }
+# }
+
+ # Remove reply message if the response contains an EAP-Message
+ remove_reply_message_if_eap
+
+ #
+ # Access-Reject packets are sent through the REJECT sub-section of the
+ # post-auth section.
+ #
+ # Add the ldap module name (or instance) if you have set
+ # 'edir = yes' in the ldap module configuration
+ #
+ # The "session-state" attributes are not available here.
+ #
+ Post-Auth-Type REJECT {
+ # log failed authentications in SQL, too.
+ -sql
+ attr_filter.access_reject
+
+ # Insert EAP-Failure message if the request was
+ # rejected by policy instead of because of an
+ # authentication failure
+ eap
+
+ # Remove reply message if the response contains an EAP-Message
+ remove_reply_message_if_eap
+ }
+
+ #
+ # Filter access challenges.
+ #
+ Post-Auth-Type Challenge {
+# remove_reply_message_if_eap
+# attr_filter.access_challenge.post-auth
+ }
+
+ #
+ # The Client-Lost section will be run for a request when
+ # FreeRADIUS has given up waiting for an end-users client to
+ # respond. This is most useful for logging EAP sessions where
+ # the client stopped responding (likely because the
+ # certificate was not acceptable.) i.e. this is not for
+ # RADIUS clients, but for end-user systems.
+ #
+ # This will only be triggered by new packets arriving,
+ # and will be run at some point in the future *after* the
+ # original request has been discarded.
+ #
+ # Therefore the *ONLY* attributes that are available here
+ # are those in the session-state list. If you want data
+ # to log, make sure it is copied to &session-state:
+ # before the client stops responding. NONE of the other
+ # original attributes (request, reply, etc) will be
+ # available.
+ #
+ # This section will only be run if `postauth_client_lost`
+ # is enabled in the main configuration in `radiusd.conf`.
+ #
+ # Note that there are MANY reasons why an end users system
+ # might not respond:
+ #
+ # * it could not get the packet due to firewall issues
+ # * it could not get the packet due to a lossy network
+ # * the users system might not like the servers cert
+ # * the users system might not like something else...
+ #
+ # In some cases, the client is helpful enough to send us a
+ # TLS Alert message, saying what it doesn't like about the
+ # certificate. In other cases, no such message is available.
+ #
+ # All that we can know on the FreeRADIUS side is that we sent
+ # an Access-Challenge, and the client never sent anything
+ # else. The reasons WHY this happens are buried inside of
+ # the logs on the client system. No amount of looking at the
+ # FreeRADIUS logs, or poking the FreeRADIUS configuration
+ # will tell you why the client gave up. The answers are in
+ # the logs on the client side. And no, the FreeRADIUS team
+ # didn't write the client, so we don't know where those logs
+ # are, or how to get at them.
+ #
+ # Information about the TLS state changes is in the
+ # &session-state:TLS-Session-Information attribute.
+ #
+ Post-Auth-Type Client-Lost {
+ #
+ # Debug ALL of the TLS state changes done during the
+ # EAP negotiation.
+ #
+# %{debug_attr:&session-state:TLS-Session-Information[*]}
+
+ #
+ # Debug the LAST TLS state change done during the EAP
+ # negotiation. For errors, this is usually a TLS
+ # alert from the client saying something like
+ # "unknown CA".
+ #
+# %{debug_attr:&session-state:TLS-Session-Information[n]}
+
+ #
+ # Debug the last module failure message. This may be
+ # useful, or it may refer to a server-side failure
+ # which did not cause the client to stop talking to the server.
+ #
+# %{debug_attr:&session-state:Module-Failure-Message}
+ }
+
+ #
+ # If the client sends EAP-Key-Name in the request,
+ # then echo the real value back in the reply.
+ #
+ if (EAP-Key-Name && &reply:EAP-Session-Id) {
+ update reply {
+ &EAP-Key-Name := &reply:EAP-Session-Id
+ }
+ }
+}
+
+#
+# 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 {
+ # Before proxing the request add an Operator-Name attribute identifying
+ # if the operator-name is found for this client.
+ # No need to uncomment this if you have already enabled this in
+ # the authorize section.
+# operator-name
+
+ # The client requests the CUI by sending a CUI attribute
+ # containing one zero byte.
+ # Uncomment the line below if *requesting* the CUI.
+# cui
+
+ # Uncomment the following line if you want to change attributes
+ # as defined in the preproxy_users file.
+# files
+
+ # Uncomment the following line if you want to filter requests
+ # sent to remote servers based on the rules defined in the
+ # 'attrs.pre-proxy' file.
+# attr_filter.pre-proxy
+
+ # If you want to have a log of packets proxied to a home
+ # server, un-comment the following line, and the
+ # 'detail pre_proxy_log' section, above.
+# pre_proxy_log
+}
+
+#
+# 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 want to have a log of replies from a home server,
+ # un-comment the following line, and the 'detail post_proxy_log'
+ # section, above.
+# post_proxy_log
+
+ # Uncomment the following line if you want to filter replies from
+ # remote proxies based on the rules defined in the 'attrs' file.
+# attr_filter.post-proxy
+
+ #
+ # If you are proxying 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
+
+ #
+ # If the server tries to proxy a request and fails, then the
+ # request is processed through the modules in this section.
+ #
+ # The main use of this section is to permit robust proxying
+ # of accounting packets. The server can be configured to
+ # proxy accounting packets as part of normal processing.
+ # Then, if the home server goes down, accounting packets can
+ # be logged to a local "detail" file, for processing with
+ # radrelay. When the home server comes back up, radrelay
+ # will read the detail file, and send the packets to the
+ # home server.
+ #
+ # See the "mods-available/detail.example.com" file for more
+ # details on writing a detail file specifically for one
+ # destination.
+ #
+ # See the "sites-available/robust-proxy-accounting" virtual
+ # server for more details on reading this "detail" file.
+ #
+ # With this configuration, the server always responds to
+ # Accounting-Requests from the NAS, but only writes
+ # accounting packets to disk if the home server is down.
+ #
+# Post-Proxy-Type Fail-Accounting {
+# detail.example.com
+
+ #
+ # Ensure a response is sent to the NAS now that the
+ # packet has been written to a detail file.
+ #
+# acct_response
+# }
+}
+}
diff --git a/raddb/sites-available/dhcp b/raddb/sites-available/dhcp
new file mode 100644
index 0000000..696a395
--- /dev/null
+++ b/raddb/sites-available/dhcp
@@ -0,0 +1,595 @@
+# -*- text -*-
+######################################################################
+#
+# This is a virtual server that handles DHCP.
+#
+# See raddb/mods-available/dhcp_sqlippool for the IP Pool configuration.
+#
+# See raddb/policy.d/dhcp_sqlippool for the "glue" code that allows
+# the RADIUS based "sqlippool" module to be used for DHCP.
+#
+# See raddb/mods-config/sql/ippool/ for the schemas.
+#
+# See raddb/sites-available/dhcp for instructions on how to configure
+# the DHCP server.
+#
+# $Id$
+#
+######################################################################
+
+#
+# The DHCP functionality goes into a virtual server.
+#
+server dhcp {
+
+# Define a DHCP socket.
+#
+# The default port below is 6700, so you don't break your network.
+# If you want it to do real DHCP, change this to 67, and good luck!
+#
+# You can also bind the DHCP socket to an interface.
+# See below, and raddb/radiusd.conf for examples.
+#
+# This lets you run *one* DHCP server instance and have it listen on
+# multiple interfaces, each with a separate policy.
+#
+# If you have multiple interfaces, it is a good idea to bind the
+# listen section to an interface. You will also need one listen
+# section per interface.
+#
+# FreeBSD does *not* support binding sockets to interfaces. Therefore,
+# if you have multiple interfaces, broadcasts may go out of the wrong
+# one, or even all interfaces. The solution is to use the "setfib" command.
+# If you have a network "10.10.0/24" on LAN1, you will need to do:
+#
+# Pick any IP on the 10.10.0/24 network
+# $ setfib 1 route add default 10.10.0.1
+#
+# Edit /etc/rc.local, and add a line:
+# setfib 1 /path/to/radiusd
+#
+# The kern must be built with the following options:
+# options ROUTETABLES=2
+# or any value larger than 2.
+#
+# The other only solution is to update FreeRADIUS to use BPF sockets.
+#
+listen {
+ # This is a dhcp socket.
+ type = dhcp
+
+ # IP address to listen on. Will usually be the IP of the
+ # interface, or 0.0.0.0
+ ipaddr = 127.0.0.1
+
+ # source IP address for unicast packets sent by the
+ # DHCP server.
+ #
+ # The source IP for unicast packets is chosen from the first
+ # one of the following items which returns a valid IP
+ # address:
+ #
+ # src_ipaddr
+ # ipaddr
+ # reply:DHCP-Server-IP-Address
+ # reply:DHCP-DHCP-Server-Identifier
+ #
+ src_ipaddr = 127.0.0.1
+
+ # The port should be 67 for a production network. Don't set
+ # it to 67 on a production network unless you really know
+ # what you're doing. Even if nothing is configured below, the
+ # server may still NAK legitimate responses from clients.
+ port = 6700
+
+ # Interface name we are listening on. See comments above.
+# interface = lo0
+
+ # The DHCP server defaults to allowing broadcast packets.
+ # Set this to "no" only when the server receives *all* packets
+ # from a relay agent. i.e. when *no* clients are on the same
+ # LAN as the DHCP server.
+ #
+ # It's set to "no" here for testing. It will usually want to
+ # be "yes" in production, unless you are only dealing with
+ # relayed packets.
+ broadcast = no
+
+ # On Linux if you're running the server as non-root, you
+ # will need to do:
+ #
+ # setcap cap_net_admin,cap_net_bind_service=eip /path/to/radiusd
+ #
+ # This will allow the server to set ARP table entries
+ # for newly allocated IPs, when run as the "radius" user.
+ #
+ # The above "setcap" command adds the capability to the program,
+ # usually so long as it is run by the "radius" user. Which means
+ # (oddly enough) that it no longer works when run as root!
+ #
+ # When running the server as root in debug mode, you can use:
+ #
+ # capsh --caps="cap_setpcap,cap_setuid,cap_setgid,cap_net_admin,cap_net_bind_service+eip" --keep=1 --user=radius --addamb=cap_net_admin,cap_net_bind_service -- -c "/path/to/radiusd -X"
+ #
+ # Or, simply "sudo" or "su" to the "radius" user, and then run
+ # the server in debug mode.
+
+ # De-duplicate DHCP packets. If clients don't receive
+ # a reply within their timeout, most will re-transmit.
+ # A reply to either packet will satisfy, so de-duplicating
+ # helps manage load on a busy server
+ performance {
+ skip_duplicate_checks = no
+ }
+}
+
+# Packets received on the socket will be processed through one
+# of the following sections, named after the DHCP packet type.
+# See dictionary.dhcp for the packet types.
+
+# Return packets will be sent to, in preference order:
+# DHCP-Gateway-IP-Address
+# DHCP-Client-IP-Address
+# DHCP-Your-IP-Address
+# At least one of these attributes should be set at the end of each
+# section for a response to be sent.
+
+# An internal attribute of DHCP-Network-Subnet is set to provide
+# a basis for determining the network that a client belongs to. This
+# is a hierarchical assignment based on:
+#
+# - DHCP-Relay-Link-Selection
+# - DHCP-Subnet-Selection-Option
+# - DHCP-Gateway-IP-Address
+# - DHCP-Client-IP-Address
+#
+# Except for cases where all IP allocation is performed using a mapping from
+# the device MAC address to a fixed IP address the DHCP configuration will
+# involve the use of one or more pools.
+#
+# Each pool should be composed of a set of equally valid IP addresses for the
+# devices designated as users of the pool. During IP allocation the choice of
+# pool is driven by setting the Pool-Name attribute which may either be
+# specified directly or chosen (usually with the help of the dhcp_network
+# module) based on the initial value of DHCP-Network-Subnet.
+#
+# DHCP-Network-Subnet indicates the network from which the request is
+# originating. In cases where the originating network alone is insufficent to
+# define the required IP allocated policy, DHCP-Network-Subnet may be
+# overridden to force the selection of a particular pool.
+#
+# IP addresses belonging to a single pool that is designated for a Layer 2
+# network containing multiple subnets (a "shared-network" or "multinet"
+# configuration as defined by some other DHCP servers), will by definition be
+# members of distinct subnets that require their own DHCP reply parameters. In
+# this case the dhcp_subnet policy can be used to set the correct
+# DHCP-Subnet-Mask, DHCP-Router-Address and DHCP-Broadcast-Address options
+# based on the allocated IP.
+
+dhcp DHCP-Discover {
+
+ # The DHCP Server Identifier is set here since is returned in OFFERs
+ update control {
+ &DHCP-DHCP-Server-Identifier = 192.0.2.2
+ }
+
+ # Call a policy (defined in policy.d/dhcp) to set common reply attributes
+ dhcp_common
+
+ # Use a "passwd" module to set group memberships in DHCP-Group-Name
+ # Enable mods-available/dhcp_passwd to use this
+ #dhcp_group_membership
+
+ # If clients need to be assigned to a particular network based on
+ # an attribute in the packet rather than the calculated
+ # DHCP-Network-Subnet described above, then call a policy
+ # (defined in policy.d/dhcp) to perform the override
+ #dhcp_override_network
+
+ # Use a "files" module to lookup global and subnet options
+ # For multiple subnets use this in place of dhcp_common
+ # Enable mods-available/dhcp_files to use this
+ # Options are set in mods-config/files/dhcp
+ #dhcp_network
+
+ # Do a simple mapping of MAC to assigned IP.
+ #
+ # See below for the definition of the "mac2ip"
+ # module.
+ #
+ #mac2ip
+
+ # Or, allocate IPs from the DHCP pool in SQL. You may need to
+ # set the pool name here if you haven't set it elsewhere.
+ #update control {
+ # &Pool-Name := "local"
+ #}
+ #dhcp_sqlippool
+
+ # If the IP address was not allocated, do something else.
+ # You could call a Perl, Python, or Java script here.
+ #if (notfound) {
+ # ...
+ #}
+
+ # "Shared-networks" may have multiple IP subnets co-existing in a
+ # single Layer 2 network. If the pool for the network contains
+ # addresses from more that one subnet then the setting subnet-specific
+ # DHCP-Subnet-Mask, DHCP-Router-Address and DHCP-Broadcast-Address
+ # parameters must be performed after the allocation of the IP address.
+ #
+ # Set any subnet-specific parameters using this policy.
+ #
+ # Enable mods-available/dhcp_files AND uncomment dhcp_subnet in
+ # policy.d/dhcp to use this.
+ #
+ #dhcp_subnet
+
+ # Use a "files" module to lookup options based on DHCP-Group-Name
+ # Enable mods-available/dhcp_files to use this
+ # Options are set in mods-config/files/dhcp
+ #dhcp_group_options
+
+ # Use a "files" module to lookup host specific options
+ # Enable mods-available/dhcp_files to use this
+ # Options are set in mods-config/files/dhcp
+ #dhcp_hosts
+
+ # As an alternative or complement to configuration files based lookup
+ # for options data you can instead use an SQL database. Example
+ # configuration is found in dhcp_policy_sql in policy.d/dhcp which
+ # will need to be adapted to your requirements.
+ #dhcp_policy_sql
+
+ # Set the type of packet to send in reply.
+ #
+ # The server will look at the DHCP-Message-Type attribute to
+ # determine which type of packet to send in reply. Common
+ # values would be DHCP-Offer, DHCP-Ack or DHCP-NAK. See
+ # dictionary.dhcp for all the possible values.
+ #
+ # DHCP-Do-Not-Respond can be used to tell the server to not
+ # respond.
+ #
+ # In the event that DHCP-Message-Type is not set then the
+ # server will fall back to determining the type of reply
+ # based on the rcode of this section.
+ #
+ #update reply {
+ # DHCP-Message-Type = DHCP-Offer
+ #}
+ #
+ # If DHCP-Message-Type is not set, returning "ok" or
+ # "updated" from this section will respond with a DHCP-Offer
+ # message.
+ #
+ # Other rcodes will tell the server to not return any response.
+ #
+ #ok
+}
+
+dhcp DHCP-Request {
+
+ # You must set the DHCP Server Identifier here since this is returned
+ # in ACKs and is used to determine whether a request containing a
+ # "server-ip" field is intended for this server
+ update control {
+ &DHCP-DHCP-Server-Identifier = 192.0.2.2
+ }
+
+ # If the request is not for this server then silently discard it
+ if (&request:DHCP-DHCP-Server-Identifier && \
+ &request:DHCP-DHCP-Server-Identifier != &control:DHCP-DHCP-Server-Identifier) {
+ do_not_respond
+ }
+
+ # Response packet type. See DHCP-Discover section above.
+ #update reply {
+ # &DHCP-Message-Type = DHCP-Ack
+ #}
+
+ # Call a policy (defined in policy.d/dhcp) to set common reply attributes
+ dhcp_common
+
+ # Use a "passwd" module to set group memberships in DHCP-Group-Name
+ # Enable mods-available/dhcp_passwd to use this
+ #dhcp_group_membership
+
+ # Optionally override the network address based on client attributes
+ # See Discover section
+ #dhcp_override_network
+
+ # Use a "files" module to lookup global and subnet options
+ # For multiple subnets use this in place of dhcp_common
+ # Enable mods-available/dhcp_files AND uncomment dhcp_subnet in
+ # policy.d/dhcp to use this
+ # Options are set in mods-config/files/dhcp
+ #dhcp_network
+
+ # Do a simple mapping of MAC to assigned IP.
+ #
+ # See below for the definition of the "mac2ip"
+ # module.
+ #
+ #mac2ip
+
+ # Or, allocate IPs from the DHCP pool in SQL. You may need to
+ # set the pool name here if you haven't set it elsewhere.
+# update control {
+# &Pool-Name := "local"
+# }
+# dhcp_sqlippool_request
+
+ # If the IP was not allocated, do something else.
+ # You could call a Perl, Python, or Java script here.
+ #if (notfound) {
+ # ...
+ #}
+
+ # "Shared-networks" may have multiple IP subnets co-existing in a
+ # single Layer 2 network. If the pool for the network contains
+ # addresses from more that one subnet then the setting subnet-specific
+ # DHCP-Subnet-Mask, DHCP-Router-Address and DHCP-Broadcast-Address
+ # parameters must be performed after the allocation of the IP address.
+ #
+ # Set any subnet-specific parameters using this policy.
+ #
+ #dhcp_subnet
+
+ # Use a "files" module to lookup options based on DHCP-Group-Name
+ # Enable mods-available/dhcp_files to use this
+ # Options are set in mods-config/files/dhcp
+ #dhcp_group_options
+
+ # Use a "files" module to lookup host specific options
+ # Enable mods-available/dhcp_files to use this
+ # Options are set in mods-config/files/dhcp
+ #dhcp_hosts
+
+ # As an alternative or complement to configuration files based lookup
+ # for options data you can instead use an SQL database. Example
+ # configuration is found in dhcp_policy_sql in policy.d/dhcp which
+ # will need to be adapted to your requirements.
+ #dhcp_policy_sql
+
+ # If DHCP-Message-Type is not set, returning "ok" or
+ # "updated" from this section will respond with a DHCP-Ack
+ # packet.
+ #
+ # "handled" will not return a packet, all other rcodes will
+ # send back a DHCP-NAK.
+ #
+ #ok
+}
+
+#
+# Other DHCP packet types
+#
+# There should be a separate section for each DHCP message type.
+# By default this configuration will ignore them all. Any packet type
+# not defined here will be responded to with a DHCP-NAK.
+
+dhcp DHCP-Decline {
+
+ # Use a "passwd" module to set group memberships in DHCP-Group-Name
+ # Enable mods-available/dhcp_passwd to use this
+ #dhcp_group_membership
+
+ # Optionally override the network address based on client attributes
+ # See Discover section
+ #dhcp_override_network
+
+ # Use a "files" module to lookup global and subnet options
+ # For multiple networks use this in place of dhcp_common
+ # Enable mods-available/dhcp_files to use this
+ # Options are set in mods-config/files/dhcp
+ #dhcp_network
+
+ # Use a policy that set options from data stored in an SQL database
+ #dhcp_policy_sql
+
+ # If using IPs from a DHCP pool in SQL then you may need to set the
+ # pool name here if you haven't set it elsewhere and release the IP.
+# update control {
+# &Pool-Name := "local"
+# }
+# dhcp_sqlippool_decline
+
+ update reply {
+ &DHCP-Message-Type = DHCP-Do-Not-Respond
+ }
+ reject
+}
+
+#
+# A dummy config for Inform packets - this should match the
+# options set in the Request section above, except Inform replies
+# must not set Your-IP-Address or IP-Address-Lease-Time
+#
+dhcp DHCP-Inform {
+ # Call a policy (defined in policy.d/dhcp) to set common reply attributes
+ dhcp_common
+
+ # Use a "passwd" module to set group memberships in DHCP-Group-Name
+ # Enable mods-available/dhcp_passwd to use this
+ #dhcp_group_membership
+
+ # Optionally override the network address based on client attributes
+ # See Discover section
+ #dhcp_override_network
+
+ # Use a "files" module to lookup global and network options
+ # For multiple networks use this in place of dhcp_common
+ # Enable mods-available/dhcp_files to use this
+ # Options are set in mods-config/files/dhcp
+ #dhcp_network
+
+ # Use a policy with calls a "files" module of the same name to lookup
+ # subnet options
+ # Enable mods-available/dhcp_files AND uncomment dhcp_subnet in
+ # policy.d/dhcp to use this
+ # Options are set in mods-config/files/dhcp
+ #dhcp_subnet
+
+ # Use a "files" module to lookup options based on DHCP-Group-Name
+ # Enable mods-available/dhcp_files to use this
+ # Options are set in mods-config/files/dhcp
+ #dhcp_group_options
+
+ # Use a "files" module to lookup host specific options
+ # Enable mods-available/dhcp_files to use this
+ # Options are set in mods-config/files/dhcp
+ #dhcp_hosts
+
+ # Use a policy that set options from data stored in an SQL database
+ #dhcp_policy_sql
+
+ ok
+}
+
+#
+# For Windows 7 boxes
+#
+#dhcp DHCP-Inform {
+# update reply {
+# Packet-Dst-Port = 67
+# DHCP-Message-Type = DHCP-ACK
+# DHCP-DHCP-Server-Identifier = "%{Packet-Dst-IP-Address}"
+# DHCP-Site-specific-28 = 0x0a00
+# }
+# ok
+#}
+
+dhcp DHCP-Release {
+
+ # Use a "passwd" module to set group memberships in DHCP-Group-Name
+ # Enable mods-available/dhcp_passwd to use this
+ #dhcp_group_membership
+
+ # Optionally override the network address based on client attributes
+ # See Discover section
+ #dhcp_override_network
+
+ # Use a "files" module to lookup global and subnet options
+ # For multiple subnets use this in place of dhcp_common
+ # Enable mods-available/dhcp_files to use this
+ # Options are set in mods-config/files/dhcp
+ #dhcp_network
+
+ # If using IPs from a DHCP pool in SQL then you may need to set the
+ # pool name here if you haven't set it elsewhere and release the IP.
+# update control {
+# &Pool-Name := "local"
+# }
+# dhcp_sqlippool_release
+
+ update reply {
+ &DHCP-Message-Type = DHCP-Do-Not-Respond
+ }
+ reject
+}
+
+
+dhcp DHCP-Lease-Query {
+ # The thing being queried for is implicit
+ # in the packets.
+
+ # has MAC, asking for IP, etc.
+ if (&DHCP-Client-Hardware-Address) {
+ # look up MAC in database
+ }
+
+ # has IP, asking for MAC, etc.
+ elsif (&DHCP-Your-IP-Address) {
+ # look up IP in database
+ }
+
+ # has host name, asking for IP, MAC, etc.
+ elsif (&DHCP-Client-Identifier) {
+ # look up identifier in database
+ }
+ else {
+ update reply {
+ &DHCP-Message-Type = DHCP-Lease-Unknown
+ }
+
+ ok
+
+ # stop processing
+ return
+ }
+
+ #
+ # We presume that the database lookup returns "notfound"
+ # if it can't find anything.
+ #
+ if (notfound) {
+ update reply {
+ &DHCP-Message-Type = DHCP-Lease-Unknown
+ }
+ ok
+ return
+ }
+
+ #
+ # Add more logic here. Is the lease inactive?
+ # If so, respond with DHCP-Lease-Unassigned.
+ #
+ # Otherwise, respond with DHCP-Lease-Active
+ #
+
+ #
+ # Also be sure to return ALL information about
+ # the lease.
+ #
+
+ #
+ # The reply types are:
+ #
+ # DHCP-Lease-Unknown
+ # DHCP-Lease-Active
+ # DHCP-Lease-Unassigned
+ #
+ update reply {
+ &DHCP-Message-Type = DHCP-Lease-Unassigned
+ }
+
+}
+
+}
+
+######################################################################
+#
+# This next section is a sample configuration for the "passwd"
+# module, that reads flat-text files. It should go into
+# radiusd.conf, in the "modules" section.
+#
+# The file is in the format <mac>,<ip>
+#
+# 00:01:02:03:04:05,192.0.2.100
+# 01:01:02:03:04:05,192.0.2.101
+# 02:01:02:03:04:05,192.0.2.102
+#
+# This lets you perform simple static IP assignment.
+#
+# There is a preconfigured "mac2ip" module setup in
+# mods-available/mac2ip. To use it do:
+#
+# # cd raddb/
+# # ln -s ../mods-available/mac2ip mods-enabled/mac2ip
+# # mkdir mods-config/passwd
+#
+# Then create the file mods-config/passwd/mac2ip with the above
+# format.
+#
+######################################################################
+
+
+# This is an example only - see mods-available/mac2ip instead; do
+# not uncomment these lines here.
+#
+#passwd mac2ip {
+# filename = ${confdir}/mac2ip
+# format = "*DHCP-Client-Hardware-Address:=DHCP-Your-IP-Address"
+# delimiter = ","
+#}
diff --git a/raddb/sites-available/dhcp.relay b/raddb/sites-available/dhcp.relay
new file mode 100644
index 0000000..76d1e10
--- /dev/null
+++ b/raddb/sites-available/dhcp.relay
@@ -0,0 +1,44 @@
+# -*- text -*-
+######################################################################
+#
+# This is a virtual server that handles DHCP relaying
+#
+# Only one server can listen on a socket, so you cannot
+# do DHCP relaying && run a DHCP server at the same time.
+#
+######################################################################
+
+server dhcp.eth1 {
+ listen {
+ ipaddr = *
+ port = 67
+ type = dhcp
+ interface = eth1
+ }
+
+ # Packets received on the socket will be processed through one
+ # of the following sections, named after the DHCP packet type.
+ # See dictionary.dhcp for the packet types.
+ dhcp DHCP-Discover {
+ update config {
+ # IP Address of the DHCP server
+ &DHCP-Relay-To-IP-Address := 192.0.2.2
+ }
+ update request {
+ # IP Address of the DHCP relay (ourselves)
+ &DHCP-Gateway-IP-Address := 192.0.2.1
+ }
+ ok
+ }
+
+ dhcp DHCP-Request {
+ update config {
+ # IP Address of the DHCP server
+ &DHCP-Relay-To-IP-Address := 192.0.2.2
+ }
+ update request {
+ &DHCP-Gateway-IP-Address := 192.0.2.2
+ }
+ ok
+ }
+}
diff --git a/raddb/sites-available/dynamic-clients b/raddb/sites-available/dynamic-clients
new file mode 100644
index 0000000..0459a7f
--- /dev/null
+++ b/raddb/sites-available/dynamic-clients
@@ -0,0 +1,222 @@
+# -*- text -*-
+######################################################################
+#
+# Sample configuration file for dynamically updating the list
+# of RADIUS clients at run time.
+#
+# Everything is keyed off of a client "network". (e.g. 192.0.2/24)
+# This configuration lets the server know that clients within
+# that network are defined dynamically.
+#
+# When the server receives a packet from an unknown IP address
+# within that network, it tries to find a dynamic definition
+# for that client. If the definition is found, the IP address
+# (and other configuration) is added to the server's internal
+# cache of "known clients", with a configurable lifetime.
+#
+# Further packets from that IP address result in the client
+# definition being found in the cache. Once the lifetime is
+# reached, the client definition is deleted, and any new requests
+# from that client are looked up as above.
+#
+# If the dynamic definition is not found, then the request is
+# treated as if it came from an unknown client. i.e. It is
+# silently discarded.
+#
+# As part of protection from Denial of Service (DoS) attacks,
+# the server will add only one new client per second. This CANNOT
+# be changed, and is NOT configurable.
+#
+# $Id$
+#
+######################################################################
+
+#
+# Define a network where clients may be dynamically defined.
+client dynamic {
+ #
+ # You MUST specify a netmask!
+ # IPv4 /32 or IPv6 /128 are NOT allowed!
+ ipaddr = 192.0.2.0/24
+
+ #
+ # Any other configuration normally found in a "client"
+ # entry can be used here.
+
+ #
+ # A shared secret does NOT have to be defined. It can
+ # be left out.
+
+ #
+ # Define the virtual server used to discover dynamic clients.
+ dynamic_clients = dynamic_clients
+
+ #
+ # The directory where client definitions are stored. This
+ # needs to be used ONLY if the client definitions are stored
+ # in flat-text files. Each file in that directory should be
+ # ONE and only one client definition. The name of the file
+ # should be the IP address of the client.
+ #
+ # If you are storing clients in SQL, this entry should not
+ # be used.
+# directory = ${confdir}/dynamic-clients/
+
+ #
+ # Define the lifetime (in seconds) for dynamic clients.
+ # They will be cached for this lifetime, and deleted afterwards.
+ #
+ # If the lifetime is "0", then the dynamic client is never
+ # deleted. The only way to delete the client is to re-start
+ # the server.
+ lifetime = 3600
+}
+
+#
+# This is the virtual server referenced above by "dynamic_clients".
+server dynamic_clients {
+
+ #
+ # The only contents of the virtual server is the "authorize" section.
+ authorize {
+
+ #
+ # Put any modules you want here. SQL, LDAP, "exec",
+ # Perl, etc. The only requirements is that the
+ # attributes MUST go into the control item list.
+ #
+ # The request that is processed through this section
+ # is EMPTY. There are NO attributes. The request is fake,
+ # and is NOT the packet that triggered the lookup of
+ # the dynamic client.
+ #
+ # The ONLY piece of useful information is either
+ #
+ # Packet-Src-IP-Address (IPv4 clients)
+ # Packet-Src-IPv6-Address (IPv6 clients)
+ #
+ # The attributes used to define a dynamic client mirror
+ # the configuration items in the "client" structure.
+ #
+
+ #
+ # Example 1: Hard-code a client IP. This example is
+ # useless, but it documents the attributes
+ # you need.
+ #
+ update control {
+
+ #
+ # Echo the IP address of the client.
+ &FreeRADIUS-Client-IP-Address = "%{Packet-Src-IP-Address}"
+
+ # require_message_authenticator
+ &FreeRADIUS-Client-Require-MA = no
+
+ # secret
+ &FreeRADIUS-Client-Secret = "testing123"
+
+ # shortname
+ &FreeRADIUS-Client-Shortname = "%{Packet-Src-IP-Address}"
+
+ # nas_type
+ &FreeRADIUS-Client-NAS-Type = "other"
+
+ # virtual_server
+ #
+ # This can ONLY be used if the network client
+ # definition (e.g. "client dynamic" above) has
+ # NO virtual_server defined.
+ #
+ # If the network client definition does have a
+ # virtual_server defined, then that is used,
+ # and there is no need to define this attribute.
+ #
+ &FreeRADIUS-Client-Virtual-Server = "something"
+
+ }
+
+ #
+ # Example 2: Read the clients from "clients" files
+ # in a directory.
+ #
+
+ # This requires you to uncomment the
+ # "directory" configuration in the
+ # "client dynamic" configuration above,
+ # and then put one file per IP address in
+ # that directory.
+ #
+ dynamic_clients
+
+ #
+ # Example 3: Look the clients up in SQL.
+ #
+ # This requires the SQL module to be configured, of course.
+ if ("%{sql: SELECT nasname FROM nas WHERE nasname = '%{Packet-Src-IP-Address}'}") {
+ update control {
+ #
+ # Echo the IP.
+ &FreeRADIUS-Client-IP-Address = "%{Packet-Src-IP-Address}"
+
+ #
+ # Do multiple SELECT statements to grab
+ # the various definitions.
+ &FreeRADIUS-Client-Shortname = "%{sql: SELECT shortname FROM nas WHERE nasname = '%{Packet-Src-IP-Address}'}"
+
+ &FreeRADIUS-Client-Secret = "%{sql: SELECT secret FROM nas WHERE nasname = '%{Packet-Src-IP-Address}'}"
+
+ &FreeRADIUS-Client-NAS-Type = "%{sql: SELECT type FROM nas WHERE nasname = '%{Packet-Src-IP-Address}'}"
+
+ &FreeRADIUS-Client-Virtual-Server = "%{sql: SELECT server FROM nas WHERE nasname = '%{Packet-Src-IP-Address}'}"
+ }
+
+ }
+
+ # Do an LDAP lookup in the elements OU, check to see if
+ # the Packet-Src-IP-Address object has a "ou"
+ # attribute, if it does continue. Change "ACME.COM" to
+ # the real OU of your organization.
+ #
+ # Assuming the following schema:
+ #
+ # OU=Elements,OU=Radius,DC=ACME,DC=COM
+ #
+ # Elements will hold a record of every NAS in your
+ # Network. Create Group objects based on the IP
+ # Address of the NAS and set the "Location" or "l"
+ # attribute to the NAS Huntgroup the NAS belongs to
+ # allow them to be centrally managed in LDAP.
+ #
+ # e.g. CN=10.1.2.3,OU=Elements,OU=Radius,DC=ACME,DC=COM
+ #
+ # With a "l" value of "CiscoRTR" for a Cisco Router
+ # that has a NAS-IP-Address or Source-IP-Address of
+ # 10.1.2.3.
+ #
+ # And with a "ou" value of the shared secret password
+ # for the NAS element. ie "password"
+ if ("%{ldap:ldap:///OU=Elements,OU=Radius,DC=ACME,DC=COM?ou?sub?cn=%{Packet-Src-IP-Address}}") {
+ update control {
+ &FreeRADIUS-Client-IP-Address = "%{Packet-Src-IP-Address}"
+
+ # Set the Client-Shortname to be the Location
+ # "l" just like in the Huntgroups, but this
+ # time to the shortname.
+
+ &FreeRADIUS-Client-Shortname = "%{ldap:ldap:///OU=Elements,OU=Radius,DC=ACME,DC=COM?l?sub?cn=%{Packet-Src-IP-Address}}"
+
+ # Lookup and set the Shared Secret based on
+ # the "ou" attribute.
+ &FreeRADIUS-Client-Secret = "%{ldap:ldap:///OU=Elements,OU=Radius,DC=ACME,DC=COM?ou?sub?cn=%{Packet-Src-IP-Address}}"
+ }
+ }
+
+ #
+ # Tell the caller that the client was defined properly.
+ #
+ # If the authorize section does NOT return "ok", then
+ # the new client is ignored.
+ ok
+ }
+}
diff --git a/raddb/sites-available/example b/raddb/sites-available/example
new file mode 100644
index 0000000..5f204aa
--- /dev/null
+++ b/raddb/sites-available/example
@@ -0,0 +1,122 @@
+######################################################################
+#
+# An example virtual server configuration.
+#
+# $Id$
+#
+######################################################################
+
+
+#
+# This client will be available to any "listen" section that
+# are defined outside of a virtual server section. However,
+# when the server receives a packet from this client, the
+# request will be processed through the "example" virtual
+# server, as the "client" section contains a configuration item
+# to that effect.
+#
+# Note that this client will be able to send requests to any
+# port defined in a global "listen" section. It will NOT,
+# however, be able to send requests to a port defined in a
+# "listen" section that is contained in a "server" section.
+#
+# With careful matching of configurations, you should be able
+# to:
+#
+# - Define one authentication port, but process each client
+# through a separate virtual server.
+#
+# - define multiple authentication ports, each with a private
+# list of clients.
+#
+# - define multiple authentication ports, each of which may
+# have the same client listed, but with different shared
+# secrets
+#
+# FYI: We use an address in the 192.0.2.* space for this example,
+# as RFC 3330 says that that /24 range is used for documentation
+# and examples, and should not appear on the net. You shouldn't
+# use it for anything, either.
+#
+client 192.0.2.10 {
+ shortname = example-client
+ secret = testing123
+ virtual_server = example
+}
+
+######################################################################
+#
+# An example virtual server. It starts off with "server name {"
+# The "name" is used to reference this server from a "listen"
+# or "client" section.
+#
+######################################################################
+server example {
+ #
+ # Listen on 192.0.2.1:1812 for Access-Requests
+ #
+ # When the server receives a packet, it is processed
+ # through the "authorize", etc. sections listed here,
+ # NOT the global ones the "default" site.
+ #
+ listen {
+ ipaddr = 192.0.2.1
+ port = 1821
+ type = auth
+ }
+
+ #
+ # This client is listed within the "server" section,
+ # and is therefore known ONLY to the socket defined
+ # in the "listen" section above. If the client IP
+ # sends a request to a different socket, the server
+ # will treat it as an unknown client, and will not
+ # respond.
+ #
+ # In contrast, the client listed at the top of this file
+ # is outside of any "server" section, and is therefore
+ # global in scope. It can send packets to any port
+ # defined in a global "listen" section. It CANNOT send
+ # packets to the listen section defined above, though.
+ #
+ # Note that you don't have to have a "virtual_server = example"
+ # line here, as the client is encapsulated within
+ # the "server" section.
+ #
+ client 192.0.2.9 {
+ shortname = example-client
+ secret = testing123
+ }
+
+ authorize {
+ #
+ # Some example policies. See "man unlang" for more.
+ #
+ if (&User-Name == 'bob') {
+ update control {
+ &Cleartext-Password := 'bob'
+ }
+ }
+
+ #
+ # And then reject the user. The next line requires
+ # that the "always reject {}" section is defined in
+ # the "modules" section of radiusd.conf.
+ #
+ reject
+ }
+
+ authenticate {
+
+ }
+
+ post-auth {
+
+ Post-Auth-Type Reject {
+ update reply {
+ &Reply-Message = 'This is only an example.'
+ }
+ }
+ }
+
+}
diff --git a/raddb/sites-available/google-ldap-auth b/raddb/sites-available/google-ldap-auth
new file mode 100644
index 0000000..3be530f
--- /dev/null
+++ b/raddb/sites-available/google-ldap-auth
@@ -0,0 +1,225 @@
+# -*- text -*-
+#########################################################################
+#
+# The file contains a sample virtual server which uses Google
+# Secure LDAP for authentication
+#
+# This file is designed to be used as an inner tunnel virtual
+# server for EAP-TTLS-PAP authentication.
+#
+# Use this virtual server in conjunction with the sample Google
+# Secure LDAP module configuration, which is in
+# mods-available/ldap_google.
+#
+# Due to the poor performance of Google Secure LDAP, this
+# configuration also caches information around accepts, rejects,
+# and LDAP qeuries. See mods-available/cache_auth for the
+# configuration of the various "cache" modules used here.
+#
+# The TTL on these caches should be tuned to match site policies
+# - e.g. how long should a user be re-authenticated from a cache
+# without performing an LDAP bind.
+#
+# Typically the caches are beneficial when performing
+# authentication for 802.1x wifi where repeated authentications
+# occur as users roam. We also recommend enabling the "cache"
+# subsection of mods-available/eap. Both kinds of caching can
+# be done at the same time, and both kinds of caching will help
+# improve system performance and stability.
+#
+# $Id$
+#
+#########################################################################
+
+server google-ldap {
+
+#
+# This is only for testing, and not needed in general operation.
+#
+listen {
+ ipaddr = 127.0.0.1
+ port = 18123
+ type = auth
+}
+
+authorize {
+ #
+ # Perform sanity checks on the supplied user name
+ #
+ filter_username
+
+ #
+ # Perform sanity checks comparing inner and outer user name
+ #
+ filter_inner_identity
+
+ #
+ # Split up user names in the form user@domain
+ #
+ split_username_nai
+
+ #
+ # Check the authentication cache to see if this user
+ # recently sucessfully authenticated
+ #
+ update control {
+ &Cache-Status-Only := 'yes'
+ }
+ cache_auth_accept
+
+ #
+ # If there's a cached User-Name / User-Password which matches
+ # what the user sent here, then the user has been
+ # authenticated. We can then avoid interacting with Google's
+ # LDAP server, which significantly improves the performance
+ # of user authentication.
+ #
+ if (ok) {
+ update {
+ &control:Auth-Type := Accept
+ }
+ return
+ }
+
+ #
+ # Check the reject cache to see if this user was
+ # recently rejected
+ #
+ update control {
+ &Cache-Status-Only := 'yes'
+ }
+ cache_auth_reject
+
+ #
+ # If there's a cached User-Name / User-Password which matches
+ # what the user sent here, then the user has been rejected.
+ # As with authentication above, we don't need to check
+ # Google's LDAP server, and can improve performance.
+ #
+ # Note that in may cases rejected users will try over and
+ # over again. This increased load can significantly affect
+ # performance, and can even prevent other users from
+ # authenticating! The solution is to just tell the bad users
+ # to "go away" as quickly as possible, while using minimal
+ # resources.
+ #
+ if (ok) {
+ update {
+ &Module-Failure-Message := "Rejected by cache entry"
+ }
+ reject
+ }
+
+ #
+ # If group membership checks are required, then ensure that
+ # the relevant "cacheable_" option is set against the ldap
+ # instance, and call the ldap module here.
+ #
+ # If group membership is irrelevant, do not call ldap here
+ # to improve performance
+ #
+ # ldap_google
+
+ #
+ # As Google LDAP does not return user passwords,
+ # authentication is only possible by LDAP "bind as user". So
+ # only PAP and TTLS+PAP will work.
+ #
+ # If the request contains a password, then force LDAP "bind
+ # as user".
+ #
+ if (&User-Password && !control:Auth-Type) {
+ update {
+ &control:Auth-Type := ldap
+ }
+
+ #
+ # Look up a user's DN in the cache.
+ #
+ # The standard ldap auth mechanism is 3 steps
+ # - bind as admin user
+ # - lookup the user's DN
+ # - bind as the user
+ #
+ # Caching the DN removes the first two steps
+ # during the lifetime of the cache entry.
+ #
+ # If the ldap module is called above, then this cache
+ # call can be commented out; the DN will have been
+ # retrieved above by the "ldap_google" module.
+ #
+ update control {
+ &Cache-Read-Only := "yes"
+ }
+ cache_ldap_user_dn
+
+ }
+}
+
+authenticate {
+ #
+ # Use an LDAP "bind as user" to authenticate. Google will
+ # check the users' password, and will return success / fail.
+ #
+ Auth-Type LDAP {
+ ldap_google
+ }
+
+}
+
+#
+# Google LDAP has no specific session section configuration
+#
+session {
+
+}
+
+#
+# In post-auth the various caches get updated.
+#
+# Add in any additional policy required to set reply attributes
+#
+post-auth {
+ #
+ # Cache the user's DN. See the authorize section for
+ # how and why this would be used
+ #
+ cache_ldap_user_dn
+
+ #
+ # If a user was authenticated by ldap, add the users name /
+ # password to the cache of successful authentications.
+ #
+ # Otherwise the user was authenticated via the
+ # cache_auth_accept call above, in the "authorize" section.
+ #
+ if (&control:Auth-Type == ldap) {
+ cache_auth_accept
+ }
+
+ Post-Auth-Type REJECT {
+ attr_filter.access_reject
+
+ #
+ # Record rejects in a cache, as a protection against
+ # repeated attempts from mis-configured clients.
+ #
+ if (&control:Auth-Type == ldap) {
+ cache_auth_reject
+ }
+
+ #
+ # Clear the DN cache entry if it exists.
+ # If the DN cache is in use, retaining an incorrect
+ # DN entry could cause issues if the user's DN
+ # has changed.
+ #
+ update control {
+ &Cache-TTL := 0
+ }
+ cache_ldap_user_dn
+
+ }
+}
+
+}
diff --git a/raddb/sites-available/inner-tunnel b/raddb/sites-available/inner-tunnel
new file mode 100644
index 0000000..c178baa
--- /dev/null
+++ b/raddb/sites-available/inner-tunnel
@@ -0,0 +1,468 @@
+# -*- text -*-
+######################################################################
+#
+# This is a virtual server that handles *only* inner tunnel
+# requests for EAP-TTLS and PEAP types.
+#
+# $Id$
+#
+######################################################################
+
+server inner-tunnel {
+
+#
+# This next section is here to allow testing of the "inner-tunnel"
+# authentication methods, independently from the "default" server.
+# It is listening on "localhost", so that it can only be used from
+# the same machine.
+#
+# $ radtest USER PASSWORD 127.0.0.1:18120 0 testing123
+#
+# If it works, you have configured the inner tunnel correctly. To check
+# if PEAP will work, use:
+#
+# $ radtest -t mschap USER PASSWORD 127.0.0.1:18120 0 testing123
+#
+# If that works, PEAP should work. If that command doesn't work, then
+#
+# FIX THE INNER TUNNEL CONFIGURATION SO THAT IT WORKS.
+#
+# Do NOT do any PEAP tests. It won't help. Instead, concentrate
+# on fixing the inner tunnel configuration. DO NOTHING ELSE.
+#
+listen {
+ ipaddr = 127.0.0.1
+ port = 18120
+ type = auth
+}
+
+
+# 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 {
+ #
+ # Take a User-Name, and perform some checks on it, for spaces and other
+ # invalid characters. If the User-Name appears invalid, reject the
+ # request.
+ #
+ # See policy.d/filter for the definition of the filter_username policy.
+ #
+ filter_username
+
+ #
+ # Do checks on outer / inner User-Name, so that users
+ # can't spoof us by using incompatible identities
+ #
+# filter_inner_identity
+
+ #
+ # The chap module will set 'Auth-Type := CHAP' if we are
+ # handling a CHAP request and Auth-Type has not already been set
+ chap
+
+ #
+ # 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
+
+ #
+ # Pull crypt'd passwords from /etc/passwd or /etc/shadow,
+ # using the system API's to get the password. If you want
+ # to read /etc/passwd or /etc/shadow directly, see the
+ # passwd module, above.
+ #
+# unix
+
+ #
+ # Look for IPASS style 'realm/', and if not found, look for
+ # '@realm', and decide whether or not to proxy, based on
+ # that.
+# IPASS
+
+ #
+ # Look for realms in user@domain format
+ #
+ # Note that proxying the inner tunnel authentication means
+ # that the user MAY use one identity in the outer session
+ # (e.g. "anonymous", and a different one here
+ # (e.g. "user@example.com"). The inner session will then be
+ # proxied elsewhere for authentication. If you are not
+ # careful, this means that the user can cause you to forward
+ # the authentication to another RADIUS server, and have the
+ # accounting logs *not* sent to the other server. This makes
+ # it difficult to bill people for their network activity.
+ #
+ suffix
+# ntdomain
+
+ #
+ # The "suffix" module takes care of stripping the domain
+ # (e.g. "@example.com") from the User-Name attribute, and the
+ # next few lines ensure that the request is not proxied.
+ #
+ # If you want the inner tunnel request to be proxied, delete
+ # the next few lines.
+ #
+ update control {
+ &Proxy-To-Realm := LOCAL
+ }
+
+ #
+ # This module takes care of EAP-MSCHAPv2 authentication.
+ #
+ # It also sets the EAP-Type attribute in the request
+ # attribute list to the EAP type from the packet.
+ #
+ # The example below uses module failover to avoid querying all
+ # of the following modules if the EAP module returns "ok".
+ # Therefore, your LDAP and/or SQL servers will not be queried
+ # for the many packets that go back and forth to set up TTLS
+ # or PEAP. The load on those servers will therefore be reduced.
+ #
+ eap {
+ ok = return
+ }
+
+ #
+ # Read the 'users' file
+ files
+
+ #
+ # Look in an SQL database. The schema of the database
+ # is meant to mirror the "users" file.
+ #
+ # See "Authorization Queries" in `mods-config/sql/main/$driver/queries.conf`
+ -sql
+
+ #
+ # If you are using /etc/smbpasswd, and are also doing
+ # mschap authentication, the un-comment this line, and
+ # enable the "smbpasswd" module.
+# smbpasswd
+
+ #
+ # The ldap module reads passwords from the LDAP database.
+ -ldap
+
+ #
+ # Enforce daily limits on time spent logged in.
+# daily
+
+ expiration
+ logintime
+
+ #
+ # If no other module has claimed responsibility for
+ # authentication, then try to use PAP. This allows the
+ # other modules listed above to add a "known good" password
+ # to the request, and to do nothing else. The PAP module
+ # will then see that password, and use it to do PAP
+ # authentication.
+ #
+ # This module should be listed last, so that the other modules
+ # get a chance to set Auth-Type for themselves.
+ #
+ pap
+
+ # Uncomment this section if you want to use ldap for
+ # authentication. The "Auth-Type ldap { ...}" configuration
+ # section below also has to be uncommented.
+ #
+ # Note that this means "check plain-text password against
+ # the ldap database", which means that EAP won't work,
+ # as it does not supply a plain-text password.
+ #
+ # We do NOT recommend using this, unless you have no other
+ # choice. LDAP servers are databases. They are NOT
+ # authentication servers. FreeRADIUS is an authentication
+ # server, and knows what to do with authentication. LDAP
+ # servers do not.
+ #
+ # Note that we force "Auth-Type := LDAP" ONLY if nothing else
+ # is authenticating the user, AND ONLY if the request contains
+ # a plain-text password.
+ #
+ # LDAP servers can only do PAP. They cannot do CHAP, MS-CHAP,
+ # or EAP.
+ #
+# if (!&control.Auth-Type && &User-Password) {
+# update control {
+# &Auth-Type := LDAP
+# }
+# }
+}
+
+
+# Authentication.
+#
+#
+# This section lists which modules are available for authentication.
+# Note that it does NOT mean 'try each module in order'. It means
+# that a module from the 'authorize' section adds a configuration
+# attribute 'Auth-Type := FOO'. That authentication type is then
+# used to pick the appropriate module from the list below.
+#
+
+# In general, you SHOULD NOT set the Auth-Type attribute. The server
+# will figure it out on its own, and will do the right thing. The
+# most common side effect of erroneously setting the Auth-Type
+# attribute is that one authentication method will work, but the
+# others will not.
+#
+# The common reasons to set the Auth-Type attribute by hand
+# is to either forcibly reject the user, or forcibly accept him.
+#
+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
+ }
+
+ #
+ # For old names, too.
+ #
+ mschap
+
+ #
+ # Pluggable Authentication Modules.
+# pam
+
+ # Uncomment this section if you want to use ldap for
+ # authentication. The "Auth-Type := LDAP" configuration
+ # at the end of the "authorize" section also has to be
+ # uncommented.
+ #
+ # Note that this means "check plain-text password against
+ # the ldap database", which means that EAP won't work,
+ # as it does not supply a plain-text password.
+ #
+ # We do NOT recommend using this. LDAP servers are databases.
+ # They are NOT authentication servers. FreeRADIUS is an
+ # authentication server, and knows what to do with authentication.
+ # LDAP servers do not.
+ #
+# Auth-Type LDAP {
+# ldap
+# }
+
+ #
+ # Allow EAP authentication.
+ eap
+}
+
+######################################################################
+#
+# There are no accounting requests inside of EAP-TTLS or PEAP
+# tunnels.
+#
+######################################################################
+
+
+# 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
+
+ #
+ # See "Simultaneous Use Checking Queries" in `mods-config/sql/main/$driver/queries.conf`
+# sql
+}
+
+
+# Post-Authentication
+# Once we KNOW that the user has been authenticated, there are
+# additional steps we can take.
+#
+# Note that the last packet of the inner-tunnel authentication
+# MAY NOT BE the last packet of the outer session. So updating
+# the outer reply MIGHT work, and sometimes MIGHT NOT. The
+# exact functionality depends on both the inner and outer
+# authentication methods.
+#
+# If you need to send a reply attribute in the outer session,
+# the ONLY safe way is to set "use_tunneled_reply = yes", and
+# then update the inner-tunnel reply.
+post-auth {
+ # If you want privacy to remain, see the
+ # Chargeable-User-Identity attribute from RFC 4372.
+ # If you want to use it just uncomment the line below.
+# cui-inner
+
+ #
+ # If you want the Access-Accept to contain the inner
+ # User-Name, uncomment the following lines.
+ #
+# update outer.session-state {
+# User-Name := &User-Name
+# }
+
+ #
+ # If you want to have a log of authentication replies,
+ # un-comment the following line, and enable the
+ # 'detail reply_log' module.
+# reply_log
+
+ #
+ # After authenticating the user, do another SQL query.
+ #
+ # See "Authentication Logging Queries" in `mods-config/sql/main/$driver/queries.conf`
+ -sql
+
+ #
+ # Un-comment the following if you have set
+ # 'edir = yes' in the ldap module sub-section of
+ # the 'modules' section.
+ #
+# ldap
+
+
+ #
+ # Un-comment the following if you want to generate Moonshot (ABFAB) TargetedIds
+ #
+ # IMPORTANT: This requires the UUID package to be installed, and a targeted_id_salt
+ # to be configured.
+ #
+ # This functionality also supports SQL backing. To use this functionality, enable
+ # and configure the moonshot-targeted-ids SQL module in the mods-enabled directory.
+ # Then remove the comments from the appropriate lines in each of the below
+ # policies in the policy.d/moonshot-targeted-ids file.
+ #
+# moonshot_host_tid
+# moonshot_realm_tid
+# moonshot_coi_tid
+
+ #
+ # Instead of "use_tunneled_reply", change this "if (0)" to an
+ # "if (1)".
+ #
+ if (0) {
+ #
+ # These attributes are for the inner-tunnel only,
+ # and MUST NOT be copied to the outer reply.
+ #
+ update reply {
+ User-Name !* ANY
+ Message-Authenticator !* ANY
+ EAP-Message !* ANY
+ Proxy-State !* ANY
+ MS-MPPE-Encryption-Types !* ANY
+ MS-MPPE-Encryption-Policy !* ANY
+ MS-MPPE-Send-Key !* ANY
+ MS-MPPE-Recv-Key !* ANY
+ }
+
+ #
+ # Copy the inner reply attributes to the outer
+ # session-state list. The post-auth policy will take
+ # care of copying the outer session-state list to the
+ # outer reply.
+ #
+ update {
+ &outer.session-state: += &reply:
+ }
+ }
+
+ #
+ # Access-Reject packets are sent through the REJECT sub-section of the
+ # post-auth section.
+ #
+ # Add the ldap module name (or instance) if you have set
+ # 'edir = yes' in the ldap module configuration
+ #
+ Post-Auth-Type REJECT {
+ # log failed authentications in SQL, too.
+ -sql
+ attr_filter.access_reject
+
+ #
+ # Let the outer session know which module failed, and why.
+ #
+ update outer.session-state {
+ &Module-Failure-Message := &request:Module-Failure-Message
+ }
+ }
+}
+
+#
+# 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 {
+ # Uncomment the following line if you want to change attributes
+ # as defined in the preproxy_users file.
+# files
+
+ # Uncomment the following line if you want to filter requests
+ # sent to remote servers based on the rules defined in the
+ # 'attrs.pre-proxy' file.
+# attr_filter.pre-proxy
+
+ # If you want to have a log of packets proxied to a home
+ # server, un-comment the following line, and the
+ # 'detail pre_proxy_log' section, above.
+# pre_proxy_log
+}
+
+#
+# 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 want to have a log of replies from a home server,
+ # un-comment the following line, and the 'detail post_proxy_log'
+ # section, above.
+# post_proxy_log
+
+ # Uncomment the following line if you want to filter replies from
+ # remote proxies based on the rules defined in the 'attrs' file.
+# attr_filter.post-proxy
+
+ #
+ # If you are proxying 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
+}
+
+} # inner-tunnel server block
diff --git a/raddb/sites-available/originate-coa b/raddb/sites-available/originate-coa
new file mode 100644
index 0000000..3325b88
--- /dev/null
+++ b/raddb/sites-available/originate-coa
@@ -0,0 +1,185 @@
+# -*- text -*-
+######################################################################
+#
+# The server can originate Change of Authorization (CoA) or
+# Disconnect request packets. These packets are used to dynamically
+# change the parameters of a users session (bandwidth, etc.), or
+# to forcibly disconnect the user.
+#
+# There are some caveats. Not all NAS vendors support this
+# functionality. Even for the ones that do, it may be difficult to
+# find out what needs to go into a CoA-Request or Disconnect-Request
+# packet. All we can suggest is to read the NAS documentation
+# available from the vendor. That documentation SHOULD describe
+# what information their equipment needs to see in a CoA packet.
+#
+# This information is usually a list of attributes such as:
+#
+# NAS-IP-Address (or NAS-IPv6 address)
+# NAS-Identifier
+# User-Name
+# Acct-Session-Id
+#
+# CoA packets can be originated when a normal Access-Request or
+# Accounting-Request packet is received. Simply update the
+# "coa" list:
+#
+# update coa {
+# &User-Name = "%{User-Name}"
+# &Acct-Session-Id = "%{Acct-Session-Id}"
+# &NAS-IP-Address = "%{NAS-IP-Address}"
+# }
+#
+# And the CoA packet will be sent. You can also send Disconnect
+# packets by using "update disconnect { ...".
+#
+# This "update coa" entry can be placed in any section (authorize,
+# preacct, etc.), EXCEPT for pre-proxy and post-proxy. The CoA
+# packets CANNOT be sent if the original request has been proxied.
+#
+# The CoA functionality works best when the RADIUS server and
+# the NAS receiving CoA packets are on the same network.
+#
+# If "update coa { ... " is used, and then later it becomes necessary
+# to not send a CoA request, the following example can suppress the
+# CoA packet:
+#
+# update control {
+# &Send-CoA-Request = No
+# }
+#
+# The default destination of a CoA packet is the NAS (or client)
+# the sent the original Access-Request or Accounting-Request. See
+# raddb/clients.conf for a "coa_server" configuration that ties
+# a client to a specific home server, or to a home server pool.
+#
+# If you need to send the packet to a different destination, update
+# the "coa" list with one of:
+#
+# Packet-Dst-IP-Address = ...
+# Packet-Dst-IPv6-Address = ...
+# Home-Server-Pool = ...
+#
+# That specifies an Ipv4 or IPv6 address, or a home server pool
+# (such as the "coa" pool example below). This use is not
+# recommended, however, It is much better to point the client
+# configuration directly at the CoA server/pool, as outlined
+# earlier.
+#
+# If the CoA port is non-standard, you can also set:
+#
+# Packet-Dst-Port
+#
+# to have the value of the port.
+#
+######################################################################
+
+#
+# When CoA packets are sent to a NAS, the NAS is acting as a
+# server (see RFC 5176). i.e. it has a type (accepts CoA and/or
+# Disconnect packets), an IP address (or IPv6 address), a
+# destination port, and a shared secret.
+#
+home_server example-coa {
+ type = coa
+
+ #
+ # Note that a home server of type "coa" MUST be a real NAS,
+ # with an ipaddr or ipv6addr. It CANNOT point to a virtual
+ # server.
+ #
+ # Change this IP address to the IP address of the NAS.
+ #
+ ipaddr = 192.0.2.42
+ port = 3799
+
+ # This secret SHOULD NOT be the same as the shared
+ # secret in a "client" section.
+ secret = testing1234
+
+ # CoA specific parameters. See raddb/proxy.conf for details.
+ coa {
+ irt = 2
+ mrt = 16
+ mrc = 5
+ mrd = 30
+ }
+}
+
+#
+# CoA servers can be put into pools, just like normal servers.
+#
+home_server_pool coa {
+ type = fail-over
+
+ # Point to the CoA server above.
+ home_server = example-coa
+
+ # CoA requests are run through the pre-proxy section.
+ # CoA responses are run through the post-proxy section.
+ virtual_server = originate-coa.example.com
+
+ #
+ # Home server pools of type "coa" cannot (currently) have
+ # a "fallback" configuration.
+ #
+}
+
+#
+# When this virtual server is run, the original request has FINISHED
+# processing. i.e. the reply has already been sent to the NAS.
+# You can access the attributes in the original packet, reply, and
+# control items, but changing them will have NO EFFECT.
+#
+# The CoA packet is in the "proxy-request" attribute list.
+# The CoA reply (if any) is in the "proxy-reply" attribute list.
+#
+server originate-coa.example.com {
+ pre-proxy {
+ update proxy-request {
+ NAS-IP-Address = 192.0.2.42
+ }
+ }
+
+ #
+ # Handle the responses here.
+ #
+ post-proxy {
+ switch &proxy-reply:Packet-Type {
+ case CoA-ACK {
+ ok
+ }
+
+ case CoA-NAK {
+ # the NAS didn't like the CoA request
+ ok
+ }
+
+ case Disconnect-ACK {
+ ok
+ }
+
+ case Disconnect-NAK {
+ # the NAS didn't like the Disconnect request
+ ok
+ }
+
+ # Invalid packet type. This shouldn't happen.
+ case {
+ fail
+ }
+ }
+
+ #
+ # These methods are run when there is NO response
+ # to the request.
+ #
+ Post-Proxy-Type Fail-CoA {
+ ok
+ }
+
+ Post-Proxy-Type Fail-Disconnect {
+ ok
+ }
+ }
+}
diff --git a/raddb/sites-available/proxy-inner-tunnel b/raddb/sites-available/proxy-inner-tunnel
new file mode 100644
index 0000000..938d954
--- /dev/null
+++ b/raddb/sites-available/proxy-inner-tunnel
@@ -0,0 +1,47 @@
+# -*- text -*-
+######################################################################
+#
+# This is a virtual server that handles *only* inner tunnel
+# requests for EAP-TTLS and PEAP types.
+#
+# $Id$
+#
+######################################################################
+
+server proxy-inner-tunnel {
+
+#
+# This example is very simple. All inner tunnel requests get
+# proxied to another RADIUS server.
+#
+authorize {
+ #
+ # Do other things here, as necessary.
+ #
+ # e.g. run the "realms" module, to decide how to proxy
+ # the inner tunnel request.
+ #
+
+ update control {
+ # You should update this to be one of your realms.
+ &Proxy-To-Realm := "example.com"
+ }
+}
+
+authenticate {
+ #
+ # This is necessary so that the inner tunnel EAP-MSCHAPv2
+ # method can be called. That method takes care of turning
+ # EAP-MSCHAPv2 into plain MS-CHAPv2, if necessary.
+ eap
+}
+
+post-proxy {
+ #
+ # This is necessary for LEAP, or if you set:
+ #
+ # proxy_tunneled_request_as_eap = no
+ #
+ eap
+}
+}
diff --git a/raddb/sites-available/resource-check b/raddb/sites-available/resource-check
new file mode 100644
index 0000000..486c3b8
--- /dev/null
+++ b/raddb/sites-available/resource-check
@@ -0,0 +1,140 @@
+# -*- text -*-
+######################################################################
+#
+# This virtual server provides an example of how to dynamically amend the
+# control flow within some virtual server's policy on the basis of the status
+# of some resource, such as an external database.
+#
+# This resource-check virtual server receives periodic dummy server-status
+# requests that trigger an arbitrary set of checks. On the basis of those
+# checks the status of an instance of the rlm_always module, that we refer to
+# as the "control module", is updated to reflect the system status.
+#
+# Elsewhere, some other virtual server (the "controlled virtual server") uses
+# the control module to make decisions during the processing of incoming
+# requests. By amending the status of the control module in response to the
+# system status this virtual server is able to manipulate the outcome of the
+# controlled virtual server.
+#
+# Firstly, the authorize section of this virtual server will need to be
+# amended to check the status of the external resources and to set the status
+# of the control module appropriately, as described in the inline comments
+# below...
+#
+# In addition to configuring and activating this virtual server, a control
+# module must be configured as an instance of rlm_always in mods-enabled, for
+# example:
+#
+# always db_online {
+# # Default to online
+# rcode = ok
+# }
+#
+# Now trigger the resource checks by sending a server-status request to this
+# virtual server, as follows:
+#
+# echo "Message-Authenticator = 0x00" | \
+# radclient -r 1 -t 3 -q 127.0.0.1:18122 status testing123
+#
+# The trigger could be invoked by a cron job or if more frequent checks than
+# once per minute are required a systemd timer might be used.
+#
+# The current status of the control module can be examined at any time using
+# radmin:
+#
+# radmin -e 'show module status db_online'
+#
+# For radmin to work requires that the control-socket virtual server is
+# configured and enabled.
+#
+# The controlled virtual server will contain some control flow decision that
+# uses the control module, for example:
+#
+# server default {
+#
+# ...
+#
+# authorize {
+#
+# # If the database is not healthy then remain silent to trigger
+# # NAS failover
+# #
+# db_online {
+# fail = 1
+# }
+# if (fail) {
+# do_not_respond
+# }
+#
+# sql
+#
+# pap
+# }
+#
+# ...
+#
+#
+# The configuration for this virtual server follows and should be amended as
+# required...
+#
+
+
+#
+# Listen on a local port for Server-Status requests that trigger the resource
+# checks.
+#
+# This uses the normal set of clients, with the same secret as for
+# authentication and accounting.
+#
+listen {
+ type = status
+ ipaddr = 127.0.0.1
+ port = 18122
+ virtual_server = resource_check
+}
+
+
+#
+# Within this virual server we provide only an Autz-Type Status-Server section
+# whose task is to perform the resource checks and sets the status of the
+# "control module"
+#
+server resource-check {
+
+authorize {
+
+Autz-Type Status-Server {
+
+ #
+ # In this example we check whether a PostgreSQL database is in
+ # recovery (or inaccessible) and when this is the case we fail the
+ # db_online control module.
+ #
+ # Other modules could be used here.
+ #
+ # You can even invoke synchronous checks using the %{exec:...} xlat in
+ # which case timeout should be set to less than the check trigger
+ # interval to avoid buildup of checks when resources do not respond.
+ # See rlm_exec for details.
+ #
+ if ("%{sql:SELECT pg_is_in_recovery()}" != "f") {
+
+ # Fail the db_online module, if it isn't already
+ if ("%{db_online:}" != "fail") {
+ %{db_online:fail}
+ }
+
+ } else {
+
+ # Set the db_online module status to alive, if it isn't already
+ if ("%{db_online:}" != "alive") {
+ %{db_online:alive}
+ }
+
+ }
+
+}
+
+}
+
+}
diff --git a/raddb/sites-available/robust-proxy-accounting b/raddb/sites-available/robust-proxy-accounting
new file mode 100644
index 0000000..7371643
--- /dev/null
+++ b/raddb/sites-available/robust-proxy-accounting
@@ -0,0 +1,177 @@
+# -*- text -*-
+######################################################################
+#
+# This is a sample configuration for robust proxy accounting.
+# accounting packets are proxied, OR logged locally if all
+# home servers are down. When the home servers come back up,
+# the accounting packets are forwarded.
+#
+# This method enables the server to proxy all packets to the
+# home servers when they're up, AND to avoid writing to the
+# detail file in most situations.
+#
+# In most situations, proxying of accounting messages is done
+# in a "pass-through" fashion. If the home server does not
+# respond, then the proxy server does not respond to the NAS.
+# That means that the NAS must retransmit packets, sometimes
+# forever. This example shows how the proxy server can still
+# respond to the NAS, even if all home servers are down.
+#
+# This configuration could be done MUCH more simply if ALL
+# packets were written to the detail file. But that would
+# involve a lot more disk writes, which may not be a good idea.
+#
+# This file is NOT meant to be used as-is. It needs to be
+# edited to match your local configuration.
+#
+# Please see the sites-available/default file, in the
+# "Post-Proxy-Type Fail-Accounting" section. That should be
+# configured to write packets to the "detail.example.com"
+# file when proxying fails. The "listen" section below will
+# then read packets from that file, and proxy them.
+#
+# See also mods-available/detail.example.com, which is the
+# module that writes the "detail.example.com" file.
+#
+#
+# $Id$
+#
+######################################################################
+
+# (1) Define two home servers.
+home_server home1.example.com {
+ type = acct
+ ipaddr = 192.0.2.10
+ port = 1813
+ secret = testing123
+
+ # Mark this home server alive ONLY when it starts being responsive
+ status_check = request
+ username = "test_user_status_check"
+
+ # Set the response timeout aggressively low.
+ # You MAY have to increase this, depending on tests with
+ # your local installation.
+ response_window = 6
+}
+
+home_server home2.example.com {
+ type = acct
+ ipaddr = 192.0.2.20
+ port = 1813
+ secret = testing123
+
+ # Mark this home server alive ONLY when it starts being responsive
+ status_check = request
+ username = "test_user_status_check"
+
+ # Set the response timeout aggressively low.
+ # You MAY have to increase this, depending on tests with
+ # your local installation.
+ response_window = 6
+}
+
+# (2) Put all of the servers into a pool.
+home_server_pool acct_pool.example.com {
+ type = load-balance # other types are OK, too.
+
+ home_server = home1.example.com
+ home_server = home2.example.com
+ # add more home_server's here.
+
+ # for pre/post-proxy policies
+ virtual_server = home.example.com
+}
+
+# (3) Define a realm for these home servers.
+# It should NOT be used as part of normal proxying decisions!
+realm acct_realm.example.com {
+ acct_pool = acct_pool.example.com
+}
+
+# (4) Define a detail file writer.
+# See raddb/modules/detail.example.com
+
+# (5) Define a virtual server to handle pre/post-proxy re-writing
+server home.example.com {
+ pre-proxy {
+ # Insert pre-proxy rules here
+ }
+
+ post-proxy {
+ # Insert post-proxy rules here
+
+ # This will be called when the CURRENT packet failed
+ # to be proxied. This may happen when one home server
+ # suddenly goes down, even though another home server
+ # may be alive.
+ #
+ # i.e. the current request has run out of time, so it
+ # cannot fail over to another (possibly) alive server.
+ #
+ # We want to respond to the NAS, so that it can stop
+ # re-sending the packet. We write the packet to the
+ # "detail" file, where it will be read, and sent to
+ # another home server.
+ #
+ Post-Proxy-Type Fail-Accounting {
+ detail.example.com
+
+ # Now that the packet has been stored
+ # mark that we can respond to the NAS
+ acct_response
+ }
+
+ #
+ # This section is run when there are problems
+ # proxying Access-Request packets
+ #
+ Post-Proxy-Type Fail-Authentication {
+ # add policies here
+ }
+
+ }
+
+
+ # Read accounting packets from the detail file(s) for
+ # the home server.
+ #
+ # Note that you can have only ONE "listen" section reading
+ # detail files from a particular directory. That is why the
+ # destination host name is used as part of the directory name
+ # below. Having two "listen" sections reading detail files
+ # from the same directory WILL cause problems. The packets
+ # may be read by one, the other, or both "listen" sections.
+ listen {
+ type = detail
+ filename = "${radacctdir}/detail.example.com/detail-*:*"
+
+ #
+ # See sites-available/buffered-sql for documentation
+ # on the configuration items for a detail listener.
+ #
+ load_factor = 90
+ track = yes
+ }
+
+ # All packets read from the detail file are proxied back to
+ # the home servers.
+ #
+ # The normal pre/post-proxy rules are applied to them, too.
+ #
+ # If the home servers are STILL down, then the server stops
+ # reading the detail file, and queues the packets for a later
+ # retransmission. The Post-Proxy-Type "Fail" handler is NOT
+ # called.
+ #
+ # When the home servers come back up, the packets are forwarded,
+ # and the detail file processed as normal.
+ accounting {
+ # You may want accounting policies here...
+
+ update control {
+ &Proxy-To-Realm := 'acct_realm.example.com'
+ }
+ }
+
+}
diff --git a/raddb/sites-available/soh b/raddb/sites-available/soh
new file mode 100644
index 0000000..86748b6
--- /dev/null
+++ b/raddb/sites-available/soh
@@ -0,0 +1,34 @@
+# This is a simple server for the MS SoH requests generated by the
+# peap module - see "eap.conf" for more info
+
+# Requests are ONLY passed through the authorize section, and cannot
+# current be proxied (in any event, the radius attributes used are
+# internal).
+
+server soh-server {
+ authorize {
+ if (&SoH-Supported == no) {
+ # client NAKed our request for SoH - not supported, or turned off
+ update config {
+ &Auth-Type = Accept
+ }
+ }
+ else {
+ # client replied; check something - this is a local policy issue!
+ if (&SoH-MS-Windows-Health-Status =~ /antivirus (warn|error) /) {
+ update config {
+ &Auth-Type = Reject
+ }
+ update reply {
+ &Reply-Message = 'You must have antivirus enabled & installed!'
+ }
+ }
+ else {
+ update config {
+ &Auth-Type = Accept
+ }
+ }
+ }
+ }
+}
+
diff --git a/raddb/sites-available/status b/raddb/sites-available/status
new file mode 100644
index 0000000..e7d4346
--- /dev/null
+++ b/raddb/sites-available/status
@@ -0,0 +1,127 @@
+# -*- text -*-
+######################################################################
+#
+# A virtual server to handle ONLY Status-Server packets.
+#
+# Server statistics can be queried with a properly formatted
+# Status-Server request. See dictionary.freeradius for comments.
+#
+# If radiusd.conf has "status_server = yes", then any client
+# will be able to send a Status-Server packet to any port
+# (listen section type "auth", "acct", or "status"), and the
+# server will respond.
+#
+# If radiusd.conf has "status_server = no", then the server will
+# ignore Status-Server packets to "auth" and "acct" ports. It
+# will respond only if the Status-Server packet is sent to a
+# "status" port.
+#
+# The server statistics are available ONLY on socket of type
+# "status". Queries for statistics sent to any other port
+# are ignored.
+#
+# Similarly, a socket of type "status" will not process
+# authentication or accounting packets. This is for security.
+#
+# $Id$
+#
+######################################################################
+
+server status {
+ listen {
+ # ONLY Status-Server is allowed to this port.
+ # ALL other packets are ignored.
+ type = status
+
+ ipaddr = 127.0.0.1
+ port = 18121
+ }
+
+ #
+ # We recommend that you list ONLY management clients here.
+ # i.e. NOT your NASes or Access Points, and for an ISP,
+ # DEFINITELY not any RADIUS servers that are proxying packets
+ # to you.
+ #
+ # If you do NOT list a client here, then any client that is
+ # globally defined (i.e. all of them) will be able to query
+ # these statistics.
+ #
+ # Do you really want your partners seeing the internal details
+ # of what your RADIUS server is doing?
+ #
+ client admin {
+ ipaddr = 127.0.0.1
+ secret = adminsecret
+ }
+
+ #
+ # Simple authorize section. The "Autz-Type Status-Server"
+ # section will work here, too. See "raddb/sites-available/default".
+ authorize {
+ ok
+
+ # respond to the Status-Server request.
+ Autz-Type Status-Server {
+ ok
+ }
+ }
+}
+
+# Statistics can be queried via a number of methods:
+#
+# All packets received/sent by the server (1 = auth, 2 = acct)
+# FreeRADIUS-Statistics-Type = 3
+#
+# All packets proxied by the server (4 = proxy-auth, 8 = proxy-acct)
+# FreeRADIUS-Statistics-Type = 12
+#
+# All packets sent && received:
+# FreeRADIUS-Statistics-Type = 15
+#
+# Internal server statistics:
+# FreeRADIUS-Statistics-Type = 16
+#
+# All packets for a particular client (globally defined)
+# FreeRADIUS-Statistics-Type = 35
+# FreeRADIUS-Stats-Client-IP-Address = 192.0.2.1
+#
+# All packets for a client attached to a "listen" ip/port
+# FreeRADIUS-Statistics-Type = 35
+# FreeRADIUS-Stats-Client-IP-Address = 192.0.2.1
+# FreeRADIUS-Stats-Server-IP-Address = 127.0.0.1
+# FreeRADIUS-Stats-Server-Port = 1812
+#
+# All packets for a "listen" IP/port
+# FreeRADIUS-Statistics-Type = 67
+# FreeRADIUS-Stats-Server-IP-Address = 127.0.0.1
+# FreeRADIUS-Stats-Server-Port = 1812
+#
+# All packets for a home server IP / port
+# FreeRADIUS-Statistics-Type = 131
+# FreeRADIUS-Stats-Server-IP-Address = 192.0.2.2
+# FreeRADIUS-Stats-Server-Port = 1812
+
+#
+# You can also get exponentially weighted moving averages of
+# response times (in usec) of home servers. Just set the config
+# item "historic_average_window" in a home_server section.
+#
+# By default it is zero (don't calculate it). Useful values
+# are between 100, and 10,000. The server will calculate and
+# remember the moving average for this window, and for 10 times
+# that window.
+#
+
+#
+# Some of this could have been simplified. e.g. the proxy-auth and
+# proxy-acct bits aren't completely necessary. But using them permits
+# the server to be queried for ALL inbound && outbound packets at once.
+# This gives a good snapshot of what the server is doing.
+#
+# Due to internal limitations, the statistics might not be exactly up
+# to date. Do not expect all of the numbers to add up perfectly.
+# The Status-Server packets are also counted in the total requests &&
+# responses. The responses are counted only AFTER the response has
+# been sent.
+#
diff --git a/raddb/sites-available/tls b/raddb/sites-available/tls
new file mode 100644
index 0000000..137fcbc
--- /dev/null
+++ b/raddb/sites-available/tls
@@ -0,0 +1,696 @@
+######################################################################
+#
+# RADIUS over TLS (radsec)
+#
+# When a new client connects, the various TLS parameters for the
+# connection are available as dynamic expansions, e.g.
+#
+# %{listen:TLS-Client-Cert-Common-Name}
+#
+# Along with other TLS-Client-Cert-... attributes.
+# These expansions will only exist if the relevant fields
+# are in the client certificate. Read the debug output to see
+# which fields are available. Look for output like the following:
+#
+# (0) TLS - Creating attributes from certificate OIDs
+# (0) TLS-Client-Cert-Subject-Alt-Name-Dns := "one.example.org"
+# (0) TLS-Client-Cert-Subject-Alt-Name-Dns := "two.example.org"
+# ...
+#
+# It is also possible to distinguish between connections which have
+# TLS enables, and ones which do not. The expansion:
+#
+# %{listen:tls}
+#
+# Will return "yes" if the connection has TLS enabled. It will
+# return "no" if TLS is not enabled for a particular listen section.
+#
+# A number of TLS-Client-Cert-.. attributes holds X509v3 extensions
+# data, attributes named the way OpenSSL names them. It is possible
+# to extract data for an extension not known to OpenSSL by defining
+# a custom string attribute which contains extension OID in it's
+# name after 'TLS-Client-Cert-' prefix. E.g.:
+#
+# ATTRIBUTE TLS-Client-Cert-1.3.6.1.4.1.311.21.7 3002 string
+#
+# which will yield something simmilar to:
+#
+# (0) eap_tls: TLS - Creating attributes from certificate OIDs
+# (0) eap_tls: TLS-Client-Cert-1.3.6.1.4.1.311.21.7 += "0x302e06"
+# ...
+#
+######################################################################
+
+listen {
+ ipaddr = *
+ port = 2083
+
+ #
+ # TCP and TLS sockets can accept Access-Request and
+ # Accounting-Request on the same socket.
+ #
+ # auth = only Access-Request
+ # acct = only Accounting-Request
+ # auth+acct = both
+ # coa = only CoA / Disconnect requests
+ #
+ type = auth+acct
+
+ # For now, only TCP transport is allowed.
+ proto = tcp
+
+ # Send packets to the default virtual server
+ virtual_server = default
+
+ clients = radsec
+
+ #
+ # Use the haproxy "PROXY protocol".
+ #
+ # This configuration allows for many FreeRADIUS servers to be
+ # behind a haproxy server. The "PROXY protocol" allows
+ # haproxy to send the actual client IP to FreeRADIUS.
+ #
+ # This will work ONLY for RadSec (TLS). Both the haproxy AND
+ # the RadSec client MUST be listed as allowed RADIUS clients.
+ #
+ # haproxy needs to have "send-proxy" configured for this server.
+ # Health checks should be turned off, as haproxy does not
+ # support RADIUS health checks.
+ #
+ # The main use of this feature is for scalability. There is no
+ # longer any need to have a RADIUS proxy as a load balancer.
+ # haproxy is fast, stable, and supports dynamic reloads!
+ #
+ # The only problem is that many RADIUS clients do not support
+ # RadSec. That situation will hopefully change over time.
+ #
+# proxy_protocol = no
+
+ #
+ # When this is set to "yes", new TLS connections
+ # are processed through a section called
+ #
+ # Autz-Type New-TLS-Connection {
+ # ...
+ # }
+ #
+ # The request contains TLS client certificate attributes,
+ # and nothing else. The debug output will print which
+ # attributes are available on your system.
+ #
+ # If the section returns "ok" or "updated", then the
+ # connection is accepted. Otherwise the connection is
+ # terminated.
+ #
+# check_client_connections = yes
+
+ #
+ # Connection limiting for sockets with "proto = tcp".
+ #
+ limit {
+ #
+ # Limit the number of simultaneous TCP connections to the socket
+ #
+ # The default is 16.
+ # Setting this to 0 means "no limit"
+ max_connections = 16
+
+ # The per-socket "max_requests" option does not exist.
+
+ #
+ # The lifetime, in seconds, of a TCP connection. After
+ # this lifetime, the connection will be closed.
+ #
+ # Setting this to 0 means "forever".
+ lifetime = 0
+
+ #
+ # The idle timeout, in seconds, of a TCP connection.
+ # If no packets have been received over the connection for
+ # this time, the connection will be closed.
+ #
+ # Setting this to 0 means "no timeout".
+ #
+ # We STRONGLY RECOMMEND that you set an idle timeout.
+ #
+ idle_timeout = 30
+ }
+
+ # This is *exactly* the same configuration as used by the EAP-TLS
+ # module. It's OK for testing, but for production use it's a good
+ # idea to use different server certificates for EAP and for RADIUS
+ # transport.
+ #
+ # If you want only one TLS configuration for multiple sockets,
+ # then we suggest putting "tls { ...}" into radiusd.conf.
+ # The subsection below can then be changed into a reference:
+ #
+ # tls = ${tls}
+ #
+ # Which means "the tls sub-section is not here, but instead is in
+ # the top-level section called 'tls'".
+ #
+ # If you have multiple tls configurations, you can put them into
+ # sub-sections of a top-level "tls" section. There's no need to
+ # call them all "tls". You can then use:
+ #
+ # tls = ${tls.site1}
+ #
+ # to refer to the "site1" sub-section of the "tls" section.
+ #
+ tls {
+ private_key_password = whatever
+ private_key_file = ${certdir}/server.pem
+
+ # Accept an expired Certificate Revocation List
+ #
+ # allow_expired_crl = no
+
+ # If Private key & Certificate are located in
+ # the same file, then private_key_file &
+ # certificate_file must contain the same file
+ # name.
+ #
+ # If ca_file (below) is not used, then the
+ # certificate_file below MUST include not
+ # only the server certificate, but ALSO all
+ # of the CA certificates used to sign the
+ # server certificate.
+ certificate_file = ${certdir}/server.pem
+
+ # Trusted Root CA list
+ #
+ # ALL of the CA's in this list will be trusted
+ # to issue client certificates for authentication.
+ #
+ # In general, you should use self-signed
+ # certificates for 802.1x (EAP) authentication.
+ # In that case, this CA file should contain
+ # *one* CA certificate.
+ #
+ # This parameter is used only for EAP-TLS,
+ # when you issue client certificates. If you do
+ # not use client certificates, and you do not want
+ # to permit EAP-TLS authentication, then delete
+ # this configuration item.
+ ca_file = ${cadir}/ca.pem
+
+ # For DH cipher suites to work in OpenSSL < 1.1.0,
+ # you have to run OpenSSL to create the DH file
+ # first:
+ #
+ # openssl dhparam -out certs/dh 2048
+ #
+ # For OpenSSL >= 1.1.0, just leave this commented
+ # out, and OpenSSL will do the right thing.
+ #
+# dh_file = ${certdir}/dh
+
+ #
+ # If your system doesn't have /dev/urandom,
+ # you will need to create this file, and
+ # periodically change its contents.
+ #
+ # For security reasons, FreeRADIUS doesn't
+ # write to files in its configuration
+ # directory.
+ #
+# random_file = /dev/urandom
+
+ #
+ # The default fragment size is 1K.
+ # However, it's possible to send much more data than
+ # that over a TCP connection. The upper limit is 64K.
+ # Setting the fragment size to more than 1K means that
+ # there are fewer round trips when setting up a TLS
+ # connection. But only if the certificates are large.
+ #
+ fragment_size = 8192
+
+ # 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
+
+ # Check the Certificate Revocation List
+ #
+ # 1) Copy CA certificates and CRLs to same directory.
+ # 2) Execute 'c_rehash <CA certs&CRLs Directory>'.
+ # 'c_rehash' is OpenSSL's command.
+ # 3) uncomment the line below.
+ # 5) Restart radiusd
+ # check_crl = yes
+ ca_path = ${cadir}
+
+ # OpenSSL does not reload contents of ca_path dir over time.
+ # That means that if check_crl is enabled and CRLs are loaded
+ # from ca_path dir, at some point CRLs will expire and
+ # RADIUSd will stop authenticating NASes.
+ # If ca_path_reload_interval is non-zero, it will force OpenSSL
+ # to reload all data from ca_path periodically
+ #
+ # Flush ca_path each hour
+ ca_path_reload_interval = 3600
+
+ #
+ # If check_cert_issuer is set, the value will
+ # be checked against the DN of the issuer in
+ # the client certificate. If the values do not
+ # match, the certificate verification will fail,
+ # rejecting the user.
+ #
+ # This check can be done more generally by checking
+ # the value of the TLS-Client-Cert-Issuer attribute.
+ # This check can be done via any mechanism you choose.
+ #
+ # check_cert_issuer = "/C=GB/ST=Berkshire/L=Newbury/O=My Company Ltd"
+
+ #
+ # If check_cert_cn is set, the value will
+ # be xlat'ed and checked against the CN
+ # in the client certificate. If the values
+ # do not match, the certificate verification
+ # will fail rejecting the user.
+ #
+ # This check is done only if the previous
+ # "check_cert_issuer" is not set, or if
+ # the check succeeds.
+ #
+ # In 2.1.10 and later, this check can be done
+ # more generally by checking the value of the
+ # TLS-Client-Cert-Common-Name attribute. This check
+ # can be done via any mechanism you choose.
+ #
+ # check_cert_cn = %{User-Name}
+ #
+ # Set this option to specify the allowed
+ # TLS cipher suites. The format is listed
+ # in "man 1 ciphers".
+ cipher_list = "DEFAULT"
+
+ # If enabled, OpenSSL will use server cipher list
+ # (possibly defined by cipher_list option above)
+ # for choosing right cipher suite rather than
+ # using client-specified list which is OpenSSl default
+ # behavior. Having it set to yes is a current best practice
+ # for TLS
+ cipher_server_preference = no
+
+ #
+ # Older TLS versions are deprecated. But for RadSec,
+ # we CAN allow TLS 1.3.
+ #
+ tls_min_version = "1.2"
+ tls_max_version = "1.3"
+
+ #
+ # Session resumption / fast reauthentication
+ # cache.
+ #
+ # The cache contains the following information:
+ #
+ # session Id - unique identifier, managed by SSL
+ # User-Name - from the Access-Accept
+ # Stripped-User-Name - from the Access-Request
+ # Cached-Session-Policy - from the Access-Accept
+ #
+ # The "Cached-Session-Policy" is the name of a
+ # policy which should be applied to the cached
+ # session. This policy can be used to assign
+ # VLANs, IP addresses, etc. It serves as a useful
+ # way to re-apply the policy from the original
+ # Access-Accept to the subsequent Access-Accept
+ # for the cached session.
+ #
+ # On session resumption, these attributes are
+ # copied from the cache, and placed into the
+ # reply list.
+ #
+ # You probably also want "use_tunneled_reply = yes"
+ # when using fast session resumption.
+ #
+ cache {
+ #
+ # Enable it. The default is "no".
+ # Deleting the entire "cache" subsection
+ # Also disables caching.
+ #
+ #
+ # The session cache requires the use
+ # of the "name" and "persist_dir" configuration items, below.
+ #
+ # The internal OpenSSL session cache has been permanently
+ # disabled.
+ #
+ # You can disallow resumption for a
+ # particular user by adding the following
+ # attribute to the control item list:
+ #
+ # Allow-Session-Resumption = No
+ #
+ # If "enable = no" below, you CANNOT
+ # enable resumption for just one user
+ # by setting the above attribute to "yes".
+ #
+ enable = no
+
+ #
+ # Lifetime of the cached entries, in hours.
+ # The sessions will be deleted after this
+ # time.
+ #
+ lifetime = 24 # hours
+
+ #
+ # Internal "name" of the session cache.
+ # Used to distinguish which TLS context
+ # sessions belong to.
+ #
+ # The server will generate a random value
+ # if unset. This will change across server
+ # restart so you MUST set the "name" if you
+ # want to persist sessions (see below).
+ #
+ # If you use IPv6, change the "ipaddr" below
+ # to "ipv6addr"
+ #
+ #name = "TLS ${..ipaddr} ${..port} ${..proto}"
+
+ #
+ # Simple directory-based storage of sessions.
+ # Two files per session will be written, the SSL
+ # state and the cached VPs. This will persist session
+ # across server restarts.
+ #
+ # The server will need write perms, and the directory
+ # should be secured from anyone else. You might want
+ # a script to remove old files from here periodically:
+ #
+ # find ${logdir}/tlscache -mtime +2 -exec rm -f {} \;
+ #
+ # This feature REQUIRES "name" option be set above.
+ #
+ #persist_dir = "${logdir}/tlscache"
+ }
+
+ #
+ # Require a client certificate.
+ #
+ require_client_cert = yes
+
+ #
+ # As of version 2.1.10, client certificates can be
+ # validated via an external command. This allows
+ # dynamic CRLs or OCSP to be used.
+ #
+ # This configuration is commented out in the
+ # default configuration. Uncomment it, and configure
+ # the correct paths below to enable it.
+ #
+ verify {
+ # A temporary directory where the client
+ # certificates are stored. This directory
+ # MUST be owned by the UID of the server,
+ # and MUST not be accessible by any other
+ # users. When the server starts, it will do
+ # "chmod go-rwx" on the directory, for
+ # security reasons. The directory MUST
+ # exist when the server starts.
+ #
+ # You should also delete all of the files
+ # in the directory when the server starts.
+ # tmpdir = /tmp/radiusd
+
+ # The command used to verify the client cert.
+ # We recommend using the OpenSSL command-line
+ # tool.
+ #
+ # The ${..ca_path} text is a reference to
+ # the ca_path variable defined above.
+ #
+ # The %{TLS-Client-Cert-Filename} is the name
+ # of the temporary file containing the cert
+ # in PEM format. This file is automatically
+ # deleted by the server when the command
+ # returns.
+ # client = "/path/to/openssl verify -CApath ${..ca_path} %{TLS-Client-Cert-Filename}"
+ }
+
+ #
+ # When the RadSec clients use SNI, the server will
+ # automatically choose the correct certificate from
+ # "realm_dir". See raddb/certs/realms/README.md for
+ # more information.
+ #
+ # Note that the default is to use the same set of
+ # realm certificates for both EAP and RadSec! If
+ # this is not what you want, you should use different
+ # subdirectories or each, e.g. ${certdir}/realms/radsec/,
+ # and ${certdir}/realms/eap/
+ #
+ # realm_dir = ${certdir}/realms/
+ }
+}
+
+clients radsec {
+ client 127.0.0.1 {
+ ipaddr = 127.0.0.1
+
+ #
+ # Ensure that this client is TLS *only*.
+ #
+ proto = tls
+
+ #
+ # TCP clients can have any shared secret.
+ #
+ # TLS clients MUST have the shared secret
+ # set to "radsec". Or, for "proto = tls",
+ # you can omit the secret, and it will
+ # automatically be set to "radsec".
+ #
+ secret = radsec
+
+ #
+ # You can also use a "limit" section here.
+ # See raddb/clients.conf for examples.
+ #
+ # Note that BOTH limits are applied. You
+ # should therefore set the "listen" limits
+ # higher than the ones for each individual
+ # client.
+ #
+ }
+}
+
+#
+# When a request is proxied to a TLS-enabled home server,
+# the TLS parameters are available via the expansion:
+#
+# %{proxy_listen: ... }
+#
+# The contents of the expansion are the same as described
+# above with the %{listen: ... } expansion, and have similar
+# meanings. "client" in this case is the proxy (this system)
+# and "server" is the remote system (home server).
+#
+# Note that the %{proxy_listen: ... } parameters are available
+# only AFTER the connection has been made to the home server.
+#
+home_server tls {
+ ipaddr = 127.0.0.1
+ port = 2083
+
+ # type can be the same types as for the "listen" section/
+ # e.g. auth, acct, auth+acct, coa
+ type = auth
+ secret = radsec
+ proto = tcp
+ status_check = none
+
+ tls {
+ #
+ # Similarly to HTTP, the client can use Server Name
+ # Indication to inform the RadSec server as to which
+ # domain it is requesting. This selection allows
+ # multiple sites to exist at the same IP address.
+ #
+ # For example, an identity provider could host
+ # multiple sites, but present itself with one public
+ # IP address. If the RadSec clients do not use SNI,
+ # then they must be configured with the certificate
+ # of the identity provider.
+ #
+ # When SNI is used, the clients can be configured
+ # with the certificate of the hosted system that
+ # they're connecting to. This ability means that
+ # there is no need to change certificates when
+ # changing providers. In addition, there is no need
+ # to change the configuration of all RadSec clients
+ # when the hosting system changes its certifiates.
+ # Because the hosting system certificates are never used.
+ #
+ # Instead, each hosted company is responsible for its
+ # own certificates, and for its own clients.
+ #
+ # SNI also permits the use of a load balancer such as
+ # haproxy. That load balancer can terminate the TLS
+ # connection, and then use SNI to route the
+ # underlying RADIUS TCP traffic to a particular host.
+ #
+ # Note that "hostname" here is only for SNI, and is NOT
+ # the hostname or IP address we connect to. For that,
+ # see "ipaddr", above.
+ #
+ # hostname = "example.com"
+
+ private_key_password = whatever
+ private_key_file = ${certdir}/client.pem
+
+ # If Private key & Certificate are located in
+ # the same file, then private_key_file &
+ # certificate_file must contain the same file
+ # name.
+ #
+ # If ca_file (below) is not used, then the
+ # certificate_file below MUST include not
+ # only the server certificate, but ALSO all
+ # of the CA certificates used to sign the
+ # server certificate.
+ certificate_file = ${certdir}/client.pem
+
+ # Trusted Root CA list
+ #
+ # ALL of the CA's in this list will be trusted
+ # to issue client certificates for authentication.
+ #
+ # In general, you should use self-signed
+ # certificates for 802.1x (EAP) authentication.
+ # In that case, this CA file should contain
+ # *one* CA certificate.
+ #
+ # This parameter is used only for EAP-TLS,
+ # when you issue client certificates. If you do
+ # not use client certificates, and you do not want
+ # to permit EAP-TLS authentication, then delete
+ # this configuration item.
+ ca_file = ${cadir}/ca.pem
+
+ #
+ # Before version 3.2.1, outbound RadSec connections
+ # would put the home server certificate into the
+ # TLS-Client-Cert* attributes. Set this configuration
+ # item to "yes" in order to have the home server
+ # certificates placed into the "TLS-Cert-*" attributes.
+ #
+# fix_cert_order = yes
+
+ #
+ # For TLS-PSK, the key should be specified
+ # dynamically, instead of using a hard-coded
+ # psk_identity and psk_hexphrase.
+ #
+ # The input to the dynamic expansion will be the PSK
+ # identity supplied by the client, in the
+ # TLS-PSK-Identity attribute. The output of the
+ # expansion should be a hex string, of no more than
+ # 512 characters. The string should not be prefixed
+ # with "0x". e.g. "abcdef" is OK. "0xabcdef" is not.
+ #
+ # psk_query = "%{psksql:select hex(key) from psk_keys where keyid = '%{TLS-PSK-Identity}'}"
+
+ #
+ # For DH cipher suites to work, you have to
+ # run OpenSSL to create the DH file first:
+ #
+ # openssl dhparam -out certs/dh 1024
+ #
+# dh_file = ${certdir}/dh
+# random_file = /dev/urandom
+
+ #
+ # The default fragment size is 1K.
+ # However, TLS can send 64K of data at once.
+ # It can be useful to set it higher.
+ #
+ fragment_size = 8192
+
+ # 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
+
+ # Check the Certificate Revocation List
+ #
+ # 1) Copy CA certificates and CRLs to same directory.
+ # 2) Execute 'c_rehash <CA certs&CRLs Directory>'.
+ # 'c_rehash' is OpenSSL's command.
+ # 3) uncomment the line below.
+ # 5) Restart radiusd
+ # check_crl = yes
+ ca_path = ${cadir}
+
+ #
+ # If check_cert_issuer is set, the value will
+ # be checked against the DN of the issuer in
+ # the client certificate. If the values do not
+ # match, the certificate verification will fail,
+ # rejecting the user.
+ #
+ # In 2.1.10 and later, this check can be done
+ # more generally by checking the value of the
+ # TLS-Client-Cert-Issuer attribute. This check
+ # can be done via any mechanism you choose.
+ #
+ # check_cert_issuer = "/C=GB/ST=Berkshire/L=Newbury/O=My Company Ltd"
+
+ #
+ # If check_cert_cn is set, the value will
+ # be xlat'ed and checked against the CN
+ # in the client certificate. If the values
+ # do not match, the certificate verification
+ # will fail rejecting the user.
+ #
+ # This check is done only if the previous
+ # "check_cert_issuer" is not set, or if
+ # the check succeeds.
+ #
+ # In 2.1.10 and later, this check can be done
+ # more generally by checking the value of the
+ # TLS-Client-Cert-Common-Name attribute. This check
+ # can be done via any mechanism you choose.
+ #
+ # check_cert_cn = %{User-Name}
+ #
+ # Set this option to specify the allowed
+ # TLS cipher suites. The format is listed
+ # in "man 1 ciphers".
+ cipher_list = "DEFAULT"
+
+ #
+ # Connection timeout for outgoing TLS connections.
+ # Values are 1..30.
+ #
+ connect_timeout = 30
+ }
+}
+
+home_server_pool tls {
+ type = fail-over
+ home_server = tls
+}
+
+realm tls {
+ auth_pool = tls
+}
diff --git a/raddb/sites-available/tls-cache b/raddb/sites-available/tls-cache
new file mode 100644
index 0000000..e6451c5
--- /dev/null
+++ b/raddb/sites-available/tls-cache
@@ -0,0 +1,144 @@
+# -*- text -*-
+######################################################################
+#
+# This is a virtual server which handles TLS session caching.
+#
+# $Id$
+#
+######################################################################
+#
+# In mods-enabled/eap, "cache" subsection
+#
+# comment out
+#
+# persist_dir
+#
+# add
+#
+# virtual_server = tls-cache
+#
+# and set
+#
+# enable = yes
+#
+# In order to enable caching.
+#
+
+#
+# This virtual server SHOULD NOT have any "listen" sections.
+#
+#
+# All of the cache sections key off of &request:TLS-Session-Id
+#
+# The cache sections also run the "post-auth" section of any
+# module which they use.
+#
+# These sections do not need to return any specific codes (e.g. ok /
+# fail /etc.). The cache functionality depends only on which
+# attributes are saved / loaded.
+#
+# For example, if the "cache save" process fails, there is nothing
+# that the server can do about that. The users authentication
+# session will still succeed. The only difference from a successful
+# "cache save" is that the user will be unable to resume their
+# session. Instead, they will need to do a full re-authentication
+# process.
+#
+# Similarly for "cache load". If the session (and/or) the VPs are
+# not loaded from the cache, then the user will do a full
+# re-authentication.
+#
+# Whilst any store can be used for tls session caching, whatever is
+# chosen should be faster than performing a full re-authentication
+server tls-cache {
+
+cache clear {
+ # clear the cache entry by keying off of &request:TLS-Session-Id
+
+ # An example using redis
+# "%{redis:DEL %{request:TLS-Session-ID}}"
+
+ # An example using SQL
+# "%{sql:DELETE FROM tls_cache WHERE session_id = '%{request:TLS-Session-ID}'}"
+}
+
+cache save {
+ # use the key &request:TLS-Session-ID
+ # save &session-state:TLS-Session-Data
+ # save &reply:...
+
+ # The &reply: list is initialized to the attributes
+ # which should be saved. This includes attributes
+ # mentioned in the "store" subsection of the "cache"
+ # section configuration. This is the same set of
+ # attributes which is saved when the 'persist_dir'
+ # configuration is used.
+ #
+ # Note the "store" subsection will only copy matching
+ # attributes from the &reply: list at the time that
+ # eap authentication succeeds.
+ #
+ # Other attributes can be saved by referring to them
+ # e.g. &outer.request:...
+
+ # An example using redis
+# update {
+# &Tmp-String-0 := "%{session-state:TLS-Session-Data}|%{escape:%{reply:Tunnel-Private-Group-ID}}"
+# }
+# "%{redis: SET %{request:TLS-Session-ID} \"%{Tmp-String-0}\" EX 86400}"
+
+ # An example using SQL
+# "%{sql: INSERT INTO tls_cache (session_id, session_data, vlan, expiry) VALUES ('%{request:TLS-Session-ID}', '%{session-state:TLS-Session-Data}', '%{escape:%{reply:Tunnel-Private-Group-ID}}', DATE_ADD(NOW(), INTERVAL 24 HOUR))}"
+}
+
+cache load {
+ # use the key &request:TLS-Session-ID
+ # load &session-state:TLS-Session-Data
+ # load &reply:...
+
+ # Attributes returned in &reply: which are listed
+ # in the "store" subsection of the "cache" section
+ # configuration will be copied to &session-state:
+ #
+ # Certificate attributes returned in &reply: are added
+ # to &request: if they do not already exist and if
+ # EAP-Type is returned it is added to &control:
+ #
+ # Any other attributes returned are added to &reply:
+
+ # An example using redis
+# update {
+# &Tmp-String-0 := "%{redis:GET %{request:TLS-Session-ID}}"
+# }
+# if (!&Tmp-String-0 || &Tmp-String-0 !~ /^([^|]+)\|([^|]+)$/) {
+# return
+# }
+# update {
+# &session-state:TLS-Session-Data := "%{1}"
+# &reply:Tunnel-Private-Group-ID := "%{unescape:%{2}}"
+# }
+
+ # An example using SQL
+# update {
+# &Tmp-String-0 := "%{sql:SELECT CONCAT(session_data, '|', vlan) FROM session_cache WHERE session_id = '%{request:TLS-Session-ID}'}"
+# }
+# if (!&Tmp-String-0 || &Tmp-String-0 !~ /^([^|]+)\|([^|]+)$/) {
+# return
+# }
+# update {
+# &session-state:TLS-Session-Data := "%{1}"
+# &reply:Tunnel-Private-Group-ID := "%{unescape:%{2}}"
+# }
+}
+
+cache refresh {
+ # refresh the cache entry by keying off of &request:TLS-Session-ID
+
+ # An example using redis
+# "%{redis:EXPIRE %{request:TLS-Session-ID} 86400}"
+
+ # An example using SQL
+# "%{sql:UPDATE tls_cache SET expiry = DATE_ADD(NOW(), INTERVAL 24 HOUR) WHERE session_id = '%{request:TLS-Session-ID}'}"
+}
+
+}
diff --git a/raddb/sites-available/totp b/raddb/sites-available/totp
new file mode 100644
index 0000000..e42bf05
--- /dev/null
+++ b/raddb/sites-available/totp
@@ -0,0 +1,85 @@
+######################################################################
+#
+# $Id$
+#
+######################################################################
+#
+# Simple server to do TOTP and not much else.
+#
+server totp {
+authorize {
+ #
+ # TOTP only works for PAP
+ #
+ if (!&User-Password) {
+ reject
+ }
+
+ #
+ # The 6-digit TOTP password should be at the end of the
+ # User-Password attribute. It can be at the beginning or at
+ # the end, it doesn't really make any difference. Just
+ # update the regular expression for whatever you want.
+ #
+ # If the password doesn't have 6 digits at the end, reject.
+ #
+ if (User-Password !~ /^(.*)([0-9]{6})$/) {
+ reject
+ }
+
+ #
+ # Separate the two fields
+ #
+ update request {
+ User-Password := "%{1}"
+ TOTP-Password := "%{2}"
+ }
+
+ #
+ # Get the users' real password and authorization credentials
+ # from somewhere, such as a database. This should also set
+ #
+ # &control:TOTP-Secret
+ #
+ -ldap
+ -sql
+
+ #
+ # As an example, fake out the TOTP secret
+ #
+ # The value should be the base-32 version of the TOTP secret.
+ #
+ # Note that the TOTP secret is effectively a password, and
+ # should be kept secret! At this time, there is no way to
+ # "hide" or "encrypt" the TOTP secret for a user. Even if it
+ # was encrypted, the server would still need a key to decrypt
+ # it. So encrypying this field does not offer much benefit.
+ #
+ if (&User-Name == "bob") {
+ &control:TOTP-Secret := 12345678901234567890
+ }
+
+ #
+ # Verify the 6-digit TOTP password. If the module does not
+ # return "ok", then the TOTP password is wrong.
+ #
+ totp.authenticate
+ if (!ok) {
+ reject
+ }
+
+ #
+ # Set Auth-Type = PAP
+ #
+ pap
+}
+
+authenticate {
+ #
+ # Check the User-Password against whatever we found in LDAP
+ # or SQL.
+ #
+ pap
+}
+
+}
diff --git a/raddb/sites-available/virtual.example.com b/raddb/sites-available/virtual.example.com
new file mode 100644
index 0000000..3c4aea7
--- /dev/null
+++ b/raddb/sites-available/virtual.example.com
@@ -0,0 +1,32 @@
+# -*- text -*-
+######################################################################
+#
+# Sample virtual server for internally proxied requests.
+#
+# See the "realm virtual.example.com" example in "proxy.conf".
+#
+# $Id$
+#
+######################################################################
+
+#
+# You will want to edit this to your local needs. We suggest copying
+# the text from the "default" file here, and then editing the text.
+# That way, any changes to the "default" file will not affect this
+# virtual server, and vice-versa.
+#
+# When this virtual server receives the request, the original
+# attributes can be accessed as "outer.request", "outer.control", etc.
+# See "man unlang" for more details.
+#
+server virtual.example.com {
+authorize {
+ # insert policies here
+}
+
+authenticate {
+ # insert policies here
+}
+
+# etc.
+}
diff --git a/raddb/sites-available/vmps b/raddb/sites-available/vmps
new file mode 100644
index 0000000..c5c5078
--- /dev/null
+++ b/raddb/sites-available/vmps
@@ -0,0 +1,98 @@
+# -*- text -*-
+######################################################################
+#
+# As of version 2.0.0, the server also supports the VMPS
+# protocol.
+#
+# $Id$
+#
+######################################################################
+
+server vmps {
+ listen {
+ # VMPS sockets only support IPv4 addresses.
+ ipaddr = *
+
+ # Port on which to listen.
+ # Allowed values are:
+ # integer port number
+ # 1589 is the default VMPS port.
+ port = 1589
+
+ # Type of packets to listen for. Here, it is VMPS.
+ type = vmps
+
+ # Some systems support binding to an interface, in addition
+ # to the IP address. This feature isn't strictly necessary,
+ # but for sites with many IP addresses on one interface,
+ # it's useful to say "listen on all addresses for
+ # eth0".
+ #
+ # If your system does not support this feature, you will
+ # get an error if you try to use it.
+ #
+ # interface = eth0
+ }
+
+ # If you have switches that are allowed to send VMPS, but NOT
+ # RADIUS packets, then list them here as "client" sections.
+ #
+ # Note that for compatibility with RADIUS, you still have to
+ # list a "secret" for each client, though that secret will not
+ # be used for anything.
+
+
+ # And the REAL contents. This section is just like the
+ # "post-auth" section of radiusd.conf. In fact, it calls the
+ # "post-auth" component of the modules that are listed here.
+ # But it's called "vmps" to highlight that it's for VMPS.
+ #
+ vmps {
+ #
+ # Some requests may not have a MAC address. Try to
+ # create one using other attributes.
+ if (!&VMPS-Mac) {
+ if (&VMPS-Ethernet-Frame =~ /0x.{12}(..)(..)(..)(..)(..)(..).*/) {
+ update request {
+ &VMPS-Mac = "%{1}:%{2}:%{3}:%{4}:%{5}:%{6}"
+ }
+ }
+ else {
+ update request {
+ &VMPS-Mac = &VMPS-Cookie
+ }
+ }
+ }
+
+ # Do a simple mapping of MAC to VLAN.
+ #
+ # See radiusd.conf for the definition of the "mac2vlan"
+ # module.
+ #
+ #mac2vlan
+
+ # required VMPS reply attributes
+ update reply {
+ &VMPS-Packet-Type = VMPS-Join-Response
+ &VMPS-Cookie = &VMPS-Mac
+
+ &VMPS-VLAN-Name = "please_use_real_vlan_here"
+
+ #
+ # If you have VLAN's in a database, you can select
+ # the VLAN name based on the MAC address.
+ #
+ #&VMPS-VLAN-Name = "%{sql:select ... where mac='%{VMPS-Mac}'}"
+ }
+
+ # correct reply packet type for reconfirmation requests
+ #
+ if (&VMPS-Packet-Type == VMPS-Reconfirm-Request){
+ update reply {
+ &VMPS-Packet-Type := VMPS-Reconfirm-Response
+ }
+ }
+ }
+
+ # Proxying of VMPS requests is NOT supported.
+}
diff --git a/raddb/templates.conf b/raddb/templates.conf
new file mode 100644
index 0000000..7b8b44e
--- /dev/null
+++ b/raddb/templates.conf
@@ -0,0 +1,108 @@
+# -*- text -*-
+##
+## templates.conf -- configurations to be used in multiple places
+##
+## $Id$
+
+######################################################################
+#
+# Version 2.0 has a useful new feature called "templates".
+#
+# Use templates by adding a line in radiusd.conf:
+#
+# $INCLUDE templates.conf
+#
+# The goal of the templates is to have common configuration located
+# in this file, and to list only the *differences* in the individual
+# sections. This feature is most useful for sections like "clients"
+# or "home_servers", where many may be defined, and each one has
+# similar repeated configuration.
+#
+# Something similar to templates can be done by putting common
+# configuration into separate files, and using "$INCLUDE file...",
+# but this is more flexible, and simpler to understand. It's also
+# cheaper for the server, because "$INCLUDE" makes a copy of the
+# configuration for inclusion, and templates are simply referenced.
+#
+# The templates are defined in the "templates" section, so that they
+# do not affect the rest of the server configuration.
+#
+# A section can reference a template by using "$template name"
+#
+templates {
+ #
+ # The contents of the templates section are other
+ # configuration sections that would normally go into
+ # the configuration files.
+ #
+
+ #
+ # This is a default template for the "home_server" section.
+ # Note that there is no name for the section.
+ #
+ # Any configuration item that is valid for a "home_server"
+ # section is also valid here. When a "home_server" section
+ # is defined in proxy.conf, this section is referenced as
+ # the template.
+ #
+ # Configuration items that are explicitly listed in a
+ # "home_server" section of proxy.conf are used in
+ # preference to the configuration items listed here.
+ #
+ # However, if a configuration item is NOT listed in a
+ # "home_server" section of proxy.conf, then the value here
+ # is used.
+ #
+ # This functionality lets you put common configuration into
+ # a template, and to put only the unique configuration
+ # items in "proxy.conf". Each section in proxy.conf can
+ # then contain a line "$template home_server", which will
+ # cause it to reference this template.
+ #
+ home_server {
+ response_window = 20
+ zombie_period = 40
+ revive_interval = 120
+ #
+ # Etc.
+ }
+
+ #
+ # You can also have named templates. For example, if you
+ # are proxying to 3 different home servers all at the same
+ # site, with identical configurations (other than IP
+ # addresses), you can use this named template.
+ #
+
+ # Then, each "home_server" section in "proxy.conf" would
+ # only list the IP address of that home server, and a
+ # line saying
+ #
+ # $template example_com
+ #
+ # That would tell FreeRADIUS to look in the section below
+ # for the rest of the configuration items.
+ #
+ # For various reasons, you shouldn't have a "." in the template
+ # name. Doing so means that the server will be unable to find
+ # the template.
+ #
+ example_com {
+ type = auth
+ port = 1812
+ secret = testing123
+ response_window = 20
+ #
+ # Etc...
+ }
+
+ #
+ # You can have templates for other sections, too, but they
+ # seem to be most useful for home_servers.
+ #
+ # For now, you can use templates only for sections in
+ # radiusd.conf, not sub-sections. So you still have to use
+ # the "$INCLUDE file.." method for things like defining
+ # multiple "sql" modules, each with similar configuration.
+ #
+}
diff --git a/raddb/trigger.conf b/raddb/trigger.conf
new file mode 100644
index 0000000..413a182
--- /dev/null
+++ b/raddb/trigger.conf
@@ -0,0 +1,281 @@
+# -*- text -*-
+##
+## trigger.conf -- Events in the server can trigger a hook to be executed.
+##
+## $Id$
+
+#
+# The triggers are named as "type.subtype.value". These names refer
+# to subsections and then configuration items in the "trigger"
+# section below. When an event occurs, the trigger is executed. The
+# trigger is simply a program that is run, with optional arguments.
+#
+# The server does not wait when a trigger is executed. It is simply
+# a "one-shot" event that is sent.
+#
+# The trigger names should be self-explanatory.
+#
+
+#
+# SNMP configuration.
+#
+# For now, this is only for SNMP traps.
+#
+# They are enabled by uncommenting (or adding) "$INCLUDE trigger.conf"
+# in the main "radiusd.conf" file.
+#
+# The traps *REQUIRE* that the files in the "mibs" directory be copied
+# to the global mibs directory, usually /usr/share/snmp/mibs/.
+# If this is not done, the "snmptrap" program has no idea what information
+# to send, and will not work. The MIB installation is *NOT* done as
+# part of the default installation, so that step *MUST* be done manually.
+#
+# The global MIB directory can be found by running the following command:
+#
+# snmptranslate -Dinit_mib .1.3 2>&1 | grep MIBDIR | sed "s/' .*//;s/.* '//;s/.*://"
+#
+# Or maybe just:
+#
+# snmptranslate -Dinit_mib .1.3 2>&1 | grep MIBDIR
+#
+# If you have copied the MIBs to that directory, you can test the
+# FreeRADIUS MIBs by running the following command:
+#
+# snmptranslate -m +FREERADIUS-NOTIFICATION-MIB -IR -On serverStart
+#
+# It should print out:
+#
+# .1.3.6.1.4.1.11344.4.1.1
+#
+# As always, run the server in debugging mode after enabling the
+# traps. You will see the "snmptrap" command being run, and it will
+# print out any errors or issues that it encounters. Those need to
+# be fixed before running the server in daemon mode.
+#
+# We also suggest running in debugging mode as the "radiusd" user, if
+# you have "user/group" set in radiusd.conf. The "snmptrap" program
+# may behave differently when run as "root" or as the "radiusd" user.
+#
+snmp {
+ #
+ # Configuration for SNMP traps / notifications
+ #
+ # To disable traps, edit "radiusd.conf", and delete the line
+ # which says "$INCUDE trigger.conf"
+ #
+ trap {
+ #
+ # Absolute path for the "snmptrap" command, and
+ # default command-line arguments.
+ #
+ # You can disable traps by changing the command to
+ # "/bin/echo".
+ #
+ cmd = "/usr/bin/snmptrap -v2c"
+
+ #
+ # Community string
+ #
+ community = "public"
+
+ #
+ # Agent configuration.
+ #
+ agent = "localhost ''"
+ }
+}
+
+#
+# The "snmptrap" configuration defines the full command used to run the traps.
+#
+# This entry should not be edited. Instead, edit the "trap" section above.
+#
+snmptrap = "${snmp.trap.cmd} -c ${snmp.trap.community} ${snmp.trap.agent} FREERADIUS-NOTIFICATION-MIB"
+
+#
+# The individual triggers are defined here. You can disable one by
+# deleting it, or by commenting it out. You can disable an entire
+# section of traps by deleting the section.
+#
+# The entries below should not be edited. For example, the double colons
+# *must* immediately follow the ${snmptrap} reference. Adding a space
+# before the double colons will break all SNMP traps.
+#
+# However... the traps are just programs which are run when
+# particular events occur. If you want to replace a trap with
+# another program, you can. Just edit the definitions below, so that
+# they run a program of your choice.
+#
+# For example, you can leverage the "start/stop" triggers to run a
+# program when the server starts, or when it stops. But that will
+# prevent the start/stop SNMP traps from working, of course.
+#
+trigger {
+ #
+ # Events in the server core
+ #
+ server {
+ # the server has just started
+ start = "${snmptrap}::serverStart"
+
+ # the server is about to stop
+ stop = "${snmptrap}::serverStop"
+
+ # The "max_requests" condition has been reached.
+ # This will trigger only once per 60 seconds.
+ max_requests = "${snmptrap}::serverMaxRequests"
+
+ # For events related to clients
+ client {
+ # Added a new dynamic client
+ add = "/path/to/file %{Packet-Src-IP-Address}"
+
+ # There is no event for when dynamic clients expire
+ }
+
+ # Events related to signals received.
+ signal {
+ # a HUP signal
+ hup = "${snmptrap}::signalHup"
+
+ # a TERM signal
+ term = "${snmptrap}::signalTerm"
+ }
+
+
+ # Events related to the thread pool
+ thread {
+ # A new thread has been started
+ start = "${snmptrap}::threadStart"
+
+ # an existing thread has been stopped
+ stop = "${snmptrap}::threadStop"
+
+ # an existing thread is unresponsive
+ unresponsive = "${snmptrap}::threadUnresponsive"
+
+ # the "max_threads" limit has been reached
+ max_threads = "${snmptrap}::threadMaxThreads"
+ }
+ }
+
+ # When a home server changes state.
+ # These traps are edge triggered.
+ home_server {
+ # common arguments: IP, port, identifier
+ args = "radiusAuthServerAddress a %{proxy-request:Packet-Dst-IP-Address} radiusAuthClientServerPortNumber i %{proxy-request:Packet-Dst-Port} radiusAuthServIdent s '%{home_server:instance}'"
+
+ # The home server has been marked "alive"
+ alive = "${snmptrap}::homeServerAlive ${args}"
+
+ # The home server has been marked "zombie"
+ zombie = "${snmptrap}::homeServerZombie ${args}"
+
+ # The home server has been marked "dead"
+ dead = "${snmptrap}::homeServerDead ${args}"
+ }
+
+ # When a pool of home servers changes state.
+ home_server_pool {
+ # common arguments
+ args = "radiusdConfigName s %{home_server:instance}"
+
+ # It has reverted to "normal" mode, where at least one
+ # home server is alive.
+ normal = "${snmptrap}::homeServerPoolNormal ${args}"
+
+ # It is in "fallback" mode, with all home servers "dead"
+ fallback = "${snmptrap}::homeServerPoolFallback ${args}"
+ }
+
+ # Triggers for specific modules. These are NOT in the module
+ # configuration because they are global to all instances of the
+ # module. You can have module-specific triggers, by placing a
+ # "trigger" subsection in the module configuration.
+ modules {
+ # Common arguments
+ args = "radiusdModuleInstance s ''"
+
+ # The files module
+ files {
+ # Common arguments
+ args = "radiusdModuleName s files ${..args}"
+
+ # The module has been HUP'd via radmin
+ hup = "${snmptrap}::serverModuleHup ${args}"
+
+ # Note that "hup" can be used for every module
+ # which can be HUP'd via radmin
+ }
+
+ # The LDAP module
+ # If the server does "bind as user", it will open and close
+ # an LDAP connection ofr every "bind as user". Be aware that
+ # this will likely produce a lot of triggers.
+ ldap {
+ # Common arguments
+ args = "radiusdModuleName s ldap ${..args}"
+
+ # A new connection to the DB has been opened
+ open = "${snmptrap}::serverModuleConnectionUp ${args}"
+
+ # A connection to the DB has been closed
+ close = "${snmptrap}::serverModuleConnectionDown ${args}"
+
+ # The module has been HUP'd via radmin
+ hup = "${snmptrap}::serverModuleHup ${args}"
+ }
+
+ # The SQL module
+ sql {
+ # Common arguments
+ args = "radiusdModuleName s sql ${..args}"
+
+ # A new connection to the DB has been opened
+ open = "${snmptrap}::serverModuleConnectionUp ${args}"
+
+ # A connection to the DB has been closed
+ close = "${snmptrap}::serverModuleConnectionDown ${args}"
+
+ # Failed to open a new connection to the DB
+ fail = "${snmptrap}::serverModuleConnectionFail ${args}"
+
+ # The module has been HUP'd via radmin
+ hup = "${snmptrap}::serverModuleHup ${args}"
+ }
+
+ # You can also use connection pool's start/stop/open/close triggers
+ # for any module which uses the "pool" section, here and under
+ # pool.trigger in module configuration.
+ }
+}
+
+#
+# The complete list of triggers as generated from the source code is below.
+#
+# These are the ONLY traps which are generated. You CANNOT add new traps
+# by defining them in one of the sections above. New traps can be created
+# only by edited both the source code to the server, *and* the MIBs.
+# If you are not an expert in C and SNMP, then adding new traps will be
+# difficult to create.
+#
+# home_server.alive
+# home_server.dead
+# home_server.zombie
+# home_server_pool.fallback
+# home_server_pool.normal
+# modules.*.hup
+# modules.ldap.timeout
+# modules.sql.close
+# modules.sql.fail
+# modules.sql.open
+# server.client.add
+# server.max_requests
+# server.signal.hup
+# server.signal.term
+# server.start
+# server.stop
+# server.thread.max_threads
+# server.thread.start
+# server.thread.stop
+# server.thread.unresponsive
diff --git a/raddb/vmpsd.conf.in b/raddb/vmpsd.conf.in
new file mode 100644
index 0000000..d68ef01
--- /dev/null
+++ b/raddb/vmpsd.conf.in
@@ -0,0 +1,405 @@
+##
+## vmpsd.conf -- FreeRADIUS VMPS server configuration file.
+##
+## http://www.freeradius.org/
+## $Id$
+##
+
+#
+# This configuration file is for a stand-alone VMPS server that
+# does not do RADIUS. For an integrated radius + vmps server,
+# edit "radiusd.conf", and add two sections to it:
+#
+# listen {
+# type = vmps
+# ...
+# }
+#
+# vmps {
+# ...
+# }
+#
+#
+# See the text below for additional documentation on those two
+# sections.
+#
+
+# 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.
+
+#
+# Standard includes, etc.
+#
+# FIXME: to make this work: prefix, etc. See radiusd.conf...
+#
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+sysconfdir = @sysconfdir@
+localstatedir = @localstatedir@
+sbindir = @sbindir@
+logdir = @logdir@
+raddbdir = @raddbdir@
+radacctdir = @radacctdir@
+
+#
+# The logging messages for the server are appended to the
+# tail of this file.
+#
+log_file = ${logdir}/vmpsd.log
+
+#
+# Destination for log messages. This can be one of:
+#
+# files - log to ${log_file}, as defined above.
+# syslog - to syslog (see also the log{} section, below)
+# stdout - standard output
+# stderr - standard error.
+#
+# The command-line option "-X" over-rides this option, and forces
+# logging to go to stdout.
+#
+log_destination = files
+
+#
+# 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 = @libdir@
+
+# 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}/vmpsd.pid
+
+
+# user/group: The name (or #number) of the user/group to run vmpsd 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 privileges ) 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 VMPS 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
+
+# listen: Make the server listen on a particular IP address, and send
+# replies out from that address. This directive is most useful for
+# hosts with multiple IP addresses on one interface.
+#
+# If you want the server to listen on additional addresses, or on
+# additional ports, you can use multiple "listen" sections.
+#
+# Each section make the server listen for only one type of packet,
+# therefore authentication and accounting have to be configured in
+# different sections.
+#
+# The server ignore all "listen" section if you are using '-i' and '-p'
+# on the command line.
+#
+listen {
+ # IP address on which to listen.
+ # Allowed values are:
+ # dotted quad (1.2.3.4)
+ # hostname (radius.example.com)
+ # wildcard (*)
+ ipaddr = *
+
+ # OR, you can use an IPv6 address, but not both
+ # at the same time.
+# ipv6addr = :: # any. ::1 == localhost
+
+ # Port on which to listen.
+ # Allowed values are:
+ # integer port number
+ # 1589 is the default VMPS port.
+ port = 1589
+
+ # Type of packets to listen for. Use "vmps" for VMPSd.
+ #
+ type = vmps
+
+ # Some systems support binding to an interface, in addition
+ # to the IP address. This feature isn't strictly necessary,
+ # but for sites with many IP addresses on one interface,
+ # it's useful to say "listen on all addresses for eth0".
+ #
+ # If your system does not support this feature, you will
+ # get an error if you try to use it.
+ #
+# interface = eth0
+
+ # Per-socket lists of clients. This is a very useful feature.
+ #
+ # The name here is a reference to a section elsewhere in
+ # radiusd.conf, or clients.conf. Having the name as
+ # a reference allows multiple sockets to use the same
+ # set of clients.
+ #
+ # If this configuration is used, then the global list of clients
+ # is IGNORED for this "listen" section. Take care configuring
+ # this feature, to ensure you don't accidentally disable a
+ # client you need.
+ #
+ # See clients.conf for the configuration of "per_socket_clients".
+ #
+# clients = per_socket_clients
+}
+
+# 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 = no
+
+#
+# Logging section. The various "log_*" configuration items
+# will eventually be moved here.
+#
+log {
+ #
+ # Which syslog facility to use, if ${log_destination} == "syslog"
+ #
+ # The exact values permitted here are OS-dependent. You probably
+ # don't want to change this.
+ #
+ syslog_facility = daemon
+}
+
+# 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, The server 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 {
+ #
+ # Add modules here. See "radiusd.conf" for examples.
+ #
+}
+
+# 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 initialized. 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 {
+ #
+ # Add modules here. See "radiusd.conf" for examples.
+ #
+}
+
+#
+# And the REAL contents. This section is just like the "post-auth"
+# section of radiusd.conf. In fact, it calls the "post-auth" component
+# of the modules that are listed here. But it's called "vmps" for
+# simplicity.
+#
+vmps {
+ #
+ # This is a hack for testing
+ #
+ update reply {
+ VMPS-Packet-Type = VMPS-Join-Response
+ VMPS-VLAN-Name = "foo"
+ VMPS-Cookie = "%{VMPS-Mac}"
+ }
+}
diff --git a/redhat/.gitignore b/redhat/.gitignore
new file mode 100644
index 0000000..fcd2cd1
--- /dev/null
+++ b/redhat/.gitignore
@@ -0,0 +1 @@
+freeradius-logrotate~*
diff --git a/redhat/README b/redhat/README
new file mode 100644
index 0000000..6fc814a
--- /dev/null
+++ b/redhat/README
@@ -0,0 +1,10 @@
+ The files in this directory are intended only for "generic" systems.
+If you need to build FreeRADIUS from source on a RedHat system (RHEL,
+Fedora, or CentOS), please read the following FAQ:
+
+ http://wiki.freeradius.org/guide/Red_Hat_FAQ
+
+ It was written by the person who maintains the RedHat FreeRADIUS
+packages, and contains detailed instructions for creating an RPM from
+the original RedHat spec files. This ensures that the RPMs on your
+system closely match the RedHat requirements.
diff --git a/redhat/freeradius-logrotate b/redhat/freeradius-logrotate
new file mode 100644
index 0000000..7767806
--- /dev/null
+++ b/redhat/freeradius-logrotate
@@ -0,0 +1,61 @@
+#
+# You can use this to rotate the /var/log/radius/* files, simply copy
+# it to /etc/logrotate.d/radiusd
+#
+
+#
+# The main server log
+#
+/var/log/radius/radius.log {
+ # Common options
+ monthly
+ rotate 4
+ missingok
+ compress
+ delaycompress
+ su radiusd radiusd
+
+ copytruncate
+}
+
+
+#
+# Session monitoring utilities and SQL log files (in order)
+#
+/var/log/radius/checkrad.log /var/log/radius/radwatch.log
+/var/log/radius/sqllog.sql
+{
+ # Common options
+ monthly
+ rotate 4
+ missingok
+ compress
+ delaycompress
+ su radiusd radiusd
+
+ nocreate
+}
+
+
+#
+# There are different detail-rotating strategies you can use. One is
+# to write to a single detail file per IP and use the rotate config
+# below. Another is to write to a daily detail file per IP with:
+#
+# detailfile = ${radacctdir}/%{Client-IP-Address}/%Y%m%d-detail
+#
+# (or similar) in radiusd.conf, without rotation. If you go with the
+# second technique, you will need another cron job that removes old
+# detail files. You do not need to comment out the below for method #2.
+#
+/var/log/radius/radacct/*/detail {
+ # Common options
+ monthly
+ rotate 4
+ missingok
+ compress
+ delaycompress
+ su radiusd radiusd
+
+ nocreate
+}
diff --git a/redhat/freeradius-pam-conf b/redhat/freeradius-pam-conf
new file mode 100644
index 0000000..090c4a5
--- /dev/null
+++ b/redhat/freeradius-pam-conf
@@ -0,0 +1,6 @@
+#%PAM-1.0
+auth include password-auth
+account required pam_nologin.so
+account include password-auth
+password include password-auth
+session include password-auth
diff --git a/redhat/freeradius-radiusd-init b/redhat/freeradius-radiusd-init
new file mode 100755
index 0000000..d19b2d4
--- /dev/null
+++ b/redhat/freeradius-radiusd-init
@@ -0,0 +1,191 @@
+#!/bin/sh
+#
+# radiusd Start/Stop the FreeRADIUS daemon
+#
+# chkconfig: - 88 10
+# description: Extensible, configurable, high performance RADIUS server.
+
+### BEGIN INIT INFO
+# Provides: radiusd
+# Required-Start: $network
+# Required-Stop:
+# Default-Start:
+# Default-Stop:
+# Should-Start: $time $syslog mysql ldap postgresql samba krb5-kdc
+# Should-Stop:
+# Short-Description: FreeRADIUS server
+# Description: Extensible, configurable, high performance RADIUS server.
+### END INIT INFO
+
+# Source function library.
+
+# Get the wrappers for the standard lsb init functions
+. /lib/lsb/init-functions
+
+# and the distro specific ones
+. /etc/init.d/functions
+
+prog=radiusd
+
+[ -e /etc/sysconfig/$prog ] && . /etc/sysconfig/$prog
+
+exec=${exec:=/usr/sbin/$prog}
+config_dir=${config_dir:=/etc/raddb}
+config=${config:=$config_dir/radiusd.conf}
+pidfile=${pidfile:=/var/run/$prog/$prog.pid}
+lockfile=${lockfile:=/var/lock/subsys/radiusd}
+
+configtest() {
+ echo -n $"Checking $prog configuration: "
+ out=`$exec -Cxl stdout -d $config_dir`; retval=$?
+ out=`echo "${out}" | tail -n 1 | sed 's/^\s*ERROR:\s*\(.*\)\s*$/\1/'`
+
+ # Seems some LSB function implementations *really* need
+ # a log message < 60 chars long, else output gets mangled.
+ if [ $retval -eq 0 ]; then
+ log_success_msg
+ else
+ if [ $(expr length "$out") -gt 60 ]; then
+ log_failure_msg
+ echo "$out" 1>&2
+ else
+ log_failure_msg "$out"
+ fi
+ fi
+ return $retval
+}
+
+start() {
+ echo -n $"Starting $prog: "
+
+ if [ ! -x $exec ]; then
+ log_failure_msg "$exec not found or not executable"
+ exit 5
+ fi
+
+ if [ ! -f $config ]; then
+ log_failure_msg "Can't find radiusd.conf"
+ exit 6
+ fi
+
+ start_daemon -p $pidfile $exec -d $config_dir
+ retval=$?
+ if [ $retval -eq 0 ]; then
+ log_success_msg
+ else
+ log_failure_msg
+ fi
+ return $retval
+}
+
+stop() {
+ echo -n $"Stopping $prog: "
+ killproc -p $pidfile $prog
+ retval=$?
+ if [ $retval -eq 0 ]; then
+ log_success_msg
+ rm -f $lockfile
+ else
+ log_failure_msg
+ fi
+ return $retval
+}
+
+restart() {
+ stop
+ start
+}
+
+reload() {
+ # radiusd may not be capable of a 100% configuration reload depending
+ # on which loadable modules are in use, if sending the server a
+ # HUP is not sufficient then use restart here instead. However, we
+ # prefer by default to use HUP since it's what is usually desired.
+ #
+ # restart
+
+ kill -HUP `pidofproc -p $pidfile $prog`
+}
+
+force_reload() {
+ restart
+}
+
+rh_status() {
+ # run checks to determine if the service is running or use generic status
+ status -p $pidfile $prog
+}
+
+rh_status_q() {
+ rh_status >/dev/null 2>&1
+}
+
+case "$1" in
+ start)
+ rh_status_q && exit 0
+ configtest || exit 150
+ $1
+ ;;
+
+ stop)
+ rh_status_q || exit 0
+ $1
+ ;;
+
+ restart)
+ configtest || exit 150
+ $1
+ ;;
+
+ reload)
+ rh_status_q || exit 7
+ configtest || exit 150
+ $1
+ ;;
+
+ force-reload)
+ configtest || exit 150
+ force_reload
+ ;;
+
+ condrestart|try-restart)
+ configtest || exit 150
+ rh_status_q || exit 0
+ restart
+ ;;
+
+ configtest|testconfig)
+ configtest || exit 150
+ ;;
+
+ debug)
+ echo -n $"Debugging $prog: "
+ if rh_status_q; then
+ log_failure_msg "$prog already running; for live debugging see raddebug(8)"
+ exit 151
+ else
+ log_success_msg
+ fi
+ $exec -X -d $config_dir || exit $?
+ ;;
+
+ debug-threaded)
+ echo -n $"Debugging $prog: "
+ if rh_status_q; then
+ log_failure_msg "$prog already running; for live debugging see raddebug(8)"
+ exit 151
+ else
+ log_success_msg
+ fi
+ $exec -f -xx -l stdout -d $config_dir || exit $?
+ ;;
+
+ status)
+ rh_status
+ ;;
+
+ *)
+ echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload|configtest|debug|debug-threaded}"
+ exit 2
+esac
+exit $?
diff --git a/redhat/freeradius-tmpfiles-conf b/redhat/freeradius-tmpfiles-conf
new file mode 100644
index 0000000..ead7a2f
--- /dev/null
+++ b/redhat/freeradius-tmpfiles-conf
@@ -0,0 +1 @@
+D /var/run/radiusd 0710 radiusd radiusd -
diff --git a/redhat/freeradius.spec b/redhat/freeradius.spec
new file mode 100644
index 0000000..3cb211f
--- /dev/null
+++ b/redhat/freeradius.spec
@@ -0,0 +1,956 @@
+%bcond_with rlm_yubikey
+%bcond_without ldap
+# %%bcond_with experimental_modules
+
+%{!?_with_rlm_cache_memcached: %global _without_rlm_cache_memcached --without-rlm_cache_memcached}
+%{!?_with_rlm_eap_pwd: %global _without_rlm_eap_pwd --without-rlm_eap_pwd}
+%{!?_with_rlm_eap_tnc: %global _without_rlm_eap_tnc --without-rlm_eap_tnc}
+%{!?_with_rlm_yubikey: %global _without_rlm_yubikey --without-rlm_yubikey}
+%{?_without_ldap: %global _without_libfreeradius_ldap --without-libfreeradius-ldap}
+
+# experimental modules
+%bcond_with rlm_idn
+%bcond_with rlm_ruby
+%bcond_with rlm_sql_oracle
+%{?_with_rlm_idn: %global _with_experimental_modules --with-experimental-modules}
+%{?_with_rlm_opendirectory: %global _with_experimental_modules --with-experimental-modules}
+%{?_with_rlm_ruby: %global _with_experimental_modules --with-experimental-modules}
+%{?_with_rlm_securid: %global _with_experimental_modules --with-experimental-modules}
+%{?_with_rlm_sql_oracle: %global _with_experimental_modules --with-experimental-modules}
+
+%if %{?_with_experimental_modules:1}%{!?_with_experimental_modules:0}
+%{!?_with_rlm_idn: %global _without_rlm_idn --without-rlm_idn}
+%{!?_with_rlm_opendirectory: %global _without_rlm_opendirectory --without-rlm_opendirectory}
+%{!?_with_rlm_ruby: %global _without_rlm_ruby --without-rlm_ruby}
+%{!?_with_rlm_securid: %global _without_rlm_securid --without-rlm_securid}
+%{!?_with_rlm_sql_oracle: %global _without_rlm_sql_oracle --without-rlm_sql_oracle}
+%endif
+
+%{?el6: %global _without_libwbclient --with-winbind-dir=/nonexistant}
+
+Summary: High-performance and highly configurable free RADIUS server
+Name: freeradius
+Version: 3.2.3
+Release: 1%{?dist}
+License: GPLv2+ and LGPLv2+
+Group: System Environment/Daemons
+URL: http://www.freeradius.org/
+
+Source0: ftp://ftp.freeradius.org/pub/radius/freeradius-server-%{version}.tar.bz2
+%if %{?_unitdir:1}%{!?_unitdir:0}
+Source100: radiusd.service
+Source104: freeradius-tmpfiles-conf
+%else
+Source100: freeradius-radiusd-init
+%define initddir %{?_initddir:%{_initddir}}%{!?_initddir:%{_initrddir}}
+%endif
+
+Source102: freeradius-logrotate
+Source103: freeradius-pam-conf
+
+Obsoletes: freeradius-devel
+Obsoletes: freeradius-libs
+
+%define docdir %{_docdir}/freeradius-%{version}
+%define initddir %{?_initddir:%{_initddir}}%{!?_initddir:%{_initrddir}}
+
+BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
+
+BuildRequires: autoconf
+BuildRequires: gdbm-devel
+BuildRequires: openssl, openssl-devel
+BuildRequires: pam-devel
+BuildRequires: zlib-devel
+BuildRequires: net-snmp-devel
+BuildRequires: net-snmp-utils
+%{?el7:BuildRequires: libwbclient-devel}
+%{?el7:BuildRequires: samba-devel}
+%if %{?_unitdir:1}%{!?_unitdir:0}
+BuildRequires: systemd-devel
+%endif
+BuildRequires: readline-devel
+BuildRequires: libpcap-devel
+BuildRequires: libtalloc-devel
+BuildRequires: libcurl-devel
+
+Requires(pre): shadow-utils glibc-common
+Requires(post): /sbin/chkconfig
+Requires(preun): /sbin/chkconfig
+Requires: freeradius-config = %{version}-%{release}
+Requires: openssl
+Requires: libpcap
+Requires: readline
+Requires: libtalloc
+Requires: net-snmp
+%{?el7:Requires: libwbclient}
+Requires: zlib
+Requires: pam
+%{?el6:Requires: redhat-lsb-core}
+
+%if %{?_with_rlm_idn:1}%{?!_with_rlm_idn:0}
+Requires: libidn
+BuildRequires: libidn-devel
+%endif
+
+%description
+The FreeRADIUS Server Project is a high performance and highly configurable
+GPL'd free RADIUS server. The server is similar in some respects to
+Livingston's 2.0 server. While FreeRADIUS started as a variant of the
+Cistron RADIUS server, they don't share a lot in common any more. It now has
+many more features than Cistron or Livingston, and is much more configurable.
+
+FreeRADIUS is an Internet authentication daemon, which implements the RADIUS
+protocol, as defined in RFC 2865 (and others). It allows Network Access
+Servers (NAS boxes) to perform authentication for dial-up users. There are
+also RADIUS clients available for Web servers, firewalls, Unix logins, and
+more. Using RADIUS allows authentication and authorization for a network to
+be centralized, and minimizes the amount of re-configuration which has to be
+done when adding or deleting new users.
+
+# CentOS defines debug package by default. Only define it if not already defined
+%if 0%{!?_enable_debug_packages:1}
+%debug_package
+%endif
+
+%if %{?_with_rlm_cache_memcached:1}%{?!_with_rlm_cache_memcached:0}
+%package memcached
+Summary: Memcached support for freeRADIUS
+Group: System Environment/Daemons
+Requires: %{name} = %{version}-%{release}
+Requires: libmemcached
+BuildRequires: libmemcached-devel
+
+%description memcached
+Adds support for rlm_memcached as a cache driver.
+%endif
+
+%package config
+Group: System Environment/Daemons
+Summary: FreeRADIUS config files
+Provides: freeradius-config
+
+%description config
+FreeRADIUS default config files
+This package should be used as a base for a site local package
+to configure the FreeRADIUS server.
+Requires: make
+Requires: util-linux
+
+%package utils
+Group: System Environment/Daemons
+Summary: FreeRADIUS utilities
+Requires: %{name} = %{version}-%{release}
+Requires: libpcap >= 0.9.4
+
+%description utils
+The FreeRADIUS server has a number of features found in other servers,
+and additional features not found in any other server. Rather than
+doing a feature by feature comparison, we will simply list the features
+of the server, and let you decide if they satisfy your needs.
+
+Support for RFC and VSA Attributes Additional server configuration
+attributes Selecting a particular configuration Authentication methods
+
+%package perl-util
+Group: System Environment/Daemons
+Summary: FreeRADIUS Perl utilities
+Requires: perl-Net-IP
+
+%description perl-util
+This package provides Perl utilities for managing IP pools stored in
+SQL databases.
+
+%if %{!?_without_ldap:1}%{?_without_ldap:0}
+%package ldap
+Summary: LDAP support for FreeRADIUS
+Group: System Environment/Daemons
+Requires: %{name} = %{version}-%{release}
+%if 0%{?rhel} <= 8
+Requires: openldap-ltb, cyrus-sasl
+BuildRequires: openldap-ltb, cyrus-sasl-devel
+%endif
+%if 0%{?rhel} >= 9
+Requires: openldap, cyrus-sasl
+BuildRequires: openldap-devel, cyrus-sasl-devel
+%endif
+
+%description ldap
+This plugin provides LDAP support for the FreeRADIUS server project.
+%endif
+
+%package krb5
+Summary: Kerberos 5 support for FreeRADIUS
+Group: System Environment/Daemons
+Requires: %{name} = %{version}-%{release}
+Requires: krb5-libs
+BuildRequires: krb5-devel
+
+%description krb5
+This plugin provides Kerberos 5 support for the FreeRADIUS server project.
+
+%package perl
+Summary: Perl support for FreeRADIUS
+Group: System Environment/Daemons
+Requires: %{name} = %{version}-%{release}
+Requires: perl(:MODULE_COMPAT_%(eval "`%{__perl} -V:version`"; echo $version))
+%{?fedora:BuildRequires: perl-devel}
+%if 0%{?rhel} <= 5
+BuildRequires: perl
+%endif
+%if 0%{?rhel} >= 6
+BuildRequires: perl-devel
+%endif
+BuildRequires: perl(ExtUtils::Embed)
+
+%description perl
+This plugin provides Perl support for the FreeRADIUS server project.
+
+%if %{?el6:0}%{!?el6:1}
+%package python
+Summary: Python support for FreeRADIUS
+Group: System Environment/Daemons
+Requires: %{name} = %{version}-%{release}
+%{?fedora:Requires: python2}
+%{?fedora:BuildRequires: python2-devel}
+%if 0%{?rhel} <= 7
+Requires: python
+BuildRequires: python-devel
+%endif
+%if 0%{?rhel} == 8
+Requires: python2
+Requires: python3
+BuildRequires: python2-devel
+BuildRequires: python3-devel
+%endif
+%if 0%{?rhel} >= 9
+Requires: python3
+BuildRequires: python3-devel
+%endif
+
+%description python
+This plugin provides Python support for the FreeRADIUS server project.
+%endif
+
+%package mysql
+Summary: MySQL support for FreeRADIUS
+Group: System Environment/Daemons
+Requires: %{name} = %{version}-%{release}
+%if 0%{?rhel} <= 7
+Requires: mysql
+%endif
+%if 0%{?rhel} >= 8
+Requires: mysql-libs
+%endif
+BuildRequires: mysql-devel
+
+%description mysql
+This plugin provides MySQL support for the FreeRADIUS server project.
+
+%package postgresql
+Summary: PostgreSQL support for FreeRADIUS
+Group: System Environment/Daemons
+Requires: %{name} = %{version}-%{release}
+Requires: postgresql
+BuildRequires: postgresql-devel
+
+%description postgresql
+This plugin provides PostgreSQL support for the FreeRADIUS server project.
+
+%package sqlite
+Summary: SQLite support for FreeRADIUS
+Group: System Environment/Daemons
+Requires: %{name} = %{version}-%{release}
+Requires: sqlite
+BuildRequires: sqlite-devel
+
+%description sqlite
+This plugin provides SQLite support for the FreeRADIUS server project.
+
+%package unixODBC
+Summary: unixODBC support for FreeRADIUS
+Group: System Environment/Daemons
+Requires: %{name} = %{version}-%{release}
+Requires: unixODBC
+BuildRequires: unixODBC-devel
+
+%description unixODBC
+This plugin provides unixODBC support for the FreeRADIUS server project.
+
+%package freetds
+Summary: FreeTDS support for FreeRADIUS
+Group: System Environment/Daemons
+Requires: %{name} = %{version}-%{release}
+Requires: freetds
+BuildRequires: freetds-devel
+
+%description freetds
+This plugin provides FreeTDS support for the FreeRADIUS server project.
+
+%if %{?_with_rlm_sql_oracle:1}%{!?_with_rlm_sql_oracle:0}
+%package oracle
+Summary: Oracle support for FreeRADIUS
+Group: System Environment/Daemons
+Requires: %{name} = %{version}-%{release}
+Requires: oracle-instantclient11.2
+BuildRequires: oracle-instantclient11.2-devel
+
+%description oracle
+This plugin provides Oracle support for the FreeRADIUS server project.
+
+%ifarch x86_64
+%global oracle_include_dir /usr/include/oracle/11.2/client64
+%global oracle_lib_dir %{_prefix}/lib/oracle/11.2/client64/lib
+%endif
+%ifarch i386
+%global oracle_include_dir /usr/include/oracle/11.2/client
+%global oracle_lib_dir %{_prefix}/lib/oracle/11.2/client/lib
+%endif
+%endif
+
+%if %{?el6:0}%{!?el6:1}
+%package redis
+Summary: Redis support for FreeRADIUS
+Group: System Environment/Daemons
+Requires: %{name} = %{version}-%{release}
+Requires: hiredis
+BuildRequires: hiredis-devel
+
+%description redis
+This plugin provides Redis support for the FreeRADIUS server project.
+%endif
+
+%package rest
+Summary: REST and JSON support for FreeRADIUS
+Group: System Environment/Daemons
+Requires: %{name} = %{version}-%{release}
+Requires: json-c >= 0.10
+BuildRequires: json-c-devel >= 0.10
+
+%description rest
+This plugin provides REST support for the FreeRADIUS server project.
+
+%if %{?_with_rlm_ruby:1}%{!?_with_rlm_ruby:0}
+%package ruby
+Summary: Ruby support for FreeRADIUS
+Group: System Environment/Daemons
+Requires: %{name} = %{version}-%{release}
+Requires: ruby
+BuildRequires: ruby ruby-devel
+
+%description ruby
+This plugin provides Ruby support for the FreeRADIUS server project.
+%endif
+
+%package unbound
+Summary: Unbound DNS support for FreeRADIUS
+Group: System Environment/Daemons
+Requires: %{name} = %{version}-%{release}
+Requires: unbound
+BuildRequires: unbound-devel
+
+%description unbound
+This plugin provides unbound DNS support for the FreeRADIUS server project.
+
+%if %{?_with_rlm_yubikey:1}%{!?_with_rlm_yubikey:0}
+%package yubikey
+Summary: YubiCloud support for FreeRADIUS
+Group: System Environment/Daemons
+Requires: %{name} = %{version}-%{release}
+Requires: ykclient >= 2.10
+BuildRequires: ykclient-devel >= 2.10
+
+%description yubikey
+This plugin provides YubiCloud support for the FreeRADIUS server project.
+%endif
+
+
+%prep
+%setup -q -n freeradius-server-%{version}
+# Some source files mistakenly have execute permissions set
+find $RPM_BUILD_DIR/freeradius-server-%{version} \( -name '*.c' -o -name '*.h' \) -a -perm /0111 -exec chmod a-x {} +
+
+
+%build
+# Retain CFLAGS from the environment...
+%if %{?_with_developer:1}%{!?_with_developer:0}
+export CFLAGS="$CFLAGS -fpic"
+export CXXFLAGS="$CFLAGS"
+%endif
+
+# Need to pass these explicitly for clang, else rpmbuilder bails when trying to extract debug info from
+# the libraries. Guessing GCC does this by default. Why use clang over gcc? The version of clang
+# which ships with RHEL 6 has basic C11 support, gcc doesn't.
+export LDFLAGS="-Wl,--build-id"
+
+%configure \
+ --libdir=%{_libdir}/freeradius \
+ --sysconfdir=%{_sysconfdir} \
+ --disable-ltdl-install \
+ --with-gnu-ld \
+ --with-threads \
+ --with-thread-pool \
+ --with-docdir=%{docdir} \
+%if %{!?_without_ldap:1}%{?_without_ldap:0}
+ --with-rlm-ldap-include-dir=/usr/local/openldap/include \
+ --with-rlm-ldap-lib-dir=/usr/local/openldap/lib64 \
+%endif
+ --with-rlm-sql_postgresql-include-dir=/usr/include/pgsql \
+ --with-rlm-sql-postgresql-lib-dir=%{_libdir} \
+ --with-rlm-sql_mysql-include-dir=/usr/include/mysql \
+ --with-mysql-lib-dir=%{_libdir}/mysql \
+ --with-unixodbc-lib-dir=%{_libdir} \
+ --with-rlm-dbm-lib-dir=%{_libdir} \
+ --with-rlm-krb5-include-dir=/usr/kerberos/include \
+ --without-rlm_eap_ikev2 \
+ --without-rlm_sql_iodbc \
+ --without-rlm_sql_firebird \
+ --without-rlm_sql_db2 \
+ --without-rlm_sql_mongo \
+ --with-jsonc-lib-dir=%{_libdir} \
+ --with-jsonc-include-dir=/usr/include/json \
+ --with-winbind-include-dir=/usr/include/samba-4.0 \
+ --with-winbind-lib-dir=/usr/lib64/samba \
+ --with-systemd \
+ %{?_with_rlm_yubikey} \
+ %{?_without_rlm_yubikey} \
+ %{?_with_rlm_sql_oracle} \
+ %{?_with_rlm_sql_oracle: --with-oracle-include-dir=%{oracle_include_dir}} \
+ %{?_with_rlm_sql_oracle: --with-oracle-lib-dir=%{oracle_lib_dir}} \
+ %{?_without_rlm_sql_oracle} \
+ %{?_with_experimental_modules} \
+ %{?_without_experimental_modules} \
+ %{?_without_rlm_eap_pwd} \
+ %{?_without_rlm_eap_tnc} \
+ %{?_with_rlm_idn} \
+ %{?_without_rlm_idn} \
+ %{?_with_rlm_opendirectory} \
+ %{?_without_rlm_opendirectory} \
+ %{?_with_rlm_securid} \
+ %{?_without_rlm_securid} \
+ %{?_with_rlm_ruby} \
+ %{?_without_rlm_ruby} \
+ %{?_with_rlm_cache_memcached} \
+ %{?_without_rlm_cache_memcached} \
+ %{?_without_libwbclient} \
+ %{?_without_libfreeradius_ldap} \
+# --with-modules="rlm_wimax" \
+
+make %_smp_mflags
+
+%install
+rm -rf $RPM_BUILD_ROOT
+mkdir -p $RPM_BUILD_ROOT/var/run/radiusd
+mkdir -p $RPM_BUILD_ROOT/var/lib/radiusd
+make install R=$RPM_BUILD_ROOT
+# modify default configuration
+RADDB=$RPM_BUILD_ROOT%{_sysconfdir}/raddb
+perl -i -pe 's/^#user =.*$/user = radiusd/' $RADDB/radiusd.conf
+perl -i -pe 's/^#group =.*$/group = radiusd/' $RADDB/radiusd.conf
+# logs
+mkdir -p $RPM_BUILD_ROOT/var/log/radius/radacct
+touch $RPM_BUILD_ROOT/var/log/radius/{radutmp,radius.log}
+install -m 755 scripts/raduat $RPM_BUILD_ROOT/%{_bindir}/raduat
+
+# For systemd based systems, that define _unitdir, install the radiusd unit
+%if %{?_unitdir:1}%{!?_unitdir:0}
+install -D -m 755 redhat/radiusd.service $RPM_BUILD_ROOT/%{_unitdir}/radiusd.service
+install -D -m 644 %{SOURCE104} $RPM_BUILD_ROOT/%{_prefix}/lib/tmpfiles.d/radiusd.conf
+# For SystemV install the init script
+%else
+install -D -m 755 redhat/freeradius-radiusd-init $RPM_BUILD_ROOT/%{initddir}/radiusd
+%endif
+
+install -D -m 644 redhat/freeradius-logrotate $RPM_BUILD_ROOT/%{_sysconfdir}/logrotate.d/radiusd
+install -D -m 644 redhat/freeradius-pam-conf $RPM_BUILD_ROOT/%{_sysconfdir}/pam.d/radiusd
+
+# remove unneeded stuff
+rm -rf doc/00-OLD
+rm -f $RPM_BUILD_ROOT/usr/sbin/rc.radiusd
+rm -rf $RPM_BUILD_ROOT/%{_libdir}/freeradius/*.a
+rm -rf $RPM_BUILD_ROOT/%{_libdir}/freeradius/*.la
+%if %{?_with_rlm_idn:0}%{!?_with_rlm_idn:1}
+# Does not delete file. Why?
+rm -f $RPM_BUILD_ROOT/%{_mandir}/man5/rlm_idn.5.gz
+rm -f $RPM_BUILD_ROOT/%{_sysconfdir}/raddb/mods-available/idn
+%endif
+%if %{?_with_rlm_ruby:0}%{!?_with_rlm_ruby:1}
+rm -rf $RPM_BUILD_ROOT/%{_sysconfdir}/raddb/mods-config/ruby
+%endif
+%if %{?_with_rlm_sql_oracle:0}%{!?_with_rlm_sql_oracle:1}
+rm -rf $RPM_BUILD_ROOT/%{_sysconfdir}/raddb/mods-config/sql/dhcp/oracle
+rm -rf $RPM_BUILD_ROOT/%{_sysconfdir}/raddb/mods-config/sql/ippool/oracle
+rm -rf $RPM_BUILD_ROOT/%{_sysconfdir}/raddb/mods-config/sql/ippool-dhcp/oracle
+rm -rf $RPM_BUILD_ROOT/%{_sysconfdir}/raddb/mods-config/sql/main/oracle
+%endif
+rm -rf $RPM_BUILD_ROOT/%{_libdir}/freeradius/rlm_test.so
+# remove header files, we don't ship a devel package and the
+# headers have multilib conflicts
+rm -rf $RPM_BUILD_ROOT/%{_includedir}
+
+# remove unsupported config files
+rm -f $RPM_BUILD_ROOT/%{_sysconfdir}/raddb/experimental.conf
+rm -rf $RPM_BUILD_ROOT/%{_sysconfdir}/raddb/mods-config/sql/ippool/mongo
+rm -rf $RPM_BUILD_ROOT/%{_sysconfdir}/raddb/mods-config/sql/main/mongo
+
+# install doc files omitted by standard install
+for f in COPYRIGHT CREDITS INSTALL.rst README.rst; do
+ cp $f $RPM_BUILD_ROOT/%{docdir}
+done
+cp LICENSE $RPM_BUILD_ROOT/%{docdir}/LICENSE.gpl
+cp src/lib/LICENSE $RPM_BUILD_ROOT/%{docdir}/LICENSE.lgpl
+cp src/LICENSE.openssl $RPM_BUILD_ROOT/%{docdir}/LICENSE.openssl
+
+# add Red Hat specific documentation
+cat >> $RPM_BUILD_ROOT/%{docdir}/REDHAT << EOF
+
+Red Hat, RHEL, Fedora, and CentOS specific information can be found on the
+FreeRADIUS Wiki in the Red Hat FAQ.
+
+http://wiki.freeradius.org/guide/Red_Hat_FAQ
+
+Please reference that document.
+
+EOF
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+
+# Make sure our user/group is present prior to any package or subpackage installation
+%pre
+getent group radiusd >/dev/null || /usr/sbin/groupadd -r -g 95 radiusd
+getent passwd radiusd >/dev/null || /usr/sbin/useradd -r -g radiusd -u 95 -c "radiusd user" -s /sbin/nologin radiusd > /dev/null 2>&1
+exit 0
+
+# Make sure our user/group is present prior to any package or subpackage installation
+%pre config
+getent group radiusd >/dev/null || /usr/sbin/groupadd -r -g 95 radiusd
+getent passwd radiusd >/dev/null || /usr/sbin/useradd -r -g radiusd -u 95 -c "radiusd user" -s /sbin/nologin radiusd > /dev/null 2>&1
+exit 0
+
+
+%post
+if [ $1 = 1 ]; then
+%if %{?_unitdir:1}%{!?_unitdir:0}
+ /bin/systemctl enable radiusd.service
+%else
+ /sbin/chkconfig --add radiusd
+%endif
+fi
+
+%post config
+if [ $1 = 1 ]; then
+ if [ ! -e %{_sysconfdir}/raddb/certs/server.pem ]; then
+ /sbin/runuser -g radiusd -c 'umask 007; %{_sysconfdir}/raddb/certs/bootstrap' > /dev/null 2>&1 || :
+ fi
+fi
+
+
+%preun
+if [ $1 = 0 ]; then
+%if %{?_unitdir:1}%{!?_unitdir:0}
+ /bin/systemctl stop radiusd.service || :
+ /bin/systemctl disable radiusd.service || :
+%else
+ /sbin/chkconfig --del radiusd
+%endif
+fi
+
+%postun
+if [ $1 -ge 1 ]; then
+ /sbin/service radiusd condrestart >/dev/null 2>&1 || :
+fi
+
+
+%files
+%defattr(-,root,root)
+%doc %{docdir}/
+%config(noreplace) %{_sysconfdir}/pam.d/radiusd
+%config(noreplace) %{_sysconfdir}/logrotate.d/radiusd
+
+%if %{?_unitdir:1}%{!?_unitdir:0}
+%{_unitdir}/radiusd.service
+%config(noreplace) %{_prefix}/lib/tmpfiles.d/radiusd.conf
+%else
+%{initddir}/radiusd
+%endif
+
+%dir %attr(755,radiusd,radiusd) /var/lib/radiusd
+%dir %attr(755,radiusd,radiusd) /var/run/radiusd/
+# binaries
+%defattr(-,root,root)
+/usr/sbin/checkrad
+/usr/sbin/raddebug
+/usr/sbin/radiusd
+/usr/sbin/radmin
+# man-pages
+%doc %{_mandir}/man1/smbencrypt.1.gz
+%doc %{_mandir}/man5/checkrad.5.gz
+%doc %{_mandir}/man5/clients.conf.5.gz
+%doc %{_mandir}/man5/dictionary.5.gz
+%doc %{_mandir}/man5/radiusd.conf.5.gz
+%doc %{_mandir}/man5/radrelay.conf.5.gz
+%doc %{_mandir}/man5/rlm_always.5.gz
+%doc %{_mandir}/man5/rlm_attr_filter.5.gz
+%doc %{_mandir}/man5/rlm_chap.5.gz
+%doc %{_mandir}/man5/rlm_counter.5.gz
+%doc %{_mandir}/man5/rlm_detail.5.gz
+%doc %{_mandir}/man5/rlm_digest.5.gz
+%doc %{_mandir}/man5/rlm_expr.5.gz
+%doc %{_mandir}/man5/rlm_files.5.gz
+%doc %{_mandir}/man5/rlm_idn.5.gz
+# %%{?_with_rlm_idn: %doc %{_mandir}/man5/rlm_idn.5.gz}
+%doc %{_mandir}/man5/rlm_mschap.5.gz
+%doc %{_mandir}/man5/rlm_pap.5.gz
+%doc %{_mandir}/man5/rlm_passwd.5.gz
+%doc %{_mandir}/man5/rlm_realm.5.gz
+%doc %{_mandir}/man5/rlm_sql.5.gz
+%doc %{_mandir}/man5/rlm_unbound.5.gz
+%doc %{_mandir}/man5/rlm_unix.5.gz
+%doc %{_mandir}/man5/unlang.5.gz
+%doc %{_mandir}/man5/users.5.gz
+%doc %{_mandir}/man8/radcrypt.8.gz
+%doc %{_mandir}/man8/raddebug.8.gz
+%doc %{_mandir}/man8/radiusd.8.gz
+%doc %{_mandir}/man8/radmin.8.gz
+%doc %{_mandir}/man8/radrelay.8.gz
+%doc %{_mandir}/man8/radsniff.8.gz
+# dictionaries
+%dir %attr(755,root,root) /usr/share/freeradius
+/usr/share/freeradius/*
+# logs
+%dir %attr(700,radiusd,radiusd) /var/log/radius/
+%dir %attr(700,radiusd,radiusd) /var/log/radius/radacct/
+%ghost %attr(644,radiusd,radiusd) /var/log/radius/radutmp
+%ghost %attr(600,radiusd,radiusd) /var/log/radius/radius.log
+# RADIUS shared libs
+%attr(755,root,root) %{_libdir}/freeradius/lib*.so*
+# RADIUS Loadable Modules
+%dir %attr(755,root,root) %{_libdir}/freeradius
+%{_libdir}/freeradius/proto_dhcp.so
+%{_libdir}/freeradius/proto_vmps.so
+%{_libdir}/freeradius/rlm_always.so
+%{_libdir}/freeradius/rlm_attr_filter.so
+%{_libdir}/freeradius/rlm_cache.so
+%{_libdir}/freeradius/rlm_cache_rbtree.so
+%{_libdir}/freeradius/rlm_chap.so
+%{_libdir}/freeradius/rlm_counter.so
+%{_libdir}/freeradius/rlm_date.so
+%{_libdir}/freeradius/rlm_detail.so
+%{_libdir}/freeradius/rlm_dhcp.so
+%{_libdir}/freeradius/rlm_digest.so
+%{_libdir}/freeradius/rlm_dynamic_clients.so
+%{_libdir}/freeradius/rlm_eap.so
+%{_libdir}/freeradius/rlm_eap_fast.so
+%{_libdir}/freeradius/rlm_eap_gtc.so
+%{_libdir}/freeradius/rlm_eap_md5.so
+%{_libdir}/freeradius/rlm_eap_mschapv2.so
+%{_libdir}/freeradius/rlm_eap_peap.so
+%{_libdir}/freeradius/rlm_eap_sim.so
+%{_libdir}/freeradius/rlm_eap_tls.so
+%{_libdir}/freeradius/rlm_eap_ttls.so
+%{_libdir}/freeradius/rlm_exec.so
+%{_libdir}/freeradius/rlm_expiration.so
+%{_libdir}/freeradius/rlm_expr.so
+%{_libdir}/freeradius/rlm_files.so
+%{_libdir}/freeradius/rlm_ippool.so
+%{_libdir}/freeradius/rlm_linelog.so
+%{_libdir}/freeradius/rlm_logintime.so
+%{_libdir}/freeradius/rlm_mschap.so
+%{_libdir}/freeradius/rlm_pam.so
+%{_libdir}/freeradius/rlm_pap.so
+%{_libdir}/freeradius/rlm_passwd.so
+%{_libdir}/freeradius/rlm_preprocess.so
+%{_libdir}/freeradius/rlm_radutmp.so
+%{_libdir}/freeradius/rlm_realm.so
+%{_libdir}/freeradius/rlm_replicate.so
+%{_libdir}/freeradius/rlm_soh.so
+%{_libdir}/freeradius/rlm_sometimes.so
+%{_libdir}/freeradius/rlm_sql.so
+%{_libdir}/freeradius/rlm_sql_null.so
+%{_libdir}/freeradius/rlm_sql_sqlite.so
+%{_libdir}/freeradius/rlm_sqlcounter.so
+%{_libdir}/freeradius/rlm_sqlippool.so
+%{_libdir}/freeradius/rlm_sql_map.so
+
+%{_libdir}/freeradius/rlm_totp.so
+%{_libdir}/freeradius/rlm_unpack.so
+%{_libdir}/freeradius/rlm_unix.so
+%{_libdir}/freeradius/rlm_utf8.so
+%{_libdir}/freeradius/rlm_wimax.so
+%{?_with_rlm_idn: %{_libdir}/freeradius/rlm_idn.so}
+%if %{?_with_experimental_modules:1}%{!?_with_experimental_modules:0}
+%{_libdir}/freeradius/rlm_example.so
+%{_libdir}/freeradius/rlm_smsotp.so
+%endif
+
+%files config
+%dir %attr(755,root,radiusd) %{_sysconfdir}/raddb
+%defattr(-,root,radiusd)
+%attr(644,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/dictionary
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/clients.conf
+%config(noreplace) %{_sysconfdir}/raddb/hints
+%config(noreplace) %{_sysconfdir}/raddb/huntgroups
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/panic.gdb
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/README.rst
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/proxy.conf
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/radiusd.conf
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/trigger.conf
+%config(noreplace) %{_sysconfdir}/raddb/users
+%dir %attr(770,root,radiusd) %{_sysconfdir}/raddb/certs
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/certs/*
+%attr(750,root,radiusd) %{_sysconfdir}/raddb/certs/bootstrap
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/sites-available
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/sites-available/*
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/sites-enabled
+%config(noreplace) %{_sysconfdir}/raddb/sites-enabled/*
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/policy.d
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/policy.d/*
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/templates.conf
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-available
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/mods-available/*
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/mods-config/README.rst
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/attr_filter
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/mods-config/attr_filter/*
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/files
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/mods-config/files/*
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/perl
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/mods-config/perl/*
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/preprocess
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/mods-config/preprocess/*
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/unbound
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/mods-config/unbound/*
+%if %{?el6:0}%{!?el6:1}
+%if 0%{?rhel} <= 8
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/python
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/mods-config/python/*
+%endif
+%if 0%{?rhel} >= 8
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/python3
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/mods-config/python3/*
+%endif
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/realm
+%attr(-,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/mods-config/realm/*
+%endif
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-enabled
+%config(noreplace) %{_sysconfdir}/raddb/mods-enabled/*
+# ruby
+%if %{?_with_rlm_ruby:1}%{!?_with_rlm_ruby:0}
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/ruby
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/mods-config/ruby/*
+%endif
+#
+# sql - general
+#
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/sql
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/sql/counter
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/sql/cui
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/sql/dhcp
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/sql/ippool
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/sql/ippool-dhcp
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/sql/main
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/sql/moonshot-targeted-ids
+#
+# mysql
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/sql/counter/mysql
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/mods-config/sql/counter/mysql/*
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/sql/cui/mysql
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/mods-config/sql/cui/mysql/*
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/sql/dhcp/mysql
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/mods-config/sql/dhcp/mysql/*
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/sql/ippool/mysql
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/mods-config/sql/ippool/mysql/*
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/sql/ippool-dhcp/mysql
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/mods-config/sql/ippool-dhcp/mysql/*
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/sql/main/mysql
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/mods-config/sql/main/mysql/*
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/sql/main/mysql/extras
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/sql/main/mysql/extras/wimax
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/mods-config/sql/main/mysql/extras/wimax/*
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/sql/main/ndb
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/mods-config/sql/main/ndb/*
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/sql/moonshot-targeted-ids/mysql
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/mods-config/sql/moonshot-targeted-ids/mysql/*
+#
+# postgres
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/sql/counter/postgresql
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/mods-config/sql/counter/postgresql/*
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/sql/cui/postgresql
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/mods-config/sql/cui/postgresql/*
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/sql/dhcp/postgresql
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/mods-config/sql/dhcp/postgresql/*
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/sql/ippool/postgresql
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/mods-config/sql/ippool/postgresql/*
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/sql/ippool-dhcp/postgresql
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/mods-config/sql/ippool-dhcp/postgresql/*
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/sql/main/postgresql
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/mods-config/sql/main/postgresql/*
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/sql/main/postgresql/extras
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/mods-config/sql/main/postgresql/extras/*
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/sql/moonshot-targeted-ids/postgresql
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/mods-config/sql/moonshot-targeted-ids/postgresql/*
+#
+# sqlite
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/sql/counter/sqlite
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/mods-config/sql/counter/sqlite/*
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/sql/cui/sqlite
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/mods-config/sql/cui/sqlite/*
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/sql/dhcp/sqlite
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/mods-config/sql/dhcp/sqlite/*
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/sql/ippool/sqlite
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/mods-config/sql/ippool/sqlite/*
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/sql/ippool-dhcp/sqlite
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/mods-config/sql/ippool-dhcp/sqlite/*
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/sql/main/sqlite
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/mods-config/sql/main/sqlite/*
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/sql/moonshot-targeted-ids/sqlite
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/mods-config/sql/moonshot-targeted-ids/sqlite/*
+#
+# freetds
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/sql/dhcp/mssql
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/mods-config/sql/dhcp/mssql/*
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/sql/ippool/mssql
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/mods-config/sql/ippool/mssql/*
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/sql/ippool-dhcp/mssql
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/mods-config/sql/ippool-dhcp/mssql/*
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/sql/main/mssql
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/mods-config/sql/main/mssql/*
+#
+# oracle
+%if %{?_with_rlm_sql_oracle:1}%{!?_with_rlm_sql_oracle:0}
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/sql/dhcp/oracle
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/mods-config/sql/dhcp/oracle/*
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/sql/ippool/oracle
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/mods-config/sql/ippool/oracle/*
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/sql/ippool-dhcp/oracle
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/mods-config/sql/ippool-dhcp/oracle/*
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb/mods-config/sql/main/oracle
+%attr(640,root,radiusd) %config(noreplace) %{_sysconfdir}/raddb/mods-config/sql/main/oracle/*
+%endif
+
+%files utils
+%defattr(-,root,root)
+/usr/bin/dhcpclient
+/usr/bin/map_unit
+/usr/bin/rad_counter
+/usr/bin/radattr
+/usr/bin/radclient
+/usr/bin/radcrypt
+/usr/bin/radeapclient
+/usr/bin/radlast
+/usr/bin/radtest
+/usr/bin/radsniff
+/usr/bin/radsqlrelay
+/usr/bin/raduat
+/usr/bin/radwho
+/usr/bin/radzap
+/usr/bin/rlm_ippool_tool
+/usr/bin/smbencrypt
+# man-pages
+%doc %{_mandir}/man1/dhcpclient.1.gz
+%doc %{_mandir}/man1/rad_counter.1.gz
+%doc %{_mandir}/man1/radclient.1.gz
+%doc %{_mandir}/man1/radeapclient.1.gz
+%doc %{_mandir}/man1/radlast.1.gz
+%doc %{_mandir}/man8/radsqlrelay.8.gz
+%doc %{_mandir}/man1/radtest.1.gz
+%doc %{_mandir}/man1/radwho.1.gz
+%doc %{_mandir}/man1/radzap.1.gz
+%doc %{_mandir}/man8/rlm_ippool_tool.8.gz
+
+%files perl-util
+%defattr(-,root,root)
+/usr/bin/rlm_sqlippool_tool
+#man-pages
+%doc %{_mandir}/man8/rlm_sqlippool_tool.8.gz
+
+%if %{?_with_rlm_cache_memcached:1}%{!?_with_rlm_cache_memcached:0}
+%files memcached
+%defattr(-,root,root)
+%{_libdir}/freeradius/rlm_cache_memcached.so
+%endif
+
+%files krb5
+%defattr(-,root,root)
+%{_libdir}/freeradius/rlm_krb5.so
+
+%files perl
+%defattr(-,root,root)
+%{_libdir}/freeradius/rlm_perl.so
+
+%if %{?el6:0}%{!?el6:1}
+%files python
+%defattr(-,root,root)
+%if 0%{?rhel} <= 8
+%{_libdir}/freeradius/rlm_python.so
+%endif
+%if 0%{?rhel} >= 8
+%{_libdir}/freeradius/rlm_python3.so
+%endif
+%endif
+
+%files mysql
+%defattr(-,root,root)
+%{_libdir}/freeradius/rlm_sql_mysql.so
+
+%files postgresql
+%defattr(-,root,root)
+%{_libdir}/freeradius/rlm_sql_postgresql.so
+
+%files sqlite
+%defattr(-,root,root)
+%{_libdir}/freeradius/rlm_sql_sqlite.so
+
+%if %{!?_without_ldap:1}%{?_without_ldap:0}
+%files ldap
+%defattr(-,root,root)
+%{_libdir}/freeradius/rlm_ldap.so
+%endif
+
+%files unixODBC
+%defattr(-,root,root)
+%{_libdir}/freeradius/rlm_sql_unixodbc.so
+
+%if %{?el6:0}%{!?el6:1}
+%files redis
+%defattr(-,root,root)
+%{_libdir}/freeradius/rlm_redis.so
+%{_libdir}/freeradius/rlm_rediswho.so
+%{_libdir}/freeradius/rlm_cache_redis.so
+%endif
+
+%files rest
+%defattr(-,root,root)
+%{_libdir}/freeradius/rlm_rest.so
+%{_libdir}/freeradius/rlm_json.so
+
+%if %{?_with_rlm_ruby:1}%{!?_with_rlm_ruby:0}
+%files ruby
+%defattr(-,root,root)
+%{_libdir}/freeradius/rlm_ruby.so
+%endif
+
+%files freetds
+%defattr(-,root,root)
+%{_libdir}/freeradius/rlm_sql_freetds.so
+
+%if %{?_with_rlm_sql_oracle:1}%{!?_with_rlm_sql_oracle:0}
+%files oracle
+%defattr(-,root,root)
+%{_libdir}/freeradius/rlm_sql_oracle.so
+%endif
+
+%files unbound
+%defattr(-,root,root)
+%{_libdir}/freeradius/rlm_unbound.so
+
+%if %{?_with_rlm_yubikey:1}%{!?_with_rlm_yubikey:0}
+%files yubikey
+%defattr(-,root,root)
+%{_libdir}/freeradius/rlm_yubikey.so
+%endif
+
+%changelog
+* Wed Sep 25 2013 Alan DeKok <aland@freeradius.org> - 3.0.0
+- upgrade to latest upstream release
diff --git a/redhat/radiusd-pam b/redhat/radiusd-pam
new file mode 100644
index 0000000..a4dd2b5
--- /dev/null
+++ b/redhat/radiusd-pam
@@ -0,0 +1,7 @@
+#%PAM-1.0
+auth required /lib/security/pam_unix_auth.so shadow nullok
+auth required /lib/security/pam_nologin.so
+account required /lib/security/pam_unix_acct.so
+password required /lib/security/pam_cracklib.so
+password required /lib/security/pam_unix_password.so shadow nullok use_authtok
+session required /lib/security/pam_unix_session.so
diff --git a/redhat/radiusd.service b/redhat/radiusd.service
new file mode 100644
index 0000000..ebeee95
--- /dev/null
+++ b/redhat/radiusd.service
@@ -0,0 +1,67 @@
+[Unit]
+Description=FreeRADIUS multi-protocol policy server
+After=network-online.target
+Documentation=man:radiusd(8) man:radiusd.conf(5) http://wiki.freeradius.org/ http://networkradius.com/doc/
+
+[Service]
+Type=notify
+WatchdogSec=60
+NotifyAccess=all
+EnvironmentFile=-/etc/sysconfig/radiusd
+
+# FreeRADIUS can do static evaluation of policy language rules based
+# on environmental variables which is very useful for doing per-host
+# customization.
+# Unfortunately systemd does not allow variable substitutions such
+# as %H or $(hostname) in the EnvironmentFile.
+# We provide HOSTNAME here for convenience.
+Environment=HOSTNAME=%H
+
+# Limit memory to 2G this is fine for %99.99 of deployments. FreeRADIUS
+# is not memory hungry, if it's using more than this, then there's probably
+# a leak somewhere.
+MemoryLimit=2G
+
+RuntimeDirectory=radiusd
+RuntimeDirectoryMode=0775
+User=radiusd
+Group=radiusd
+ExecStartPre=/usr/sbin/radiusd $FREERADIUS_OPTIONS -Cx -lstdout
+ExecStart=/usr/sbin/radiusd -f $FREERADIUS_OPTIONS
+Restart=on-failure
+RestartSec=5
+ExecReload=/usr/sbin/radiusd $FREERADIUS_OPTIONS -Cxm -lstdout
+ExecReload=/bin/kill -HUP $MAINPID
+
+# Don't elevate privileges after starting
+NoNewPrivileges=true
+
+# Allow binding to secure ports, broadcast addresses, and raw interfaces.
+#
+# This list of capabilities may not be exhaustive, and needs
+# further testing. Please uncomment, test, and report any issues.
+#CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_BROADCAST CAP_NET_RAW CAP_SETUID CAP_SETGID CAP_CHOWN CAP_DAC_OVERRIDE
+
+# Private /tmp that isn't shared by other processes
+PrivateTmp=true
+
+# cgroups are readable only by radiusd, and child processes
+ProtectControlGroups=true
+
+# don't load new kernel modules
+ProtectKernelModules=true
+
+# don't tune kernel parameters
+ProtectKernelTunables=true
+
+# Only allow native system calls
+SystemCallArchitectures=native
+
+# We shouldn't be writing to the configuration directory
+ReadOnlyDirectories=/etc/raddb/
+
+# We can read and write to the log directory.
+ReadWriteDirectories=/var/log/radius/
+
+[Install]
+WantedBy=multi-user.target
diff --git a/scripts/.gitignore b/scripts/.gitignore
new file mode 100644
index 0000000..3c72551
--- /dev/null
+++ b/scripts/.gitignore
@@ -0,0 +1,8 @@
+check-radiusd-config
+cryptpasswd
+radiusd.cron.daily
+radiusd.cron.monthly
+radwatch
+rc.radiusd
+radcrypt
+jlibtool
diff --git a/scripts/Ssha2Passwd b/scripts/Ssha2Passwd
new file mode 100755
index 0000000..65c23a4
--- /dev/null
+++ b/scripts/Ssha2Passwd
@@ -0,0 +1,144 @@
+#!/usr/bin/perl -w
+use strict;
+use Getopt::Long qw(:config no_ignore_case);
+use Pod::Usage;
+use Digest::SHA;
+use MIME::Base64;
+use Math::Random::Secure qw(irand);
+
+my %opts;
+GetOptions(\%opts,
+ qw[ help|?! man! f|format=s l|len=i s|salt=s S|Salt=s z|saltlen:i ]
+) or pod2usage(2);
+pod2usage(1) if $opts{help};
+pod2usage(-verbose => 2) if $opts{man};
+
+my $len = 256;
+if (exists $opts{l}) {
+ my @length = (224, 256, 384, 512);
+ if (grep {$_ eq $opts{l}} @length) {
+ $len = $opts{l};
+ } else {
+ print "Bad length\n";
+ exit(1);
+ }
+}
+
+sub fmt_base64 {
+ return encode_base64(shift, '')."\n";
+}
+
+sub fmt_hex {
+ return unpack('H*', shift)."\n";
+}
+
+sub fmt_bin {
+ return shift;
+}
+
+my $fmt = \&{'fmt_base64'};
+if (exists $opts{f}) {
+ my %format = ('m' => \&{'fmt_base64'}, 'base64' => \&{'fmt_base64'},
+ 'x' => \&{'fmt_hex'}, 'hex' => \&{'fmt_hex'},
+ 'b' => \&{'fmt_bin'}, 'bin' => \&{'fmt_bin'});
+ $fmt = $format{$opts{f}};
+ if (!defined $fmt) {
+ print "Bad format\n";
+ exit(1);
+ }
+}
+
+my $password = $ARGV[0];
+if (!defined $password) {
+ print "Missing password\n";
+ exit(1);
+}
+
+my $salt = $opts{s};
+if (exists $opts{S}) {
+ if (defined $salt) {
+ print "Redundant salt\n";
+ exit(1);
+ }
+ $salt = pack('H*', $opts{S});
+} elsif (!defined $salt and exists $opts{z}) {
+ my $ssiz = $opts{z};
+ if ($ssiz == 0) {
+ $ssiz = 8;
+ } elsif ($ssiz < 0) {
+ print "Bad salt length\n";
+ exit(1);
+ }
+ while ($ssiz >= 4) {
+ $salt .= pack('N', irand());
+ $ssiz -= 4;
+ }
+ $salt .= substr(pack('N', irand()), 1, $ssiz) if ($ssiz > 0);
+}
+
+my $ctx = Digest::SHA->new($len);
+$ctx->add($password);
+$ctx->add($salt) if (defined $salt);
+my $dig = $ctx->digest;
+$dig .= $salt if (defined $salt);
+
+print &$fmt($dig);
+
+__END__
+
+=head1 NAME
+
+ssha2passwd - Generate a SHA2 hashed password
+
+=head1 DESCRIPTION
+
+Hash the given password into a SHA2 digest with optional salt.
+
+=head1 SYNOPSIS
+
+ ssha2passwd [options] <password>
+
+=head1 OPTIONS
+
+=over
+
+=item B<-f> or B<-format> <format>
+
+Format options:
+
+=over
+
+=item B<m> or B<base64> : base64 encoded (default)
+
+=item B<x> or B<hex> : hexadecimal string
+
+=item B<b> or B<bin> : binary string
+
+=back
+
+=item B<-l> or B<-length> <length>
+
+Hash algorithm bit length (224, 256, 384, or 512 | default: 256).
+
+=item B<-s> or B<-salt> <string>
+
+=item B<-S> or B<-Salt> <hexadecimal string>
+
+Salt string appended to password and hashed. The resultant digest then
+has the salt string appended.
+
+=item B<-z> or B<-saltlen> [<length>]
+
+Byte length of random salt appended to password and hashed, if no salt
+string is explicitly given (0 is default, default: 8).
+
+=item B<-?> or B<-help>
+
+Print a brief help message.
+
+=item B<-man>
+
+Print the manual page.
+
+=back
+=cut
diff --git a/scripts/all.mk b/scripts/all.mk
new file mode 100644
index 0000000..a6e90aa
--- /dev/null
+++ b/scripts/all.mk
@@ -0,0 +1,22 @@
+install: $(R)$(sbindir)/rc.radiusd $(R)$(sbindir)/raddebug \
+ $(R)$(bindir)/radsqlrelay $(R)$(bindir)/radcrypt $(R)$(bindir)/rlm_sqlippool_tool
+
+$(R)$(sbindir)/rc.radiusd: scripts/rc.radiusd
+ @mkdir -p $(dir $@)
+ @$(INSTALL) -m 755 $< $@
+
+$(R)$(sbindir)/raddebug: scripts/raddebug
+ @mkdir -p $(dir $@)
+ @$(INSTALL) -m 755 $< $@
+
+$(R)$(bindir)/radsqlrelay: scripts/sql/radsqlrelay
+ @mkdir -p $(dir $@)
+ @$(INSTALL) -m 755 $< $@
+
+$(R)$(bindir)/radcrypt: scripts/cryptpasswd
+ @mkdir -p $(dir $@)
+ @$(INSTALL) -m 755 $< $@
+
+$(R)$(bindir)/rlm_sqlippool_tool: scripts/sql/rlm_sqlippool_tool
+ @mkdir -p $(dir $@)
+ @$(INSTALL) -m 755 $< $@
diff --git a/scripts/bbedit/unlanglaguage.plist b/scripts/bbedit/unlanglaguage.plist
new file mode 100644
index 0000000..24496f5
--- /dev/null
+++ b/scripts/bbedit/unlanglaguage.plist
@@ -0,0 +1,116 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<!--
+
+ UnlangLanguage.plist
+ A codeless language module for Unlang in BBEdit.
+ Copyright Arran Cudbard-Bell <a.cudbardb@freeradius.org>, 2012.
+
+ This work is licensed under a Creative Commons Attribution-Share Alike 3.0 License.
+ http://creativecommons.org/licenses/by-sa/3.0/
+
+ Version 1.0
+
+-->
+<dict>
+ <key>BBEditDocumentType</key>
+ <string>CodelessLanguageModule</string>
+ <key>BBLMLanguageDisplayName</key>
+ <string>Unlang</string>
+ <key>BBLMLanguageCode</key>
+ <string>unlg</string>
+ <key>BBLMColorsSyntax</key>
+ <true/>
+ <key>BBLMScansFunctions</key>
+ <true/>
+ <key>BBLMIsCaseSensitive</key>
+ <true/>
+ <key>BBLMKeywordList</key>
+ <array>
+ <string>update</string>
+ <string>switch</string>
+ <string>case</string>
+ <string>if</string>
+ <string>else</string>
+ <string>elsif</string>
+ <string>redundant</string>
+ <string>load-balance</string>
+ <string>redundant-load-balance</string>
+ <string>notfound</string>
+ <string>noop</string>
+ <string>ok</string>
+ <string>updated</string>
+ <string>fail</string>
+ <string>userlock</string>
+ <string>invalid</string>
+ <string>handled</string>
+ </array>
+ <key>BBLMSuffixMap</key>
+ <array>
+ <dict>
+ <key>BBLMLanguageSuffix</key>
+ <string>.policy</string>
+ </dict>
+ </array>
+ <key>BBLMCommentLineDefault</key>
+ <string>#</string>
+ <key>Language Features</key>
+ <dict>
+ <key>Identifier and Keyword Character Class</key>
+ <string><![CDATA[0-9A-Z_a-z]]></string>
+
+ <key>Function Pattern</key>
+ <string><![CDATA[(?x:
+ (?x:
+ (?P<leadspace>^\s*)
+ (?P<function>
+ (?P<function_name>[a-zA-Z0-9_-\.]+)
+ \s+{\n
+ (?P<function_body>[^}]+)
+ }
+ )
+ )
+ )]]></string>
+
+ <key>Skip Pattern</key>
+ <string><![CDATA[
+ (?x:
+ (?P>comment) |
+ (?P>string)
+ )]]></string>
+ <key>Open Line Comments</key>
+ <string>#</string>
+
+ <key>Open Statement Blocks</key>
+ <string>{</string>
+
+ <key>Close Statement Blocks</key>
+ <string>}</string>
+
+ <key>Open Strings 1</key>
+ <string>"</string>
+
+ <key>Close Strings 1</key>
+ <string>"</string>
+
+ <key>Escape Char in Strings 1</key>
+ <string>\</string>
+
+ <key>End-of-line Ends Strings 1</key>
+ <true/>
+
+ <key>Open Strings 2</key>
+ <string>'</string>
+
+ <key>Close Strings 2</key>
+ <string>'</string>
+
+ <key>Escape Char in Strings 2</key>
+ <string>\</string>
+
+ <key>End-of-line Ends Strings 2</key>
+ <true/>
+ </dict>
+</dict>
+</plist> \ No newline at end of file
diff --git a/scripts/bin/README.md b/scripts/bin/README.md
new file mode 100644
index 0000000..b7f4b5d
--- /dev/null
+++ b/scripts/bin/README.md
@@ -0,0 +1,9 @@
+# Wrapper scripts for binaries
+
+The build process creates "local" versions of the binaries. These
+binaries can be run out of the source / build tree, and do not need to
+be installed in order to work.
+
+However, the "local" binaries require manual mangling of environment
+variables in order to work. As such, it's easier to just have shell
+script wrappers so people have to remember fewer things.
diff --git a/scripts/bin/gdb b/scripts/bin/gdb
new file mode 100755
index 0000000..c28b814
--- /dev/null
+++ b/scripts/bin/gdb
@@ -0,0 +1,5 @@
+#!/bin/sh
+export PANIC_ACTION=
+export DEBUGGER_ATTACHED=yes
+
+exec ./build//make/jlibtool --mode=execute gdb --args ./build/bin/local/radiusd -sf -xx -l stdout -d ./raddb -D share/ $@
diff --git a/scripts/bin/lldb b/scripts/bin/lldb
new file mode 100755
index 0000000..2634601
--- /dev/null
+++ b/scripts/bin/lldb
@@ -0,0 +1,5 @@
+#!/bin/sh
+export PANIC_ACTION=
+export DEBUGGER_ATTACHED=yes
+
+exec ./build//make/jlibtool --mode=execute lldb -- ./build/bin/local/radiusd -sf -xx -l stdout -d ./raddb -D share/ $@
diff --git a/scripts/bin/radclient b/scripts/bin/radclient
new file mode 120000
index 0000000..f3a1360
--- /dev/null
+++ b/scripts/bin/radclient
@@ -0,0 +1 @@
+radiusd \ No newline at end of file
diff --git a/scripts/bin/radict b/scripts/bin/radict
new file mode 100755
index 0000000..cedcad0
--- /dev/null
+++ b/scripts/bin/radict
@@ -0,0 +1,5 @@
+#!/bin/sh
+DIR=$(dirname $0)/../..
+PROGRAM=$(basename $0)
+
+exec $DIR/build/make/jlibtool --mode=execute $FR_DEBUGGER $DIR/build/bin/local/$PROGRAM -D $DIR/share/ $@
diff --git a/scripts/bin/radiusd b/scripts/bin/radiusd
new file mode 100755
index 0000000..7d2e5cb
--- /dev/null
+++ b/scripts/bin/radiusd
@@ -0,0 +1,5 @@
+#!/bin/sh
+DIR=$(dirname $0)/../..
+PROGRAM=$(basename $0)
+
+exec $DIR/build/make/jlibtool --mode=execute $FR_DEBUGGER $DIR/build/bin/local/$PROGRAM -d $DIR/raddb -D $DIR/share/ $@
diff --git a/scripts/bin/radmin b/scripts/bin/radmin
new file mode 120000
index 0000000..f3a1360
--- /dev/null
+++ b/scripts/bin/radmin
@@ -0,0 +1 @@
+radiusd \ No newline at end of file
diff --git a/scripts/bin/radsniff b/scripts/bin/radsniff
new file mode 120000
index 0000000..f3a1360
--- /dev/null
+++ b/scripts/bin/radsniff
@@ -0,0 +1 @@
+radiusd \ No newline at end of file
diff --git a/scripts/bin/unit_test_module b/scripts/bin/unit_test_module
new file mode 120000
index 0000000..f3a1360
--- /dev/null
+++ b/scripts/bin/unit_test_module
@@ -0,0 +1 @@
+radiusd \ No newline at end of file
diff --git a/scripts/boiler.mk b/scripts/boiler.mk
new file mode 100644
index 0000000..9d70104
--- /dev/null
+++ b/scripts/boiler.mk
@@ -0,0 +1,674 @@
+# boilermake: A reusable, but flexible, boilerplate Makefile.
+#
+# Copyright 2008, 2009, 2010 Dan Moulding, Alan T. DeKok
+#
+# 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 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Caution: Don't edit this Makefile! Create your own main.mk and other
+# submakefiles, which will be included by this Makefile.
+# Only edit this if you need to modify boilermake's behavior (fix
+# bugs, add features, etc).
+
+# Note: Parameterized "functions" in this makefile that are marked with
+# "USE WITH EVAL" are only useful in conjuction with eval. This is
+# because those functions result in a block of Makefile syntax that must
+# be evaluated after expansion. Since they must be used with eval, most
+# instances of "$" within them need to be escaped with a second "$" to
+# accomodate the double expansion that occurs when eval is invoked.
+
+#
+# You can watch what it's doing by:
+#
+# $ VERBOSE=1 make ... args ...
+#
+ifeq "${VERBOSE}" ""
+ Q=@
+else
+ Q=
+endif
+
+# ADD_CLEAN_RULE - Parameterized "function" that adds a new rule and phony
+# target for cleaning the specified target (removing its build-generated
+# files).
+#
+# USE WITH EVAL
+#
+define ADD_CLEAN_RULE
+ clean: clean_$(notdir ${1})
+ .PHONY: clean_$(notdir ${1})
+ clean_$(notdir ${1}):
+ $(Q)$(strip rm -f ${${1}_BUILD}/${1} $${${1}_OBJS} $${${1}_DEPS} $${${1}_OBJS:%.${OBJ_EXT}=%.[do]}) $(if ${TARGET_DIR},$${TARGET_DIR}/$(notdir ${1}))
+ $${${1}_POSTCLEAN}
+
+endef
+
+# FILTER_DEPENDS: function to turn a *.d file into a *.mk file.
+# We start off with the dependencies as created by the compiler,
+# CPP, or makedepend. We then ensure that there is an empty dependency
+# for each header file. The blank target ensures that the build
+# can proceed even if the header file has been deleted.
+#
+# COMMON filters:
+# remove comments
+# remove dependencies on global include files
+# remove empty dependencies
+# remove CPP hacks like "foo: <built-in>"
+#
+# 1) Filter the .d file to remove unnecessary cruft
+#
+# COMMON
+# Replace ".o" with "${OBJ_EXT}"
+# delete empty continuation lines
+# delete blank lines
+# replace "build/" with "${BUILD_DIR}/" when it's at the start of a line
+# delete references to ${BUILD_DIR}/make/include, the "config.mk"
+# file adds these dependencies automatically.
+# replace "build/" with "${BUILD_DIR}/" when it's in the middle of a line
+#
+# remove sequential duplicate lines
+#
+# 2) Create empty dependencies from the files
+#
+# COMMON
+# remove existing targets
+# remove continuations (to make the targets stand by themselves)
+# delete blank lines
+# add in empty dependency for each file.
+# remove sequential duplicate lines
+#
+define FILTER_DEPENDS
+ $(Q)mkdir -p $$(dir $${BUILD_DIR}/make/src/$$*)
+ $(Q)mkdir -p $$(dir $${BUILD_DIR}/objs/$$*)
+ $(Q)sed -e 's/#.*//' \
+ -e 's,^$${top_srcdir},$$$${top_srcdir},' \
+ -e 's, $${top_srcdir}, $$$${top_srcdir},' \
+ -e 's,^$${BUILD_DIR},$$$${BUILD_DIR},' \
+ -e 's, $${BUILD_DIR}/make/include/[^ :]*,,' \
+ -e 's, $${BUILD_DIR}, $$$${BUILD_DIR},' \
+ -e 's, /[^: ]*,,g' \
+ -e 's,^ *[^:]* *: *$$$$,,' \
+ -e '/: </ d' \
+ -e 's/\.o: /.$$$${OBJ_EXT}: /' \
+ -e '/^ *\\$$$$/ d' \
+ < $${BUILD_DIR}/objs/$$*.d | sed -e '$$$$!N; /^\(.*\)\n\1$$$$/!P; D' \
+ > $${BUILD_DIR}/make/src/$$*.mk
+ $(Q)sed -e 's/#.*//' \
+ -e 's, $${BUILD_DIR}/make/include/[^ :]*,,' \
+ -e 's, /[^: ]*,,g' \
+ -e 's,^ *[^:]* *: *$$$$,,' \
+ -e '/: </ d' \
+ -e 's/^[^:]*: *//' \
+ -e 's/ *\\$$$$//' \
+ -e 's/$$$$/ :/' \
+ < $${BUILD_DIR}/objs/$$*.d | sed -e '$$$$!N; /^\(.*\)\n\1$$$$/!P; D' \
+ >> $${BUILD_DIR}/make/src/$$*.mk
+endef
+
+# ADD_OBJECT_RULE - Parameterized "function" that adds a pattern rule, using
+# the commands from the second argument, for building object files from
+# source files with the filename extension specified in the first argument.
+#
+# This function assumes that the C/C++ sources files have filenames
+# *relative* to the source root. If they have absolute pathnames, it
+# creates the wrong filenames...
+#
+# USE WITH EVAL
+#
+ifeq "${CPP_MAKEDEPEND}" "yes"
+define ADD_OBJECT_RULE
+$${BUILD_DIR}/objs/%.${OBJ_EXT} $${BUILD_DIR}/objs/%.d: ${1} | ${BOOTSTRAP_BUILD}
+ ${2}
+ $${CPP} $${CPPFLAGS} $$(addprefix -I,$${SRC_INCDIRS}) $${SRC_DEFS} $$< | sed \
+ -n 's,^\# *[0-9][0-9]* *"\([^"]*\)".*,$$@: \1,p' > $${BUILD_DIR}/objs/$$*.d
+${FILTER_DEPENDS}
+endef
+
+else
+define ADD_OBJECT_RULE
+$${BUILD_DIR}/objs/%.${OBJ_EXT} $${BUILD_DIR}/objs/%.d: ${1} | ${BOOTSTRAP_BUILD}
+ ${2}
+${FILTER_DEPENDS}
+endef
+endif
+
+define ADD_ANALYZE_RULE
+$${BUILD_DIR}/plist/%.plist: ${1}
+ ${2}
+endef
+
+# ADD_TARGET_DIR - Parameterized "function" that makes a link from
+# TARGET_DIR to the executable or library in the BUILD_DIR directory.
+#
+# USE WITH EVAL
+#
+ifneq "${TARGET_DIR}" ""
+ define ADD_TARGET_DIR
+ all: $${TARGET_DIR}/$$(notdir ${1})
+
+ $${TARGET_DIR}/$$(notdir ${1}): ${1}
+ [ -f $${TARGET_DIR}/$$(notdir ${1}) ] || ln -s ${1} $${TARGET_DIR}/$$(notdir ${1})
+
+ endef
+endif
+
+# ADD_TARGET_TO_ALL - Parameterized "function" that adds the target,
+# and makes "all" depend on it.
+#
+# USE WITH EVAL
+#
+define ADD_TARGET_TO_ALL
+ all: ${1}
+
+endef
+
+# ADD_TARGET_RULE.* - Parameterized "functions" that adds a new target to the
+# Makefile. There should be one ADD_TARGET_RULE definition for each
+# type of target that is used in the build.
+#
+# New rules can be added by copying one of the existing ones, and
+# replacing the line after the "mkdir"
+#
+
+# ADD_TARGET_RULE.exe - Build an executable target.
+#
+# USE WITH EVAL
+#
+define ADD_TARGET_RULE.exe
+ # So "make ${1}" works
+ .PHONY: ${1}
+ ${1}: $${${1}_BUILD}/${1}
+
+ # Create executable ${1}
+ $${${1}_BUILD}/${1}: $${${1}_OBJS} $${${1}_PRBIN} $${${1}_PRLIBS}
+ $(Q)$(strip mkdir -p $(dir $${${1}_BUILD}/${1}))
+ $(Q)$(ECHO) LINK $${${1}_BUILD}/${1}
+ $(Q)$${${1}_LINKER} -o $${${1}_BUILD}/${1} $${RPATH_FLAGS} $${LDFLAGS} \
+ $${${1}_LDFLAGS} $${${1}_OBJS} $${${1}_PRLIBS} \
+ $${LDLIBS} $${${1}_LDLIBS}
+ $(Q)$${${1}_POSTMAKE}
+
+ ifneq "${ANALYZE.c}" ""
+ scan.${1}: $${${1}_PLISTS}
+ endif
+
+ .PHONY: $(DIR)
+ $(DIR)/: ${1}
+endef
+
+# ADD_TARGET_RULE.a - Build a static library target.
+#
+# USE WITH EVAL
+#
+define ADD_TARGET_RULE.a
+ # So "make ${1}" works
+ .PHONY: ${1}
+ ${1}: $${${1}_BUILD}/${1}
+
+ # Create static library ${1}
+ $${${1}_BUILD}/${1}: $${${1}_OBJS} $${${1}_PRLIBS}
+ $(Q)$(strip mkdir -p $(dir $${${1}_BUILD}/${1}))
+ $(Q)$(ECHO) LINK $${${1}_BUILD}/${1}
+ $(Q)$${AR} $${ARFLAGS} $${${1}_BUILD}/${1} $${${1}_OBJS}
+ $(Q)$${${1}_POSTMAKE}
+
+ ifneq "${ANALYZE.c}" ""
+ scan.${1}: $${${1}_PLISTS}
+ endif
+
+ .PHONY: $(DIR)
+ $(DIR)/: ${1}
+endef
+
+# ADD_TARGET_RULE.so - Build a ".so" target.
+#
+# USE WITH EVAL
+#
+define ADD_TARGET_RULE.so
+$(error Please add rules to build a ".so" file.)
+endef
+
+# ADD_TARGET_RULE.dll - Build a ".dll" target.
+#
+# USE WITH EVAL
+#
+define ADD_TARGET_RULE.dll
+$(error Please add rules to build a ".dll" file.)
+endef
+
+# ADD_TARGET_RULE.dylib - Build a ".dylib" target.
+#
+# USE WITH EVAL
+#
+define ADD_TARGET_RULE.dylib
+$(error Please add rules to build a ".dylib" file.)
+endef
+
+# CANONICAL_PATH - Given one or more paths, converts the paths to the canonical
+# form. The canonical form is the path, relative to the project's top-level
+# directory (the directory from which "make" is run), and without
+# any "./" or "../" sequences. For paths that are not located below the
+# top-level directory, the canonical form is the absolute path (i.e. from
+# the root of the filesystem) also without "./" or "../" sequences.
+define CANONICAL_PATH
+$(patsubst ${CURDIR}/%,%,$(abspath ${1}))
+endef
+
+# COMPILE_C_CMDS - Commands for compiling C source code.
+ifeq "$(CPPCHECK)" ""
+define COMPILE_C_CMDS
+ $(Q)mkdir -p $(dir $@)
+ $(Q)$(ECHO) CC $<
+ $(Q)$(strip ${COMPILE.c} -o $@ -c -MD ${CPPFLAGS} ${CFLAGS} ${SRC_CFLAGS} ${INCDIRS} \
+ $(addprefix -I, ${SRC_INCDIRS}) ${SRC_DEFS} ${DEFS} $<)
+endef
+else
+#
+# do cppcheck AND compilation, so that we have correct dependencies
+# Suppress variable scope warnings for now. They're style, and don't really
+# affect anything.
+#
+define COMPILE_C_CMDS
+ $(Q)mkdir -p $(dir $@)
+ $(Q)$(ECHO) CC $<
+ $(Q)$(strip ${COMPILE.c} -o $@ -c -MD ${CPPFLAGS} ${CFLAGS} ${SRC_CFLAGS} ${INCDIRS} \
+ $(addprefix -I,${SRC_INCDIRS}) ${SRC_DEFS} ${DEFS} $<)
+ $(Q)cppcheck --enable=style -q ${CHECKFLAGS} $(filter -isystem%,${SRC_CFLAGS}) \
+ $(filter -I%,${SRC_CFLAGS}) $(filter -D%,${SRC_CFLAGS}) ${INCDIRS} \
+ $(addprefix -I,${SRC_INCDIRS}) ${SRC_DEFS} ${DEFS} --suppress=variableScope --suppress=invalidscanf $<
+endef
+endif
+
+# ANALYZE_C_CMDS - Commands for analyzing C source code with clang.
+define ANALYZE_C_CMDS
+ $(Q)mkdir -p $(dir $@)
+ $(Q)$(ECHO) SCAN $<
+ $(Q)$(strip ${ANALYZE.c} --analyze -Xanalyzer -analyzer-output=html -c $< -o $@ ${CPPFLAGS} \
+ ${CFLAGS} ${SRC_CFLAGS} ${INCDIRS} $(addprefix -I,${SRC_INCDIRS}) ${SRC_DEFS} ${DEFS}) || (rm -f $@ && false)
+ $(Q)touch $@
+endef
+
+# COMPILE_CXX_CMDS - Commands for compiling C++ source code.
+define COMPILE_CXX_CMDS
+ $(Q)mkdir -p $(dir $@)
+ $(Q)$(strip ${COMPILE.cxx} -o $@ -c -MD ${CPPFLAGS} ${CXXFLAGS} ${SRC_CXXFLAGS} ${INCDIRS} \
+ $(addprefix -I,${SRC_INCDIRS}) ${SRC_DEFS} ${DEFS} $<)
+endef
+
+# INCLUDE_SUBMAKEFILE - Parameterized "function" that includes a new
+# "submakefile" fragment into the overall Makefile. It also recursively
+# includes all submakefiles of the specified submakefile fragment.
+#
+# USE WITH EVAL
+#
+define INCLUDE_SUBMAKEFILE
+ # Initialize all variables that can be defined by a makefile fragment, then
+ # include the specified makefile fragment.
+ TARGET :=
+ TGT_LDFLAGS :=
+ TGT_LDLIBS :=
+ TGT_LINKER :=
+ TGT_POSTCLEAN :=
+ TGT_POSTMAKE :=
+ TGT_PREREQS :=
+ TGT_POSTINSTALL :=
+ TGT_INSTALLDIR := ..
+ TGT_CHECK_HEADERS :=
+ TGT_CHECK_LIBS :=
+ TEST :=
+
+ SOURCES :=
+ SRC_CFLAGS :=
+ SRC_CXXFLAGS :=
+ SRC_DEFS :=
+ SRC_INCDIRS :=
+ MAN :=
+ FILES :=
+ OUTPUT :=
+
+ SUBMAKEFILES :=
+
+ # A directory stack is maintained so that the correct paths are used as we
+ # recursively include all submakefiles. Get the makefile's directory and
+ # push it onto the stack.
+ DIR := $(call CANONICAL_PATH,$(dir ${1}))
+ DIR_STACK := $$(call PUSH,$${DIR_STACK},$${DIR})
+
+ include ${1}
+
+ # Initialize internal local variables.
+ OBJS :=
+
+ # Determine which target this makefile's variables apply to. A stack is
+ # used to keep track of which target is the "current" target as we
+ # recursively include other submakefiles.
+ ifneq "$$(strip $${TARGET})" ""
+ # This makefile defined a new target. Target variables defined by this
+ # makefile apply to this new target. Initialize the target's variables.
+
+ # libs go into ${BUILD_DIR}/lib
+ # everything else goes into ${BUILD_DIR}/bin
+# TGT := $$(strip $$(if $$(suffix $${TARGET}),$${BUILD_DIR}/lib,$${BUILD_DIR}/bin)/$${TARGET})
+ TGT := $${TARGET}
+
+ # A "hook" to rewrite "libfoo.a" -> "libfoo.la" when using libtool
+ $$(eval $$(call ADD_LIBTOOL_SUFFIX))
+
+ ALL_TGTS += $${TGT}
+ $${TGT}_LDFLAGS := $${TGT_LDFLAGS}
+ $${TGT}_LDLIBS := $${TGT_LDLIBS}
+ $${TGT}_LINKER := $${TGT_LINKER}
+ $${TGT}_POSTMAKE := $${TGT_POSTMAKE}
+ $${TGT}_POSTCLEAN := $${TGT_POSTCLEAN}
+ $${TGT}_POSTINSTALL := $${TGT_POSTINSTALL}
+ $${TGT}_PREREQS := $${TGT_PREREQS}
+ $${TGT}_PRBIN := $$(addprefix $${BUILD_DIR}/bin/,$$(filter-out %.a %.so %.la,$${TGT_PREREQS}))
+ $${TGT}_PRLIBS := $$(addprefix $${BUILD_DIR}/lib/,$$(filter %.a %.so %.la,$${TGT_PREREQS}))
+ $${TGT}_DEPS :=
+ $${TGT}_OBJS :=
+ $${TGT}_SOURCES :=
+ $${TGT}_MAN := $${MAN}
+ $${TGT}_SUFFIX := $$(if $$(suffix $${TGT}),$$(suffix $${TGT}),.exe)
+
+ # If it's an EXE, ensure that transitive library linking works.
+ # i.e. we build libfoo.a which in turn requires -lbar. So, the executable
+ # has to be linked to both libfoo.a and -lbar.
+ ifeq "$${$${TGT}_SUFFIX}" ".exe"
+ $${TGT}_LDLIBS += $$(filter-out %.a %.so %.la,$${$${TGT_PREREQS}_LDLIBS})
+ endif
+
+ $${TGT}_BUILD := $$(if $$(suffix $${TGT}),$${BUILD_DIR}/lib,$${BUILD_DIR}/bin)
+ $${TGT}_MAKEFILES += ${1}
+ $${TGT}_CHECK_HEADERS := $${TGT_CHECK_HEADERS}
+ $${TGT}_CHECK_LIBS := $${TGT_CHECK_LIBS}
+ else
+ # The values defined by this makefile apply to the the "current" target
+ # as determined by which target is at the top of the stack.
+ TGT := $$(strip $$(call PEEK,$${TGT_STACK}))
+ $${TGT}_LDFLAGS += $${TGT_LDFLAGS}
+ $${TGT}_LDLIBS += $${TGT_LDLIBS}
+ $${TGT}_POSTCLEAN += $${TGT_POSTCLEAN}
+ $${TGT}_POSTMAKE += $${TGT_POSTMAKE}
+ $${TGT}_PREREQS += $${TGT_PREREQS}
+ endif
+
+ # Push the current target onto the target stack.
+ TGT_STACK := $$(call PUSH,$${TGT_STACK},$${TGT})
+
+ # If there's no target, don't build the sources.
+ ifneq "$$(strip $${TARGET})" ""
+
+ # if there's no sources, don't do the automatic object build
+ ifneq "$$(strip $${SOURCES})" ""
+ # This makefile builds one or more objects from source. Validate the
+ # specified sources against the supported source file types.
+ BAD_SRCS := $$(strip $$(filter-out $${ALL_SRC_EXTS},$${SOURCES}))
+ ifneq "$${BAD_SRCS}" ""
+ $$(error Unsupported source file(s) found in ${1} [$${BAD_SRCS}])
+ endif
+
+ # Qualify and canonicalize paths.
+ SOURCES := $$(call QUALIFY_PATH,$${DIR},$${SOURCES})
+ SOURCES := $$(call CANONICAL_PATH,$${SOURCES})
+ SRC_INCDIRS := $$(call QUALIFY_PATH,$${DIR},$${SRC_INCDIRS})
+ SRC_INCDIRS := $$(call CANONICAL_PATH,$${SRC_INCDIRS})
+
+ # Save the list of source files for this target.
+ $${TGT}_SOURCES += $${SOURCES}
+
+ # Convert the source file names to their corresponding object file
+ # names.
+ OBJS := $$(addprefix $${BUILD_DIR}/objs/,\
+ $$(addsuffix .${OBJ_EXT},$$(basename $${SOURCES})))
+
+ PLISTS := $$(addprefix $${BUILD_DIR}/plist/,\
+ $$(addsuffix .plist,$$(basename $${SOURCES})))
+ ALL_PLISTS += ${PLISTS}
+
+ # Add the objects to the current target's list of objects, and create
+ # target-specific variables for the objects based on any source
+ # variables that were defined.
+ $${TGT}_OBJS += $${OBJS}
+ $${TGT}_PLISTS += $${PLISTS}
+ $${TGT}_DEPS += $$(addprefix $${BUILD_DIR}/make/src/,\
+ $$(addsuffix .mk,$$(basename $${SOURCES})))
+
+ # A "hook" to define variables needed by the "legacy" makefiles.
+ $$(eval $$(call ADD_LEGACY_VARIABLES,$$(dir ${1}),$${TGT}))
+
+ $${OBJS}: SRC_CFLAGS := $${SRC_CFLAGS}
+ $${OBJS}: SRC_CXXFLAGS := $${SRC_CXXFLAGS}
+ $${OBJS}: SRC_DEFS := $$(addprefix -D,$${SRC_DEFS})
+ $${OBJS}: SRC_INCDIRS := $${SRC_INCDIRS}
+ $${OBJS}: ${1}
+
+ $${PLISTS}: SRC_CFLAGS := $${SRC_CFLAGS}
+ $${PLISTS}: SRC_CXXFLAGS := $${SRC_CXXFLAGS}
+ $${PLISTS}: SRC_DEFS := $$(addprefix -D,$${SRC_DEFS})
+ $${PLISTS}: SRC_INCDIRS := $${SRC_INCDIRS}
+ $${PLISTS}: ${1}
+ endif
+ endif
+
+ ifneq "$$(strip $${SUBMAKEFILES})" ""
+ # This makefile has submakefiles. Recursively include them.
+ $$(foreach MK,$${SUBMAKEFILES},\
+ $$(eval $$(call INCLUDE_SUBMAKEFILE,\
+ $$(call CANONICAL_PATH,\
+ $$(call QUALIFY_PATH,$${DIR},$${MK})))))
+ endif
+
+ # Reset the "current" target to it's previous value.
+ TGT_STACK := $$(call POP,$${TGT_STACK})
+ # If we're about to change targets, create the rules for the target
+ ifneq "$${TGT}" "$$(call PEEK,$${TGT_STACK})"
+ # add rules to build the target, and have "all" depend on it.
+ $$(eval $$(call ADD_TARGET_TO_ALL,$${TGT}))
+
+ # A "hook" to add rules for ${TARGET_DIR}/foo, if TARGET_DIR
+ # is defined. Otherwise, we leave the source directory untouched.
+ $$(eval $$(call ADD_TARGET_DIR,$${TGT}))
+
+ # A "hook" to build the libtool target.
+ $$(eval $$(call ADD_LIBTOOL_TARGET))
+
+ # Choose the correct linker.
+ ifeq "$$(strip $$(filter $${CXX_SRC_EXTS},$${$${TGT}_SOURCES}))" ""
+ ifeq "$${$${TGT}_LINKER}" ""
+ $${TGT}_LINKER := ${LL}$${LINK.c}
+ endif
+ else
+ ifeq "$${$${TGT}_LINKER}" ""
+ $${TGT}_LINKER := ${LL}$${LINK.cxx}
+ endif
+ endif
+
+ # add rules to build the target
+ $$(eval $$(call ADD_TARGET_RULE$${$${TGT}_SUFFIX},$${TGT}))
+
+ # generate the clean rule for this target.
+ $$(eval $$(call ADD_CLEAN_RULE,$${TGT}))
+
+ # Hook to add an installation target
+ $$(eval $$(call ADD_INSTALL_TARGET,$${TGT}))
+
+ # Hook to add a configuration target
+ $$(eval $$(call ADD_TARGET_CONFIG,$${TGT}))
+
+ # "hook" for legacy Makefiles
+ $$(eval $$(call ADD_LEGACY_RULE,$${TGT}))
+ endif
+
+ TGT := $$(call PEEK,$${TGT_STACK})
+
+ # Reset the "current" directory to it's previous value.
+ DIR_STACK := $$(call POP,$${DIR_STACK})
+ DIR := $$(call PEEK,$${DIR_STACK})
+endef
+
+# MIN - Parameterized "function" that results in the minimum lexical value of
+# the two values given.
+define MIN
+$(firstword $(sort ${1} ${2}))
+endef
+
+# PEEK - Parameterized "function" that results in the value at the top of the
+# specified colon-delimited stack.
+define PEEK
+$(lastword $(subst :, ,${1}))
+endef
+
+# POP - Parameterized "function" that pops the top value off of the specified
+# colon-delimited stack, and results in the new value of the stack. Note that
+# the popped value cannot be obtained using this function; use peek for that.
+define POP
+${1:%:$(lastword $(subst :, ,${1}))=%}
+endef
+
+# PUSH - Parameterized "function" that pushes a value onto the specified colon-
+# delimited stack, and results in the new value of the stack.
+define PUSH
+${2:%=${1}:%}
+endef
+
+# QUALIFY_PATH - Given a "root" directory and one or more paths, qualifies the
+# paths using the "root" directory (i.e. appends the root directory name to
+# the paths) except for paths that are absolute.
+define QUALIFY_PATH
+$(addprefix ${1}/,$(filter-out /%,${2})) $(filter /%,${2})
+endef
+
+###############################################################################
+#
+# Start of Makefile Evaluation
+#
+###############################################################################
+
+# Older versions of GNU Make lack capabilities needed by boilermake.
+# With older versions, "make" may simply output "nothing to do", likely leading
+# to confusion. To avoid this, check the version of GNU make up-front and
+# inform the user if their version of make doesn't meet the minimum required.
+MIN_MAKE_VERSION := 3.81
+MIN_MAKE_VER_MSG := boilermake requires GNU Make ${MIN_MAKE_VERSION} or greater
+ifeq "${MAKE_VERSION}" ""
+ $(info GNU Make not detected)
+ $(error ${MIN_MAKE_VER_MSG})
+endif
+ifneq "${MIN_MAKE_VERSION}" "$(call MIN,${MIN_MAKE_VERSION},${MAKE_VERSION})"
+ $(info This is GNU Make version ${MAKE_VERSION})
+ $(error ${MIN_MAKE_VER_MSG})
+endif
+
+# Define the source file extensions that we know how to handle.
+OBJ_EXT := o
+C_SRC_EXTS := %.c
+CXX_SRC_EXTS := %.C %.cc %.cp %.cpp %.CPP %.cxx %.c++
+ALL_SRC_EXTS := ${C_SRC_EXTS} ${CXX_SRC_EXTS}
+
+# Initialize global variables.
+ALL_TGTS :=
+DEFS :=
+DIR_STACK :=
+INCDIRS :=
+TGT_STACK :=
+
+ifeq "${top_builddir}" ""
+ top_builddir := .
+endif
+
+# Ensure that valid values are set for BUILD_DIR
+ifeq "$(strip ${BUILD_DIR})" ""
+ ifeq "${top_builddir}" "${PWD}"
+ BUILD_DIR := build
+ else
+ BUILD_DIR := ${top_builddir}/build
+ endif
+else
+ BUILD_DIR := $(call CANONICAL_PATH,${BUILD_DIR})
+endif
+
+.PHONY: $(BUILD_DIR)
+$(BUILD_DIR):
+ @mkdir -p $@
+
+# Define compilers and linkers
+#
+BOOTSTRAP_BUILD =
+COMPILE.c = ${CC}
+COMPILE.cxx = ${CXX}
+CPP = cc -E
+LINK.c = ${CC}
+LINK.cxx = ${CXX}
+
+# Set ECHO to "true" for *very* quiet builds
+ECHO = echo
+
+# Define the "all" target (which simply builds all user-defined targets) as the
+# default goal.
+.PHONY: all
+all:
+
+# Add "clean" rules to remove all build-generated files.
+.PHONY: clean
+clean:
+
+top_makedir := $(dir $(lastword ${MAKEFILE_LIST}))
+
+-include ${top_makedir}/install.mk
+-include ${top_makedir}/libtool.mk
+
+ifneq "${CPPCHECK}" ""
+CHECKFLAGS := -DCPPCHECK $(filter -isystem%,$(CPPFLAGS) $(CFLAGS)) $(filter -I%,$(CPPFLAGS) $(CFLAGS)) $(filter -D%,$(CPPFLAGS) $(CFLAGS))
+endif
+
+# Include the main user-supplied submakefile. This also recursively includes
+# all other user-supplied submakefiles.
+$(eval $(call INCLUDE_SUBMAKEFILE,${top_builddir}/main.mk))
+
+# Perform post-processing on global variables as needed.
+DEFS := $(addprefix -D,${DEFS})
+INCDIRS := $(addprefix -I,$(call CANONICAL_PATH,${INCDIRS}))
+
+# Add pattern rule(s) for creating compiled object code from C source.
+$(foreach EXT,${C_SRC_EXTS},\
+ $(eval $(call ADD_OBJECT_RULE,${EXT},$${COMPILE_C_CMDS})))
+
+ifneq "${ANALYZE.c}" ""
+$(foreach EXT,${C_SRC_EXTS},\
+ $(eval $(call ADD_ANALYZE_RULE,${EXT},$${ANALYZE_C_CMDS})))
+endif
+
+# Add pattern rule(s) for creating compiled object code from C++ source.
+$(foreach EXT,${CXX_SRC_EXTS},\
+ $(eval $(call ADD_OBJECT_RULE,${EXT},$${COMPILE_CXX_CMDS})))
+
+# Don't include the target dependencies if we're doing a "make clean"
+# Future: have a list of targets that don't require dependency generation,
+# and see if MAKECMDGOALS is one of them.
+ifneq "$(MAKECMDGOALS)" "clean"
+ $(foreach TGT,${ALL_TGTS},\
+ $(eval -include ${${TGT}_DEPS}))
+endif
+
+# Build rules for installation subdirectories
+$(foreach D,$(patsubst %/,%,$(sort $(dir ${ALL_INSTALL}))),\
+ $(eval $(call ADD_INSTALL_RULE.dir,${D})))
+
+
+scan: ${ALL_PLISTS}
+
+.PHONY: clean.scan
+clean.scan:
+ $(Q)rm -rf ${ALL_PLISTS}
+
+clean: clean.scan
diff --git a/scripts/ci/Dockerfile b/scripts/ci/Dockerfile
new file mode 100644
index 0000000..e285936
--- /dev/null
+++ b/scripts/ci/Dockerfile
@@ -0,0 +1,10 @@
+FROM ubuntu:14.04
+RUN apt-get update && apt-get install -y curl
+RUN curl -sSL "https://build.travis-ci.org/files/gpg/couchbase-precise.asc" | sudo -E apt-key add -
+RUN echo "deb http://packages.couchbase.com/ubuntu precise precise/main" | sudo tee -a /etc/apt/sources.list >/dev/null
+RUN echo "deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-5.0 main" >> /etc/apt/sources.list
+RUN curl https://raw.githubusercontent.com/travis-ci/apt-source-safelist/master/keys/llvm-toolchain-trusty-5.0.asc | apt-key add -
+RUN apt-get update && apt-get -y upgrade
+RUN apt-get -yq --no-install-suggests --no-install-recommends install autoconf build-essential debhelper devscripts dh-make doxygen fakeroot gdb graphviz lintian pbuilder python-dev quilt libruby ruby-dev libcollectdclient-dev firebird-dev freetds-dev libcap-dev libcouchbase2-libevent libcouchbase-dev libcurl4-openssl-dev libgdbm-dev libhiredis-dev libidn11-dev libiodbc2-dev libiodbc2 libjson0 libjson0-dev libkrb5-dev libldap2-dev libmemcached-dev libmysqlclient-dev libpam0g-dev libpcap-dev libpcre3-dev libperl-dev libpq-dev libreadline-dev libsnmp-dev libssl-dev libtalloc-dev libtalloc2-dbg libunbound-dev libwbclient-dev libykclient-dev libyubikey-dev clang-5.0
+RUN update-alternatives --install /usr/bin/clang clang /usr/bin/clang-5.0 100
+WORKDIR /usr/local/src/repositories
diff --git a/scripts/ci/Jenkinsfile b/scripts/ci/Jenkinsfile
new file mode 100644
index 0000000..f82fadc
--- /dev/null
+++ b/scripts/ci/Jenkinsfile
@@ -0,0 +1,66 @@
+// Initialize a variable to hold the matrix of travis builds
+tmatrix = []
+
+/* This function takes a list of tests and builds closures for each test to
+* be run in it's own docker container. It's a little strange, and uses a
+* functional programming trick (function currying) to create a closure that
+* can be passed to the "parallel" function, which can only take one argument
+* in this context
+*/
+
+def buildClosures(arg) {
+ println arg.inspect()
+ def travisTests = arg
+ def closures = [:]
+ for (value in travisTests) {
+ final valueCopy = value
+ closures[value] = { testEnv_str ->
+ def(dir,testEnv) = testEnv_str.split(":")
+ stage("$testEnv") {
+ // Docker needs full privileges and capabilites to run the tests
+ // This passes the necessary arguments to "docker run"
+ travisImage.inside("--privileged --cap-add=ALL") {
+ checkout([$class: 'GitSCM',\
+ branches: [[name: scm.branches[0].name]],\
+ doGenerateSubmoduleConfigurations: false,\
+ extensions: [[$class: 'CleanCheckout'],\
+ [$class: 'CleanBeforeCheckout'],\
+ [$class: 'RelativeTargetDirectory', relativeTargetDir: dir]],\
+ submoduleCfg: [], userRemoteConfigs: [[url: 'https://github.com/FreeRADIUS/freeradius-server']]])
+ sh "cd $dir ; export ${testEnv} ; bash scripts/travis/start.sh"
+ }
+ }
+ }.curry(value)
+ }
+ closures
+}
+
+/* This section does three things
+* 1. Checkout the repo for the necessary setup files
+* 2. Reads the test matrix from the .travis.yml and converts it into a list that
+* can be passed to the buildClosures function
+* 3. runs each test matrix under gcc and clang in parallel.
+*/
+
+node {
+ cleanWs()
+ checkout scm
+ travis = readYaml(file: "./.travis.yml")
+ travisImage = docker.build("travis-image-${scm.branches[0].name}", "./scripts/travis/")
+ stage("clang tests") {
+ tmatrix = []
+ c = "clang"
+ travis["env"]["matrix"].eachWithIndex { t,i ->
+ tmatrix << "${c}-${i}:CC=${c} ${t}"
+ }
+ parallel buildClosures(tmatrix)
+ }
+ stage("gcc tests") {
+ tmatrix = []
+ c = "gcc"
+ travis["env"]["matrix"].eachWithIndex { t,i ->
+ tmatrix << "${c}-${i}:CC=${c} ${t}"
+ }
+ parallel buildClosures(tmatrix)
+ }
+}
diff --git a/scripts/ci/eapol_test-build.sh b/scripts/ci/eapol_test-build.sh
new file mode 100755
index 0000000..42397e2
--- /dev/null
+++ b/scripts/ci/eapol_test-build.sh
@@ -0,0 +1,121 @@
+#!/bin/bash
+
+#
+# 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
+#
+# Copyright 2015 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+#
+
+#
+# Extremely basic script for building eapol_test from hostapd's main branch
+#
+# On success will write progress to stderr, and a path to the eapol_test
+# binary to stdout, exiting with 0.
+#
+# On error will exit with 1.
+#
+# Note: We don't always build eapol_test. If a copy is already present on the
+# system we use that in preference. To always build eapol_test, set
+# FORCE_BUILD=1 in the environment.
+#
+
+TMP_BUILD_DIR="${BUILD_DIR}"
+: ${TMP_BUILD_DIR:="$(mktemp -d -t eapol_test.XXXXX)"}
+: ${HOSTAPD_DIR:="${TMP_BUILD_DIR}/hostapd"}
+: ${HOSTAPD_GIT_BRANCH:="hostap_2_10"}
+#: ${HOSTAPD_GIT_COMMIT:=""}
+: ${WPA_SUPPLICANT_DIR:="${HOSTAPD_DIR}/wpa_supplicant"}
+
+: ${BUILD_CONF_DIR:="$(dirname $0)/eapol_test"}
+: ${EAPOL_TEST_PATH:="${BUILD_CONF_DIR}/eapol_test"}
+
+if [ -z "${FORCE_BUILD}" ]; then
+ if [ -e "${EAPOL_TEST_PATH}" ]; then
+ echo "${EAPOL_TEST_PATH}"
+ exit 0
+ fi
+
+ WHICH_EAPOL_TEST="$(which eapol_test)"
+ if [ ! -z "${WHICH_EAPOL_TEST}" ]; then
+ echo "${WHICH_EAPOL_TEST}"
+ exit 0
+ fi
+fi
+
+#
+# If OpenSSL 3.x
+#
+if openssl version | grep -q "OpenSSL 3\."; then
+ export EAPOL_TEST_CFLAGS="${EAPOL_TEST_CFLAGS} -DOPENSSL_USE_DEPRECATED -DOPENSSL_API_COMPAT=0x10101000L"
+ echo "WARNING: Building against OpenSSL 3, setting:" 1>&2
+ echo " EAPOL_TEST_CFLAGS='${EAPOL_TEST_CFLAGS}'" 1>&2
+ echo " EAPOL_TEST_LDFLAGS='${EAPOL_TEST_LDFLAGS}'" 1>&2
+fi
+
+case "$OSTYPE" in
+linux-gnu)
+ BUILD_CONF_FILE="${BUILD_CONF_DIR}/config_linux"
+ ;;
+
+darwin*)
+ BUILD_CONF_FILE="${BUILD_CONF_DIR}/config_osx"
+ ;;
+
+freebsd*)
+ BUILD_CONF_FILE="${BUILD_CONF_DIR}/config_freebsd"
+ ;;
+
+*)
+ echo "Don't have specific eapol_test build config for OS $OSTYPE. Using linux build config"
+ BUILD_CONF_FILE="${BUILD_CONF_DIR}/linux"
+ ;;
+esac
+
+if [ ! -e "${BUILD_CONF_FILE}" ]; then
+ echo "Missing build config file \"${BUILD_CONF_FILE}\" for OS $OSTYPE, please contribute one" 1>&2
+ exit 1
+fi
+
+# Shallow clone so we don't use all Jouni's bandwidth
+CLONE_DEPTH="--depth 1"
+# Unless we want a specific commit, in which case there's no way to grab it directly
+[ -z "${HOSTAPD_GIT_COMMIT}" ] || CLONE_DEPTH=""
+
+if ! [ -e "${HOSTAPD_DIR}/.git" ] && ! git clone --branch "${HOSTAPD_GIT_BRANCH}" ${CLONE_DEPTH} http://w1.fi/hostap.git 1>&2 "${TMP_BUILD_DIR}/hostapd"; then
+ echo "Failed cloning hostapd" 1>&2
+ if [ -z "${BUILD_DIR}" ]; then rm -rf "$TMP_BUILD_DIR"; fi
+ exit 1
+fi
+
+if [ -n "$HOSTAPD_GIT_COMMIT" ]; then
+ if ! git --work-tree="${TMP_BUILD_DIR}/hostapd" --git-dir="${TMP_BUILD_DIR}/hostapd/.git" checkout "${HOSTAPD_GIT_COMMIT}"; then
+ echo "Unable to check out hostapd commit ${HOSTAPD_GIT_COMMIT}" 1>&2
+ if [ -z "${BUILD_DIR}" ]; then rm -rf "$TMP_BUILD_DIR"; fi
+ exit 1
+ fi
+fi
+
+cp "$BUILD_CONF_FILE" "$WPA_SUPPLICANT_DIR/.config"
+
+if ! make -C "${WPA_SUPPLICANT_DIR}" -j8 eapol_test 1>&2 || [ ! -e "${WPA_SUPPLICANT_DIR}/eapol_test" ]; then
+ echo "Build error" 1>&2
+ if [ -z "${BUILD_DIR}" ]; then rm -rf "$TMP_BUILD_DIR"; fi
+ exit 1
+fi
+
+cp "${WPA_SUPPLICANT_DIR}/eapol_test" "${EAPOL_TEST_PATH}"
+
+echo "${EAPOL_TEST_PATH}"
+if [ -z "${BUILD_DIR}" ]; then rm -rf "$TMP_BUILD_DIR"; fi
diff --git a/scripts/ci/eapol_test/.gitignore b/scripts/ci/eapol_test/.gitignore
new file mode 100644
index 0000000..6a537cb
--- /dev/null
+++ b/scripts/ci/eapol_test/.gitignore
@@ -0,0 +1 @@
+eapol_test
diff --git a/scripts/ci/eapol_test/config_freebsd b/scripts/ci/eapol_test/config_freebsd
new file mode 100644
index 0000000..8cab937
--- /dev/null
+++ b/scripts/ci/eapol_test/config_freebsd
@@ -0,0 +1,520 @@
+# Example wpa_supplicant build time configuration
+#
+# This file lists the configuration options that are used when building the
+# hostapd binary. All lines starting with # are ignored. Configuration option
+# lines must be commented out complete, if they are not to be included, i.e.,
+# just setting VARIABLE=n is not disabling that variable.
+#
+# This file is included in Makefile, so variables like CFLAGS and LIBS can also
+# be modified from here. In most cases, these lines should use += in order not
+# to override previous values of the variables.
+
+CFLAGS += -g3 -O0 -Wno-error=deprecated-declarations $(EAPOL_TEST_CFLAGS)
+LIBS += $(EAPOL_TEST_LDFLAGS)
+
+#
+# Disable some warnings only against CLANG
+#
+ifeq ($(shell $(CC) -v 2>&1 | grep -c "clang version"), 1)
+CFLAGS += -Wno-error=void-pointer-to-enum-cast -Wno-error=ignored-qualifiers
+endif
+
+# Some Red Hat versions seem to include kerberos header files from OpenSSL, but
+# the kerberos files are not in the default include path. Following line can be
+# used to fix build issues on such systems (krb5.h not found).
+#CFLAGS += -I/usr/include/kerberos
+
+# Driver interface for generic Linux wireless extensions
+# Note: WEXT is deprecated in the current Linux kernel version and no new
+# functionality is added to it. nl80211-based interface is the new
+# replacement for WEXT and its use allows wpa_supplicant to properly control
+# the driver to improve existing functionality like roaming and to support new
+# functionality.
+CONFIG_DRIVER_WEXT=n
+
+# Driver interface for Linux drivers using the nl80211 kernel interface
+CONFIG_DRIVER_NL80211=n
+
+# QCA vendor extensions to nl80211
+CONFIG_DRIVER_NL80211_QCA=n
+
+# driver_nl80211.c requires libnl. If you are compiling it yourself
+# you may need to point hostapd to your version of libnl.
+#
+#CFLAGS += -I$<path to libnl include files>
+#LIBS += -L$<path to libnl library files>
+
+# Use libnl v2.0 (or 3.0) libraries.
+#CONFIG_LIBNL20=y
+
+# Use libnl 3.2 libraries (if this is selected, CONFIG_LIBNL20 is ignored)
+#CONFIG_LIBNL32=y
+
+
+# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
+#CONFIG_DRIVER_BSD=y
+#CFLAGS += -I/usr/local/include
+#LIBS += -L/usr/local/lib
+#LIBS_p += -L/usr/local/lib
+#LIBS_c += -L/usr/local/lib
+
+# Driver interface for Windows NDIS
+#CONFIG_DRIVER_NDIS=y
+#CFLAGS += -I/usr/include/w32api/ddk
+#LIBS += -L/usr/local/lib
+# For native build using mingw
+#CONFIG_NATIVE_WINDOWS=y
+# Additional directories for cross-compilation on Linux host for mingw target
+#CFLAGS += -I/opt/mingw/mingw32/include/ddk
+#LIBS += -L/opt/mingw/mingw32/lib
+#CC=mingw32-gcc
+# By default, driver_ndis uses WinPcap for low-level operations. This can be
+# replaced with the following option which replaces WinPcap calls with NDISUIO.
+# However, this requires that WZC is disabled (net stop wzcsvc) before starting
+# wpa_supplicant.
+# CONFIG_USE_NDISUIO=y
+
+# Driver interface for wired Ethernet drivers
+CONFIG_DRIVER_WIRED=y
+
+# Driver interface for the Broadcom RoboSwitch family
+#CONFIG_DRIVER_ROBOSWITCH=y
+
+# Driver interface for no driver (e.g., WPS ER only)
+#CONFIG_DRIVER_NONE=y
+
+# Solaris libraries
+#LIBS += -lsocket -ldlpi -lnsl
+#LIBS_c += -lsocket
+
+# Enable IEEE 802.1X Supplicant (automatically included if any EAP method is
+# included)
+CONFIG_IEEE8021X_EAPOL=y
+
+# EAP-MD5
+CONFIG_EAP_MD5=y
+
+# EAP-MSCHAPv2
+CONFIG_EAP_MSCHAPV2=y
+
+# EAP-TLS
+CONFIG_EAP_TLS=y
+
+# EAL-PEAP
+CONFIG_EAP_PEAP=y
+
+# EAP-TTLS
+CONFIG_EAP_TTLS=y
+
+# EAP-FAST
+# Note: If OpenSSL is used as the TLS library, OpenSSL 1.0 or newer is needed
+# for EAP-FAST support. Older OpenSSL releases would need to be patched, e.g.,
+# with openssl-0.9.8x-tls-extensions.patch, to add the needed functions.
+CONFIG_EAP_FAST=y
+
+# EAP-GTC
+CONFIG_EAP_GTC=y
+
+# EAP-OTP
+CONFIG_EAP_OTP=y
+
+# EAP-SIM (enable CONFIG_PCSC, if EAP-SIM is used)
+#CONFIG_EAP_SIM=y
+
+# EAP-PSK (experimental; this is _not_ needed for WPA-PSK)
+CONFIG_EAP_PSK=y
+
+# EAP-pwd (secure authentication using only a password)
+CONFIG_EAP_PWD=y
+
+# EAP-PAX
+CONFIG_EAP_PAX=y
+
+# LEAP
+CONFIG_EAP_LEAP=n
+
+# EAP-AKA (enable CONFIG_PCSC, if EAP-AKA is used)
+CONFIG_EAP_AKA=y
+
+# EAP-AKA' (enable CONFIG_PCSC, if EAP-AKA' is used).
+# This requires CONFIG_EAP_AKA to be enabled, too.
+CONFIG_EAP_AKA_PRIME=y
+
+# Enable USIM simulator (Milenage) for EAP-AKA
+CONFIG_USIM_SIMULATOR=y
+
+# Enable SIM simulator (Milenage) for EAP-SIM
+CONFIG_SIM_SIMULATOR=y
+
+# EAP-SAKE
+CONFIG_EAP_SAKE=y
+
+# EAP-GPSK
+CONFIG_EAP_GPSK=y
+# Include support for optional SHA256 cipher suite in EAP-GPSK
+CONFIG_EAP_GPSK_SHA256=y
+
+# EAP-TNC and related Trusted Network Connect support (experimental)
+CONFIG_EAP_TNC=y
+
+# Wi-Fi Protected Setup (WPS)
+#CONFIG_WPS=y
+# Enable WPS external registrar functionality
+#CONFIG_WPS_ER=y
+# Disable credentials for an open network by default when acting as a WPS
+# registrar.
+#CONFIG_WPS_REG_DISABLE_OPEN=y
+# Enable WPS support with NFC config method
+#CONFIG_WPS_NFC=y
+
+# EAP-IKEv2
+CONFIG_EAP_IKEV2=y
+
+# EAP-EKE
+CONFIG_EAP_EKE=y
+
+# PKCS#12 (PFX) support (used to read private key and certificate file from
+# a file that usually has extension .p12 or .pfx)
+CONFIG_PKCS12=y
+
+# Smartcard support (i.e., private key on a smartcard), e.g., with openssl
+# engine.
+CONFIG_SMARTCARD=y
+
+# PC/SC interface for smartcards (USIM, GSM SIM)
+# Enable this if EAP-SIM or EAP-AKA is included
+#CONFIG_PCSC=y
+
+# Support HT overrides (disable HT/HT40, mask MCS rates, etc.)
+#CONFIG_HT_OVERRIDES=y
+
+# Support VHT overrides (disable VHT, mask MCS rates, etc.)
+#CONFIG_VHT_OVERRIDES=y
+
+# Development testing
+CONFIG_EAPOL_TEST=y
+
+# Select control interface backend for external programs, e.g, wpa_cli:
+# unix = UNIX domain sockets (default for Linux/*BSD)
+# udp = UDP sockets using localhost (127.0.0.1)
+# udp6 = UDP IPv6 sockets using localhost (::1)
+# named_pipe = Windows Named Pipe (default for Windows)
+# udp-remote = UDP sockets with remote access (only for tests systems/purpose)
+# udp6-remote = UDP IPv6 sockets with remote access (only for tests purpose)
+# y = use default (backwards compatibility)
+# If this option is commented out, control interface is not included in the
+# build.
+CONFIG_CTRL_IFACE=y
+
+# Include support for GNU Readline and History Libraries in wpa_cli.
+# When building a wpa_cli binary for distribution, please note that these
+# libraries are licensed under GPL and as such, BSD license may not apply for
+# the resulting binary.
+#CONFIG_READLINE=y
+
+# Include internal line edit mode in wpa_cli. This can be used as a replacement
+# for GNU Readline to provide limited command line editing and history support.
+#CONFIG_WPA_CLI_EDIT=y
+
+# Remove debugging code that is printing out debug message to stdout.
+# This can be used to reduce the size of the wpa_supplicant considerably
+# if debugging code is not needed. The size reduction can be around 35%
+# (e.g., 90 kB).
+#CONFIG_NO_STDOUT_DEBUG=y
+
+# Remove WPA support, e.g., for wired-only IEEE 802.1X supplicant, to save
+# 35-50 kB in code size.
+#CONFIG_NO_WPA=y
+
+# Remove IEEE 802.11i/WPA-Personal ASCII passphrase support
+# This option can be used to reduce code size by removing support for
+# converting ASCII passphrases into PSK. If this functionality is removed, the
+# PSK can only be configured as the 64-octet hexstring (e.g., from
+# wpa_passphrase). This saves about 0.5 kB in code size.
+#CONFIG_NO_WPA_PASSPHRASE=y
+
+# Disable scan result processing (ap_mode=1) to save code size by about 1 kB.
+# This can be used if ap_scan=1 mode is never enabled.
+#CONFIG_NO_SCAN_PROCESSING=y
+
+# Select configuration backend:
+# file = text file (e.g., wpa_supplicant.conf; note: the configuration file
+# path is given on command line, not here; this option is just used to
+# select the backend that allows configuration files to be used)
+# winreg = Windows registry (see win_example.reg for an example)
+CONFIG_BACKEND=file
+
+# Remove configuration write functionality (i.e., to allow the configuration
+# file to be updated based on runtime configuration changes). The runtime
+# configuration can still be changed, the changes are just not going to be
+# persistent over restarts. This option can be used to reduce code size by
+# about 3.5 kB.
+#CONFIG_NO_CONFIG_WRITE=y
+
+# Remove support for configuration blobs to reduce code size by about 1.5 kB.
+#CONFIG_NO_CONFIG_BLOBS=y
+
+# Select program entry point implementation:
+# main = UNIX/POSIX like main() function (default)
+# main_winsvc = Windows service (read parameters from registry)
+# main_none = Very basic example (development use only)
+#CONFIG_MAIN=main
+
+# Select wrapper for operating system and C library specific functions
+# unix = UNIX/POSIX like systems (default)
+# win32 = Windows systems
+# none = Empty template
+#CONFIG_OS=unix
+
+# Select event loop implementation
+# eloop = select() loop (default)
+# eloop_win = Windows events and WaitForMultipleObject() loop
+#CONFIG_ELOOP=eloop
+
+# Should we use poll instead of select? Select is used by default.
+#CONFIG_ELOOP_POLL=y
+
+# Should we use epoll instead of select? Select is used by default.
+#CONFIG_ELOOP_EPOLL=y
+
+# Select layer 2 packet implementation
+# linux = Linux packet socket (default)
+# pcap = libpcap/libdnet/WinPcap
+# freebsd = FreeBSD libpcap
+# winpcap = WinPcap with receive thread
+# ndis = Windows NDISUIO (note: requires CONFIG_USE_NDISUIO=y)
+# none = Empty template
+CONFIG_L2_PACKET=freebsd
+
+# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
+CONFIG_PEERKEY=y
+
+# IEEE 802.11w (management frame protection), also known as PMF
+# Driver support is also needed for IEEE 802.11w.
+#CONFIG_IEEE80211W=y
+
+# Select TLS implementation
+# openssl = OpenSSL (default)
+# gnutls = GnuTLS
+# internal = Internal TLSv1 implementation (experimental)
+# none = Empty template
+CONFIG_TLS=openssl
+
+# TLS-based EAP methods require at least TLS v1.0. Newer version of TLS (v1.1)
+# can be enabled to get a stronger construction of messages when block ciphers
+# are used. It should be noted that some existing TLS v1.0 -based
+# implementation may not be compatible with TLS v1.1 message (ClientHello is
+# sent prior to negotiating which version will be used)
+#CONFIG_TLSV11=y
+
+# TLS-based EAP methods require at least TLS v1.0. Newer version of TLS (v1.2)
+# can be enabled to enable use of stronger crypto algorithms. It should be
+# noted that some existing TLS v1.0 -based implementation may not be compatible
+# with TLS v1.2 message (ClientHello is sent prior to negotiating which version
+# will be used)
+CONFIG_TLSV12=y
+
+# If CONFIG_TLS=internal is used, additional library and include paths are
+# needed for LibTomMath. Alternatively, an integrated, minimal version of
+# LibTomMath can be used. See beginning of libtommath.c for details on benefits
+# and drawbacks of this option.
+#CONFIG_INTERNAL_LIBTOMMATH=y
+#ifndef CONFIG_INTERNAL_LIBTOMMATH
+#LTM_PATH=/usr/src/libtommath-0.39
+#CFLAGS += -I$(LTM_PATH)
+#LIBS += -L$(LTM_PATH)
+#LIBS_p += -L$(LTM_PATH)
+#endif
+# At the cost of about 4 kB of additional binary size, the internal LibTomMath
+# can be configured to include faster routines for exptmod, sqr, and div to
+# speed up DH and RSA calculation considerably
+#CONFIG_INTERNAL_LIBTOMMATH_FAST=y
+
+# Include NDIS event processing through WMI into wpa_supplicant/wpasvc.
+# This is only for Windows builds and requires WMI-related header files and
+# WbemUuid.Lib from Platform SDK even when building with MinGW.
+#CONFIG_NDIS_EVENTS_INTEGRATED=y
+#PLATFORMSDKLIB="/opt/Program Files/Microsoft Platform SDK/Lib"
+
+# Add support for old DBus control interface
+# (fi.epitest.hostap.WPASupplicant)
+#CONFIG_CTRL_IFACE_DBUS=y
+
+# Add support for new DBus control interface
+# (fi.w1.hostap.wpa_supplicant1)
+#CONFIG_CTRL_IFACE_DBUS_NEW=y
+
+# Add introspection support for new DBus control interface
+#CONFIG_CTRL_IFACE_DBUS_INTRO=y
+
+# Add support for loading EAP methods dynamically as shared libraries.
+# When this option is enabled, each EAP method can be either included
+# statically (CONFIG_EAP_<method>=y) or dynamically (CONFIG_EAP_<method>=dyn).
+# Dynamic EAP methods are build as shared objects (eap_*.so) and they need to
+# be loaded in the beginning of the wpa_supplicant configuration file
+# (see load_dynamic_eap parameter in the example file) before being used in
+# the network blocks.
+#
+# Note that some shared parts of EAP methods are included in the main program
+# and in order to be able to use dynamic EAP methods using these parts, the
+# main program must have been build with the EAP method enabled (=y or =dyn).
+# This means that EAP-TLS/PEAP/TTLS/FAST cannot be added as dynamic libraries
+# unless at least one of them was included in the main build to force inclusion
+# of the shared code. Similarly, at least one of EAP-SIM/AKA must be included
+# in the main build to be able to load these methods dynamically.
+#
+# Please also note that using dynamic libraries will increase the total binary
+# size. Thus, it may not be the best option for targets that have limited
+# amount of memory/flash.
+#CONFIG_DYNAMIC_EAP_METHODS=y
+
+# IEEE Std 802.11r-2008 (Fast BSS Transition)
+#CONFIG_IEEE80211R=y
+
+# Add support for writing debug log to a file (/tmp/wpa_supplicant-log-#.txt)
+#CONFIG_DEBUG_FILE=y
+
+# Send debug messages to syslog instead of stdout
+#CONFIG_DEBUG_SYSLOG=y
+# Set syslog facility for debug messages
+#CONFIG_DEBUG_SYSLOG_FACILITY=LOG_DAEMON
+
+# Add support for sending all debug messages (regardless of debug verbosity)
+# to the Linux kernel tracing facility. This helps debug the entire stack by
+# making it easy to record everything happening from the driver up into the
+# same file, e.g., using trace-cmd.
+#CONFIG_DEBUG_LINUX_TRACING=y
+
+# Add support for writing debug log to Android logcat instead of standard
+# output
+#CONFIG_ANDROID_LOG=y
+
+# Enable privilege separation (see README 'Privilege separation' for details)
+#CONFIG_PRIVSEP=y
+
+# Enable mitigation against certain attacks against TKIP by delaying Michael
+# MIC error reports by a random amount of time between 0 and 60 seconds
+#CONFIG_DELAYED_MIC_ERROR_REPORT=y
+
+# Enable tracing code for developer debugging
+# This tracks use of memory allocations and other registrations and reports
+# incorrect use with a backtrace of call (or allocation) location.
+#CONFIG_WPA_TRACE=y
+# For BSD, uncomment these.
+#LIBS += -lexecinfo
+#LIBS_p += -lexecinfo
+#LIBS_c += -lexecinfo
+
+# Use libbfd to get more details for developer debugging
+# This enables use of libbfd to get more detailed symbols for the backtraces
+# generated by CONFIG_WPA_TRACE=y.
+#CONFIG_WPA_TRACE_BFD=y
+# For BSD, uncomment these.
+#LIBS += -lbfd -liberty -lz
+#LIBS_p += -lbfd -liberty -lz
+#LIBS_c += -lbfd -liberty -lz
+
+# wpa_supplicant depends on strong random number generation being available
+# from the operating system. os_get_random() function is used to fetch random
+# data when needed, e.g., for key generation. On Linux and BSD systems, this
+# works by reading /dev/urandom. It should be noted that the OS entropy pool
+# needs to be properly initialized before wpa_supplicant is started. This is
+# important especially on embedded devices that do not have a hardware random
+# number generator and may by default start up with minimal entropy available
+# for random number generation.
+#
+# As a safety net, wpa_supplicant is by default trying to internally collect
+# additional entropy for generating random data to mix in with the data fetched
+# from the OS. This by itself is not considered to be very strong, but it may
+# help in cases where the system pool is not initialized properly. However, it
+# is very strongly recommended that the system pool is initialized with enough
+# entropy either by using hardware assisted random number generator or by
+# storing state over device reboots.
+#
+# wpa_supplicant can be configured to maintain its own entropy store over
+# restarts to enhance random number generation. This is not perfect, but it is
+# much more secure than using the same sequence of random numbers after every
+# reboot. This can be enabled with -e<entropy file> command line option. The
+# specified file needs to be readable and writable by wpa_supplicant.
+#
+# If the os_get_random() is known to provide strong random data (e.g., on
+# Linux/BSD, the board in question is known to have reliable source of random
+# data from /dev/urandom), the internal wpa_supplicant random pool can be
+# disabled. This will save some in binary size and CPU use. However, this
+# should only be considered for builds that are known to be used on devices
+# that meet the requirements described above.
+#CONFIG_NO_RANDOM_POOL=y
+
+# IEEE 802.11n (High Throughput) support (mainly for AP mode)
+#CONFIG_IEEE80211N=y
+
+# IEEE 802.11ac (Very High Throughput) support (mainly for AP mode)
+# (depends on CONFIG_IEEE80211N)
+#CONFIG_IEEE80211AC=y
+
+# Wireless Network Management (IEEE Std 802.11v-2011)
+# Note: This is experimental and not complete implementation.
+#CONFIG_WNM=y
+
+# Interworking (IEEE 802.11u)
+# This can be used to enable functionality to improve interworking with
+# external networks (GAS/ANQP to learn more about the networks and network
+# selection based on available credentials).
+#CONFIG_INTERWORKING=y
+
+# Hotspot 2.0
+#CONFIG_HS20=y
+
+# Disable roaming in wpa_supplicant
+#CONFIG_NO_ROAMING=y
+
+# AP mode operations with wpa_supplicant
+# This can be used for controlling AP mode operations with wpa_supplicant. It
+# should be noted that this is mainly aimed at simple cases like
+# WPA2-Personal while more complex configurations like WPA2-Enterprise with an
+# external RADIUS server can be supported with hostapd.
+#CONFIG_AP=y
+
+# P2P (Wi-Fi Direct)
+# This can be used to enable P2P support in wpa_supplicant. See README-P2P for
+# more information on P2P operations.
+#CONFIG_P2P=y
+
+# Enable TDLS support
+#CONFIG_TDLS=y
+
+# Wi-Fi Direct
+# This can be used to enable Wi-Fi Direct extensions for P2P using an external
+# program to control the additional information exchanges in the messages.
+#CONFIG_WIFI_DISPLAY=y
+
+# Autoscan
+# This can be used to enable automatic scan support in wpa_supplicant.
+# See wpa_supplicant.conf for more information on autoscan usage.
+#
+# Enabling directly a module will enable autoscan support.
+# For exponential module:
+#CONFIG_AUTOSCAN_EXPONENTIAL=y
+# For periodic module:
+#CONFIG_AUTOSCAN_PERIODIC=y
+
+# Password (and passphrase, etc.) backend for external storage
+# These optional mechanisms can be used to add support for storing passwords
+# and other secrets in external (to wpa_supplicant) location. This allows, for
+# example, operating system specific key storage to be used
+#
+# External password backend for testing purposes (developer use)
+#CONFIG_EXT_PASSWORD_TEST=y
+
+# Enable Fast Session Transfer (FST)
+#CONFIG_FST=y
+
+# Enable CLI commands for FST testing
+#CONFIG_FST_TEST=y
+
+# OS X builds. This is only for building eapol_test.
+#CONFIG_OSX=y
+
+# EAP-FAST used to require OpenSSL patches, so it's not on by default.
+# enable it.
+CONFIG_EAP_FAST=y
diff --git a/scripts/ci/eapol_test/config_linux b/scripts/ci/eapol_test/config_linux
new file mode 100644
index 0000000..e53e05a
--- /dev/null
+++ b/scripts/ci/eapol_test/config_linux
@@ -0,0 +1,520 @@
+# Example wpa_supplicant build time configuration
+#
+# This file lists the configuration options that are used when building the
+# hostapd binary. All lines starting with # are ignored. Configuration option
+# lines must be commented out complete, if they are not to be included, i.e.,
+# just setting VARIABLE=n is not disabling that variable.
+#
+# This file is included in Makefile, so variables like CFLAGS and LIBS can also
+# be modified from here. In most cases, these lines should use += in order not
+# to override previous values of the variables.
+
+CFLAGS += -g3 -O0 -Wno-error=deprecated-declarations $(EAPOL_TEST_CFLAGS)
+LIBS += $(EAPOL_TEST_LDFLAGS)
+
+#
+# Disable some warnings only against CLANG
+#
+ifeq ($(shell $(CC) -v 2>&1 | grep -c "clang version"), 1)
+CFLAGS += -Wno-error=ignored-qualifiers
+endif
+
+# Some Red Hat versions seem to include kerberos header files from OpenSSL, but
+# the kerberos files are not in the default include path. Following line can be
+# used to fix build issues on such systems (krb5.h not found).
+#CFLAGS += -I/usr/include/kerberos
+
+# Driver interface for generic Linux wireless extensions
+# Note: WEXT is deprecated in the current Linux kernel version and no new
+# functionality is added to it. nl80211-based interface is the new
+# replacement for WEXT and its use allows wpa_supplicant to properly control
+# the driver to improve existing functionality like roaming and to support new
+# functionality.
+CONFIG_DRIVER_WEXT=n
+
+# Driver interface for Linux drivers using the nl80211 kernel interface
+CONFIG_DRIVER_NL80211=n
+
+# QCA vendor extensions to nl80211
+CONFIG_DRIVER_NL80211_QCA=n
+
+# driver_nl80211.c requires libnl. If you are compiling it yourself
+# you may need to point hostapd to your version of libnl.
+#
+#CFLAGS += -I$<path to libnl include files>
+#LIBS += -L$<path to libnl library files>
+
+# Use libnl v2.0 (or 3.0) libraries.
+#CONFIG_LIBNL20=y
+
+# Use libnl 3.2 libraries (if this is selected, CONFIG_LIBNL20 is ignored)
+CONFIG_LIBNL32=y
+
+
+# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
+#CONFIG_DRIVER_BSD=y
+#CFLAGS += -I/usr/local/include
+#LIBS += -L/usr/local/lib
+#LIBS_p += -L/usr/local/lib
+#LIBS_c += -L/usr/local/lib
+
+# Driver interface for Windows NDIS
+#CONFIG_DRIVER_NDIS=y
+#CFLAGS += -I/usr/include/w32api/ddk
+#LIBS += -L/usr/local/lib
+# For native build using mingw
+#CONFIG_NATIVE_WINDOWS=y
+# Additional directories for cross-compilation on Linux host for mingw target
+#CFLAGS += -I/opt/mingw/mingw32/include/ddk
+#LIBS += -L/opt/mingw/mingw32/lib
+#CC=mingw32-gcc
+# By default, driver_ndis uses WinPcap for low-level operations. This can be
+# replaced with the following option which replaces WinPcap calls with NDISUIO.
+# However, this requires that WZC is disabled (net stop wzcsvc) before starting
+# wpa_supplicant.
+# CONFIG_USE_NDISUIO=y
+
+# Driver interface for wired Ethernet drivers
+CONFIG_DRIVER_WIRED=y
+
+# Driver interface for the Broadcom RoboSwitch family
+#CONFIG_DRIVER_ROBOSWITCH=y
+
+# Driver interface for no driver (e.g., WPS ER only)
+#CONFIG_DRIVER_NONE=y
+
+# Solaris libraries
+#LIBS += -lsocket -ldlpi -lnsl
+#LIBS_c += -lsocket
+
+# Enable IEEE 802.1X Supplicant (automatically included if any EAP method is
+# included)
+CONFIG_IEEE8021X_EAPOL=y
+
+# EAP-MD5
+CONFIG_EAP_MD5=y
+
+# EAP-MSCHAPv2
+CONFIG_EAP_MSCHAPV2=y
+
+# EAP-TLS
+CONFIG_EAP_TLS=y
+
+# EAL-PEAP
+CONFIG_EAP_PEAP=y
+
+# EAP-TTLS
+CONFIG_EAP_TTLS=y
+
+# EAP-FAST
+# Note: If OpenSSL is used as the TLS library, OpenSSL 1.0 or newer is needed
+# for EAP-FAST support. Older OpenSSL releases would need to be patched, e.g.,
+# with openssl-0.9.8x-tls-extensions.patch, to add the needed functions.
+CONFIG_EAP_FAST=y
+
+# EAP-GTC
+CONFIG_EAP_GTC=y
+
+# EAP-OTP
+CONFIG_EAP_OTP=y
+
+# EAP-SIM (enable CONFIG_PCSC, if EAP-SIM is used)
+CONFIG_EAP_SIM=y
+
+# EAP-PSK (experimental; this is _not_ needed for WPA-PSK)
+CONFIG_EAP_PSK=y
+
+# EAP-pwd (secure authentication using only a password)
+CONFIG_EAP_PWD=y
+
+# EAP-PAX
+CONFIG_EAP_PAX=y
+
+# LEAP
+CONFIG_EAP_LEAP=n
+
+# EAP-AKA (enable CONFIG_PCSC, if EAP-AKA is used)
+CONFIG_EAP_AKA=y
+
+# EAP-AKA' (enable CONFIG_PCSC, if EAP-AKA' is used).
+# This requires CONFIG_EAP_AKA to be enabled, too.
+CONFIG_EAP_AKA_PRIME=y
+
+# Enable USIM simulator (Milenage) for EAP-AKA
+CONFIG_USIM_SIMULATOR=y
+
+# Enable SIM simulator (Milenage) for EAP-SIM
+CONFIG_SIM_SIMULATOR=y
+
+# EAP-SAKE
+CONFIG_EAP_SAKE=y
+
+# EAP-GPSK
+CONFIG_EAP_GPSK=y
+# Include support for optional SHA256 cipher suite in EAP-GPSK
+CONFIG_EAP_GPSK_SHA256=y
+
+# EAP-TNC and related Trusted Network Connect support (experimental)
+CONFIG_EAP_TNC=y
+
+# Wi-Fi Protected Setup (WPS)
+#CONFIG_WPS=y
+# Enable WPS external registrar functionality
+#CONFIG_WPS_ER=y
+# Disable credentials for an open network by default when acting as a WPS
+# registrar.
+#CONFIG_WPS_REG_DISABLE_OPEN=y
+# Enable WPS support with NFC config method
+#CONFIG_WPS_NFC=y
+
+# EAP-IKEv2
+CONFIG_EAP_IKEV2=y
+
+# EAP-EKE
+CONFIG_EAP_EKE=y
+
+# PKCS#12 (PFX) support (used to read private key and certificate file from
+# a file that usually has extension .p12 or .pfx)
+CONFIG_PKCS12=y
+
+# Smartcard support (i.e., private key on a smartcard), e.g., with openssl
+# engine.
+CONFIG_SMARTCARD=y
+
+# PC/SC interface for smartcards (USIM, GSM SIM)
+# Enable this if EAP-SIM or EAP-AKA is included
+#CONFIG_PCSC=y
+
+# Support HT overrides (disable HT/HT40, mask MCS rates, etc.)
+#CONFIG_HT_OVERRIDES=y
+
+# Support VHT overrides (disable VHT, mask MCS rates, etc.)
+#CONFIG_VHT_OVERRIDES=y
+
+# Development testing
+CONFIG_EAPOL_TEST=y
+
+# Select control interface backend for external programs, e.g, wpa_cli:
+# unix = UNIX domain sockets (default for Linux/*BSD)
+# udp = UDP sockets using localhost (127.0.0.1)
+# udp6 = UDP IPv6 sockets using localhost (::1)
+# named_pipe = Windows Named Pipe (default for Windows)
+# udp-remote = UDP sockets with remote access (only for tests systems/purpose)
+# udp6-remote = UDP IPv6 sockets with remote access (only for tests purpose)
+# y = use default (backwards compatibility)
+# If this option is commented out, control interface is not included in the
+# build.
+CONFIG_CTRL_IFACE=y
+
+# Include support for GNU Readline and History Libraries in wpa_cli.
+# When building a wpa_cli binary for distribution, please note that these
+# libraries are licensed under GPL and as such, BSD license may not apply for
+# the resulting binary.
+#CONFIG_READLINE=y
+
+# Include internal line edit mode in wpa_cli. This can be used as a replacement
+# for GNU Readline to provide limited command line editing and history support.
+#CONFIG_WPA_CLI_EDIT=y
+
+# Remove debugging code that is printing out debug message to stdout.
+# This can be used to reduce the size of the wpa_supplicant considerably
+# if debugging code is not needed. The size reduction can be around 35%
+# (e.g., 90 kB).
+#CONFIG_NO_STDOUT_DEBUG=y
+
+# Remove WPA support, e.g., for wired-only IEEE 802.1X supplicant, to save
+# 35-50 kB in code size.
+#CONFIG_NO_WPA=y
+
+# Remove IEEE 802.11i/WPA-Personal ASCII passphrase support
+# This option can be used to reduce code size by removing support for
+# converting ASCII passphrases into PSK. If this functionality is removed, the
+# PSK can only be configured as the 64-octet hexstring (e.g., from
+# wpa_passphrase). This saves about 0.5 kB in code size.
+#CONFIG_NO_WPA_PASSPHRASE=y
+
+# Disable scan result processing (ap_mode=1) to save code size by about 1 kB.
+# This can be used if ap_scan=1 mode is never enabled.
+#CONFIG_NO_SCAN_PROCESSING=y
+
+# Select configuration backend:
+# file = text file (e.g., wpa_supplicant.conf; note: the configuration file
+# path is given on command line, not here; this option is just used to
+# select the backend that allows configuration files to be used)
+# winreg = Windows registry (see win_example.reg for an example)
+CONFIG_BACKEND=file
+
+# Remove configuration write functionality (i.e., to allow the configuration
+# file to be updated based on runtime configuration changes). The runtime
+# configuration can still be changed, the changes are just not going to be
+# persistent over restarts. This option can be used to reduce code size by
+# about 3.5 kB.
+#CONFIG_NO_CONFIG_WRITE=y
+
+# Remove support for configuration blobs to reduce code size by about 1.5 kB.
+#CONFIG_NO_CONFIG_BLOBS=y
+
+# Select program entry point implementation:
+# main = UNIX/POSIX like main() function (default)
+# main_winsvc = Windows service (read parameters from registry)
+# main_none = Very basic example (development use only)
+#CONFIG_MAIN=main
+
+# Select wrapper for operating system and C library specific functions
+# unix = UNIX/POSIX like systems (default)
+# win32 = Windows systems
+# none = Empty template
+#CONFIG_OS=unix
+
+# Select event loop implementation
+# eloop = select() loop (default)
+# eloop_win = Windows events and WaitForMultipleObject() loop
+#CONFIG_ELOOP=eloop
+
+# Should we use poll instead of select? Select is used by default.
+#CONFIG_ELOOP_POLL=y
+
+# Should we use epoll instead of select? Select is used by default.
+#CONFIG_ELOOP_EPOLL=y
+
+# Select layer 2 packet implementation
+# linux = Linux packet socket (default)
+# pcap = libpcap/libdnet/WinPcap
+# freebsd = FreeBSD libpcap
+# winpcap = WinPcap with receive thread
+# ndis = Windows NDISUIO (note: requires CONFIG_USE_NDISUIO=y)
+# none = Empty template
+CONFIG_L2_PACKET=linux
+
+# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
+CONFIG_PEERKEY=y
+
+# IEEE 802.11w (management frame protection), also known as PMF
+# Driver support is also needed for IEEE 802.11w.
+#CONFIG_IEEE80211W=y
+
+# Select TLS implementation
+# openssl = OpenSSL (default)
+# gnutls = GnuTLS
+# internal = Internal TLSv1 implementation (experimental)
+# none = Empty template
+CONFIG_TLS=openssl
+
+# TLS-based EAP methods require at least TLS v1.0. Newer version of TLS (v1.1)
+# can be enabled to get a stronger construction of messages when block ciphers
+# are used. It should be noted that some existing TLS v1.0 -based
+# implementation may not be compatible with TLS v1.1 message (ClientHello is
+# sent prior to negotiating which version will be used)
+#CONFIG_TLSV11=y
+
+# TLS-based EAP methods require at least TLS v1.0. Newer version of TLS (v1.2)
+# can be enabled to enable use of stronger crypto algorithms. It should be
+# noted that some existing TLS v1.0 -based implementation may not be compatible
+# with TLS v1.2 message (ClientHello is sent prior to negotiating which version
+# will be used)
+CONFIG_TLSV12=y
+
+# If CONFIG_TLS=internal is used, additional library and include paths are
+# needed for LibTomMath. Alternatively, an integrated, minimal version of
+# LibTomMath can be used. See beginning of libtommath.c for details on benefits
+# and drawbacks of this option.
+#CONFIG_INTERNAL_LIBTOMMATH=y
+#ifndef CONFIG_INTERNAL_LIBTOMMATH
+#LTM_PATH=/usr/src/libtommath-0.39
+#CFLAGS += -I$(LTM_PATH)
+#LIBS += -L$(LTM_PATH)
+#LIBS_p += -L$(LTM_PATH)
+#endif
+# At the cost of about 4 kB of additional binary size, the internal LibTomMath
+# can be configured to include faster routines for exptmod, sqr, and div to
+# speed up DH and RSA calculation considerably
+#CONFIG_INTERNAL_LIBTOMMATH_FAST=y
+
+# Include NDIS event processing through WMI into wpa_supplicant/wpasvc.
+# This is only for Windows builds and requires WMI-related header files and
+# WbemUuid.Lib from Platform SDK even when building with MinGW.
+#CONFIG_NDIS_EVENTS_INTEGRATED=y
+#PLATFORMSDKLIB="/opt/Program Files/Microsoft Platform SDK/Lib"
+
+# Add support for old DBus control interface
+# (fi.epitest.hostap.WPASupplicant)
+#CONFIG_CTRL_IFACE_DBUS=y
+
+# Add support for new DBus control interface
+# (fi.w1.hostap.wpa_supplicant1)
+#CONFIG_CTRL_IFACE_DBUS_NEW=y
+
+# Add introspection support for new DBus control interface
+#CONFIG_CTRL_IFACE_DBUS_INTRO=y
+
+# Add support for loading EAP methods dynamically as shared libraries.
+# When this option is enabled, each EAP method can be either included
+# statically (CONFIG_EAP_<method>=y) or dynamically (CONFIG_EAP_<method>=dyn).
+# Dynamic EAP methods are build as shared objects (eap_*.so) and they need to
+# be loaded in the beginning of the wpa_supplicant configuration file
+# (see load_dynamic_eap parameter in the example file) before being used in
+# the network blocks.
+#
+# Note that some shared parts of EAP methods are included in the main program
+# and in order to be able to use dynamic EAP methods using these parts, the
+# main program must have been build with the EAP method enabled (=y or =dyn).
+# This means that EAP-TLS/PEAP/TTLS/FAST cannot be added as dynamic libraries
+# unless at least one of them was included in the main build to force inclusion
+# of the shared code. Similarly, at least one of EAP-SIM/AKA must be included
+# in the main build to be able to load these methods dynamically.
+#
+# Please also note that using dynamic libraries will increase the total binary
+# size. Thus, it may not be the best option for targets that have limited
+# amount of memory/flash.
+#CONFIG_DYNAMIC_EAP_METHODS=y
+
+# IEEE Std 802.11r-2008 (Fast BSS Transition)
+#CONFIG_IEEE80211R=y
+
+# Add support for writing debug log to a file (/tmp/wpa_supplicant-log-#.txt)
+#CONFIG_DEBUG_FILE=y
+
+# Send debug messages to syslog instead of stdout
+#CONFIG_DEBUG_SYSLOG=y
+# Set syslog facility for debug messages
+#CONFIG_DEBUG_SYSLOG_FACILITY=LOG_DAEMON
+
+# Add support for sending all debug messages (regardless of debug verbosity)
+# to the Linux kernel tracing facility. This helps debug the entire stack by
+# making it easy to record everything happening from the driver up into the
+# same file, e.g., using trace-cmd.
+#CONFIG_DEBUG_LINUX_TRACING=y
+
+# Add support for writing debug log to Android logcat instead of standard
+# output
+#CONFIG_ANDROID_LOG=y
+
+# Enable privilege separation (see README 'Privilege separation' for details)
+#CONFIG_PRIVSEP=y
+
+# Enable mitigation against certain attacks against TKIP by delaying Michael
+# MIC error reports by a random amount of time between 0 and 60 seconds
+#CONFIG_DELAYED_MIC_ERROR_REPORT=y
+
+# Enable tracing code for developer debugging
+# This tracks use of memory allocations and other registrations and reports
+# incorrect use with a backtrace of call (or allocation) location.
+#CONFIG_WPA_TRACE=y
+# For BSD, uncomment these.
+#LIBS += -lexecinfo
+#LIBS_p += -lexecinfo
+#LIBS_c += -lexecinfo
+
+# Use libbfd to get more details for developer debugging
+# This enables use of libbfd to get more detailed symbols for the backtraces
+# generated by CONFIG_WPA_TRACE=y.
+#CONFIG_WPA_TRACE_BFD=y
+# For BSD, uncomment these.
+#LIBS += -lbfd -liberty -lz
+#LIBS_p += -lbfd -liberty -lz
+#LIBS_c += -lbfd -liberty -lz
+
+# wpa_supplicant depends on strong random number generation being available
+# from the operating system. os_get_random() function is used to fetch random
+# data when needed, e.g., for key generation. On Linux and BSD systems, this
+# works by reading /dev/urandom. It should be noted that the OS entropy pool
+# needs to be properly initialized before wpa_supplicant is started. This is
+# important especially on embedded devices that do not have a hardware random
+# number generator and may by default start up with minimal entropy available
+# for random number generation.
+#
+# As a safety net, wpa_supplicant is by default trying to internally collect
+# additional entropy for generating random data to mix in with the data fetched
+# from the OS. This by itself is not considered to be very strong, but it may
+# help in cases where the system pool is not initialized properly. However, it
+# is very strongly recommended that the system pool is initialized with enough
+# entropy either by using hardware assisted random number generator or by
+# storing state over device reboots.
+#
+# wpa_supplicant can be configured to maintain its own entropy store over
+# restarts to enhance random number generation. This is not perfect, but it is
+# much more secure than using the same sequence of random numbers after every
+# reboot. This can be enabled with -e<entropy file> command line option. The
+# specified file needs to be readable and writable by wpa_supplicant.
+#
+# If the os_get_random() is known to provide strong random data (e.g., on
+# Linux/BSD, the board in question is known to have reliable source of random
+# data from /dev/urandom), the internal wpa_supplicant random pool can be
+# disabled. This will save some in binary size and CPU use. However, this
+# should only be considered for builds that are known to be used on devices
+# that meet the requirements described above.
+#CONFIG_NO_RANDOM_POOL=y
+
+# IEEE 802.11n (High Throughput) support (mainly for AP mode)
+#CONFIG_IEEE80211N=y
+
+# IEEE 802.11ac (Very High Throughput) support (mainly for AP mode)
+# (depends on CONFIG_IEEE80211N)
+#CONFIG_IEEE80211AC=y
+
+# Wireless Network Management (IEEE Std 802.11v-2011)
+# Note: This is experimental and not complete implementation.
+#CONFIG_WNM=y
+
+# Interworking (IEEE 802.11u)
+# This can be used to enable functionality to improve interworking with
+# external networks (GAS/ANQP to learn more about the networks and network
+# selection based on available credentials).
+#CONFIG_INTERWORKING=y
+
+# Hotspot 2.0
+#CONFIG_HS20=y
+
+# Disable roaming in wpa_supplicant
+#CONFIG_NO_ROAMING=y
+
+# AP mode operations with wpa_supplicant
+# This can be used for controlling AP mode operations with wpa_supplicant. It
+# should be noted that this is mainly aimed at simple cases like
+# WPA2-Personal while more complex configurations like WPA2-Enterprise with an
+# external RADIUS server can be supported with hostapd.
+#CONFIG_AP=y
+
+# P2P (Wi-Fi Direct)
+# This can be used to enable P2P support in wpa_supplicant. See README-P2P for
+# more information on P2P operations.
+#CONFIG_P2P=y
+
+# Enable TDLS support
+#CONFIG_TDLS=y
+
+# Wi-Fi Direct
+# This can be used to enable Wi-Fi Direct extensions for P2P using an external
+# program to control the additional information exchanges in the messages.
+#CONFIG_WIFI_DISPLAY=y
+
+# Autoscan
+# This can be used to enable automatic scan support in wpa_supplicant.
+# See wpa_supplicant.conf for more information on autoscan usage.
+#
+# Enabling directly a module will enable autoscan support.
+# For exponential module:
+#CONFIG_AUTOSCAN_EXPONENTIAL=y
+# For periodic module:
+#CONFIG_AUTOSCAN_PERIODIC=y
+
+# Password (and passphrase, etc.) backend for external storage
+# These optional mechanisms can be used to add support for storing passwords
+# and other secrets in external (to wpa_supplicant) location. This allows, for
+# example, operating system specific key storage to be used
+#
+# External password backend for testing purposes (developer use)
+#CONFIG_EXT_PASSWORD_TEST=y
+
+# Enable Fast Session Transfer (FST)
+#CONFIG_FST=y
+
+# Enable CLI commands for FST testing
+#CONFIG_FST_TEST=y
+
+# OS X builds. This is only for building eapol_test.
+#CONFIG_OSX=y
+
+# EAP-FAST used to require OpenSSL patches, so it's not on by default.
+# enable it.
+CONFIG_EAP_FAST=y
diff --git a/scripts/ci/eapol_test/config_osx b/scripts/ci/eapol_test/config_osx
new file mode 100644
index 0000000..01dd020
--- /dev/null
+++ b/scripts/ci/eapol_test/config_osx
@@ -0,0 +1,515 @@
+# Example wpa_supplicant build time configuration
+#
+# This file lists the configuration options that are used when building the
+# hostapd binary. All lines starting with # are ignored. Configuration option
+# lines must be commented out complete, if they are not to be included, i.e.,
+# just setting VARIABLE=n is not disabling that variable.
+#
+# This file is included in Makefile, so variables like CFLAGS and LIBS can also
+# be modified from here. In most cases, these lines should use += in order not
+# to override previous values of the variables.
+
+CFLAGS += -g3 -O0 -Wno-error=deprecated-declarations -Wno-error=void-pointer-to-enum-cast $(EAPOL_TEST_CFLAGS)
+CFLAGS += -I/usr/local/opt/openssl/include -I/opt/homebrew/opt/openssl/include -I/usr/local/include/openssl
+
+LIBS += $(EAPOL_TEST_LDFLAGS) -L/usr/local/opt/openssl/lib -L/opt/homebrew/opt/openssl/lib -L/usr/local/lib
+
+# Some Red Hat versions seem to include kerberos header files from OpenSSL, but
+# the kerberos files are not in the default include path. Following line can be
+# used to fix build issues on such systems (krb5.h not found).
+#CFLAGS += -I/usr/include/kerberos
+
+# Driver interface for generic Linux wireless extensions
+# Note: WEXT is deprecated in the current Linux kernel version and no new
+# functionality is added to it. nl80211-based interface is the new
+# replacement for WEXT and its use allows wpa_supplicant to properly control
+# the driver to improve existing functionality like roaming and to support new
+# functionality.
+CONFIG_DRIVER_WEXT=n
+
+# Driver interface for Linux drivers using the nl80211 kernel interface
+CONFIG_DRIVER_NL80211=n
+
+# QCA vendor extensions to nl80211
+CONFIG_DRIVER_NL80211_QCA=n
+
+# driver_nl80211.c requires libnl. If you are compiling it yourself
+# you may need to point hostapd to your version of libnl.
+#
+#CFLAGS += -I$<path to libnl include files>
+#LIBS += -L$<path to libnl library files>
+
+# Use libnl v2.0 (or 3.0) libraries.
+#CONFIG_LIBNL20=y
+
+# Use libnl 3.2 libraries (if this is selected, CONFIG_LIBNL20 is ignored)
+#CONFIG_LIBNL32=y
+
+
+# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
+#CONFIG_DRIVER_BSD=y
+#CFLAGS += -I/usr/local/include
+#LIBS += -L/usr/local/lib
+#LIBS_p += -L/usr/local/lib
+#LIBS_c += -L/usr/local/lib
+
+# Driver interface for Windows NDIS
+#CONFIG_DRIVER_NDIS=y
+#CFLAGS += -I/usr/include/w32api/ddk
+#LIBS += -L/usr/local/lib
+# For native build using mingw
+#CONFIG_NATIVE_WINDOWS=y
+# Additional directories for cross-compilation on Linux host for mingw target
+#CFLAGS += -I/opt/mingw/mingw32/include/ddk
+#LIBS += -L/opt/mingw/mingw32/lib
+#CC=mingw32-gcc
+# By default, driver_ndis uses WinPcap for low-level operations. This can be
+# replaced with the following option which replaces WinPcap calls with NDISUIO.
+# However, this requires that WZC is disabled (net stop wzcsvc) before starting
+# wpa_supplicant.
+# CONFIG_USE_NDISUIO=y
+
+# Driver interface for wired Ethernet drivers
+CONFIG_DRIVER_WIRED=y
+
+# Driver interface for the Broadcom RoboSwitch family
+#CONFIG_DRIVER_ROBOSWITCH=y
+
+# Driver interface for no driver (e.g., WPS ER only)
+#CONFIG_DRIVER_NONE=y
+
+# Solaris libraries
+#LIBS += -lsocket -ldlpi -lnsl
+#LIBS_c += -lsocket
+
+# Enable IEEE 802.1X Supplicant (automatically included if any EAP method is
+# included)
+CONFIG_IEEE8021X_EAPOL=y
+
+# EAP-MD5
+CONFIG_EAP_MD5=y
+
+# EAP-MSCHAPv2
+CONFIG_EAP_MSCHAPV2=y
+
+# EAP-TLS
+CONFIG_EAP_TLS=y
+
+# EAL-PEAP
+CONFIG_EAP_PEAP=y
+
+# EAP-TTLS
+CONFIG_EAP_TTLS=y
+
+# EAP-FAST
+# Note: If OpenSSL is used as the TLS library, OpenSSL 1.0 or newer is needed
+# for EAP-FAST support. Older OpenSSL releases would need to be patched, e.g.,
+# with openssl-0.9.8x-tls-extensions.patch, to add the needed functions.
+CONFIG_EAP_FAST=y
+
+# EAP-GTC
+CONFIG_EAP_GTC=y
+
+# EAP-OTP
+CONFIG_EAP_OTP=y
+
+# EAP-SIM (enable CONFIG_PCSC, if EAP-SIM is used)
+CONFIG_EAP_SIM=y
+
+# EAP-PSK (experimental; this is _not_ needed for WPA-PSK)
+CONFIG_EAP_PSK=y
+
+# EAP-pwd (secure authentication using only a password)
+CONFIG_EAP_PWD=y
+
+# EAP-PAX
+CONFIG_EAP_PAX=y
+
+# LEAP
+CONFIG_EAP_LEAP=n
+
+# EAP-AKA (enable CONFIG_PCSC, if EAP-AKA is used)
+CONFIG_EAP_AKA=y
+
+# EAP-AKA' (enable CONFIG_PCSC, if EAP-AKA' is used).
+# This requires CONFIG_EAP_AKA to be enabled, too.
+CONFIG_EAP_AKA_PRIME=y
+
+# Enable USIM simulator (Milenage) for EAP-AKA
+CONFIG_USIM_SIMULATOR=y
+
+# Enable SIM simulator (Milenage) for EAP-SIM
+CONFIG_SIM_SIMULATOR=y
+
+# EAP-SAKE
+CONFIG_EAP_SAKE=y
+
+# EAP-GPSK
+CONFIG_EAP_GPSK=y
+# Include support for optional SHA256 cipher suite in EAP-GPSK
+CONFIG_EAP_GPSK_SHA256=y
+
+# EAP-TNC and related Trusted Network Connect support (experimental)
+CONFIG_EAP_TNC=y
+
+# Wi-Fi Protected Setup (WPS)
+#CONFIG_WPS=y
+# Enable WPS external registrar functionality
+#CONFIG_WPS_ER=y
+# Disable credentials for an open network by default when acting as a WPS
+# registrar.
+#CONFIG_WPS_REG_DISABLE_OPEN=y
+# Enable WPS support with NFC config method
+#CONFIG_WPS_NFC=y
+
+# EAP-IKEv2
+CONFIG_EAP_IKEV2=y
+
+# EAP-EKE
+CONFIG_EAP_EKE=y
+
+# PKCS#12 (PFX) support (used to read private key and certificate file from
+# a file that usually has extension .p12 or .pfx)
+CONFIG_PKCS12=y
+
+# Smartcard support (i.e., private key on a smartcard), e.g., with openssl
+# engine.
+CONFIG_SMARTCARD=y
+
+# PC/SC interface for smartcards (USIM, GSM SIM)
+# Enable this if EAP-SIM or EAP-AKA is included
+#CONFIG_PCSC=y
+
+# Support HT overrides (disable HT/HT40, mask MCS rates, etc.)
+#CONFIG_HT_OVERRIDES=y
+
+# Support VHT overrides (disable VHT, mask MCS rates, etc.)
+#CONFIG_VHT_OVERRIDES=y
+
+# Development testing
+CONFIG_EAPOL_TEST=y
+
+# Select control interface backend for external programs, e.g, wpa_cli:
+# unix = UNIX domain sockets (default for Linux/*BSD)
+# udp = UDP sockets using localhost (127.0.0.1)
+# udp6 = UDP IPv6 sockets using localhost (::1)
+# named_pipe = Windows Named Pipe (default for Windows)
+# udp-remote = UDP sockets with remote access (only for tests systems/purpose)
+# udp6-remote = UDP IPv6 sockets with remote access (only for tests purpose)
+# y = use default (backwards compatibility)
+# If this option is commented out, control interface is not included in the
+# build.
+CONFIG_CTRL_IFACE=y
+
+# Include support for GNU Readline and History Libraries in wpa_cli.
+# When building a wpa_cli binary for distribution, please note that these
+# libraries are licensed under GPL and as such, BSD license may not apply for
+# the resulting binary.
+#CONFIG_READLINE=y
+
+# Include internal line edit mode in wpa_cli. This can be used as a replacement
+# for GNU Readline to provide limited command line editing and history support.
+#CONFIG_WPA_CLI_EDIT=y
+
+# Remove debugging code that is printing out debug message to stdout.
+# This can be used to reduce the size of the wpa_supplicant considerably
+# if debugging code is not needed. The size reduction can be around 35%
+# (e.g., 90 kB).
+#CONFIG_NO_STDOUT_DEBUG=y
+
+# Remove WPA support, e.g., for wired-only IEEE 802.1X supplicant, to save
+# 35-50 kB in code size.
+#CONFIG_NO_WPA=y
+
+# Remove IEEE 802.11i/WPA-Personal ASCII passphrase support
+# This option can be used to reduce code size by removing support for
+# converting ASCII passphrases into PSK. If this functionality is removed, the
+# PSK can only be configured as the 64-octet hexstring (e.g., from
+# wpa_passphrase). This saves about 0.5 kB in code size.
+#CONFIG_NO_WPA_PASSPHRASE=y
+
+# Disable scan result processing (ap_mode=1) to save code size by about 1 kB.
+# This can be used if ap_scan=1 mode is never enabled.
+#CONFIG_NO_SCAN_PROCESSING=y
+
+# Select configuration backend:
+# file = text file (e.g., wpa_supplicant.conf; note: the configuration file
+# path is given on command line, not here; this option is just used to
+# select the backend that allows configuration files to be used)
+# winreg = Windows registry (see win_example.reg for an example)
+CONFIG_BACKEND=file
+
+# Remove configuration write functionality (i.e., to allow the configuration
+# file to be updated based on runtime configuration changes). The runtime
+# configuration can still be changed, the changes are just not going to be
+# persistent over restarts. This option can be used to reduce code size by
+# about 3.5 kB.
+#CONFIG_NO_CONFIG_WRITE=y
+
+# Remove support for configuration blobs to reduce code size by about 1.5 kB.
+#CONFIG_NO_CONFIG_BLOBS=y
+
+# Select program entry point implementation:
+# main = UNIX/POSIX like main() function (default)
+# main_winsvc = Windows service (read parameters from registry)
+# main_none = Very basic example (development use only)
+#CONFIG_MAIN=main
+
+# Select wrapper for operating system and C library specific functions
+# unix = UNIX/POSIX like systems (default)
+# win32 = Windows systems
+# none = Empty template
+#CONFIG_OS=unix
+
+# Select event loop implementation
+# eloop = select() loop (default)
+# eloop_win = Windows events and WaitForMultipleObject() loop
+#CONFIG_ELOOP=eloop
+
+# Should we use poll instead of select? Select is used by default.
+#CONFIG_ELOOP_POLL=y
+
+# Should we use epoll instead of select? Select is used by default.
+#CONFIG_ELOOP_EPOLL=y
+
+# Select layer 2 packet implementation
+# linux = Linux packet socket (default)
+# pcap = libpcap/libdnet/WinPcap
+# freebsd = FreeBSD libpcap
+# winpcap = WinPcap with receive thread
+# ndis = Windows NDISUIO (note: requires CONFIG_USE_NDISUIO=y)
+# none = Empty template
+CONFIG_L2_PACKET=freebsd
+
+# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
+CONFIG_PEERKEY=y
+
+# IEEE 802.11w (management frame protection), also known as PMF
+# Driver support is also needed for IEEE 802.11w.
+#CONFIG_IEEE80211W=y
+
+# Select TLS implementation
+# openssl = OpenSSL (default)
+# gnutls = GnuTLS
+# internal = Internal TLSv1 implementation (experimental)
+# none = Empty template
+CONFIG_TLS=openssl
+
+# TLS-based EAP methods require at least TLS v1.0. Newer version of TLS (v1.1)
+# can be enabled to get a stronger construction of messages when block ciphers
+# are used. It should be noted that some existing TLS v1.0 -based
+# implementation may not be compatible with TLS v1.1 message (ClientHello is
+# sent prior to negotiating which version will be used)
+#CONFIG_TLSV11=y
+
+# TLS-based EAP methods require at least TLS v1.0. Newer version of TLS (v1.2)
+# can be enabled to enable use of stronger crypto algorithms. It should be
+# noted that some existing TLS v1.0 -based implementation may not be compatible
+# with TLS v1.2 message (ClientHello is sent prior to negotiating which version
+# will be used)
+CONFIG_TLSV12=y
+
+# If CONFIG_TLS=internal is used, additional library and include paths are
+# needed for LibTomMath. Alternatively, an integrated, minimal version of
+# LibTomMath can be used. See beginning of libtommath.c for details on benefits
+# and drawbacks of this option.
+#CONFIG_INTERNAL_LIBTOMMATH=y
+#ifndef CONFIG_INTERNAL_LIBTOMMATH
+#LTM_PATH=/usr/src/libtommath-0.39
+#CFLAGS += -I$(LTM_PATH)
+#LIBS += -L$(LTM_PATH)
+#LIBS_p += -L$(LTM_PATH)
+#endif
+# At the cost of about 4 kB of additional binary size, the internal LibTomMath
+# can be configured to include faster routines for exptmod, sqr, and div to
+# speed up DH and RSA calculation considerably
+#CONFIG_INTERNAL_LIBTOMMATH_FAST=y
+
+# Include NDIS event processing through WMI into wpa_supplicant/wpasvc.
+# This is only for Windows builds and requires WMI-related header files and
+# WbemUuid.Lib from Platform SDK even when building with MinGW.
+#CONFIG_NDIS_EVENTS_INTEGRATED=y
+#PLATFORMSDKLIB="/opt/Program Files/Microsoft Platform SDK/Lib"
+
+# Add support for old DBus control interface
+# (fi.epitest.hostap.WPASupplicant)
+#CONFIG_CTRL_IFACE_DBUS=y
+
+# Add support for new DBus control interface
+# (fi.w1.hostap.wpa_supplicant1)
+#CONFIG_CTRL_IFACE_DBUS_NEW=y
+
+# Add introspection support for new DBus control interface
+#CONFIG_CTRL_IFACE_DBUS_INTRO=y
+
+# Add support for loading EAP methods dynamically as shared libraries.
+# When this option is enabled, each EAP method can be either included
+# statically (CONFIG_EAP_<method>=y) or dynamically (CONFIG_EAP_<method>=dyn).
+# Dynamic EAP methods are build as shared objects (eap_*.so) and they need to
+# be loaded in the beginning of the wpa_supplicant configuration file
+# (see load_dynamic_eap parameter in the example file) before being used in
+# the network blocks.
+#
+# Note that some shared parts of EAP methods are included in the main program
+# and in order to be able to use dynamic EAP methods using these parts, the
+# main program must have been build with the EAP method enabled (=y or =dyn).
+# This means that EAP-TLS/PEAP/TTLS/FAST cannot be added as dynamic libraries
+# unless at least one of them was included in the main build to force inclusion
+# of the shared code. Similarly, at least one of EAP-SIM/AKA must be included
+# in the main build to be able to load these methods dynamically.
+#
+# Please also note that using dynamic libraries will increase the total binary
+# size. Thus, it may not be the best option for targets that have limited
+# amount of memory/flash.
+#CONFIG_DYNAMIC_EAP_METHODS=y
+
+# IEEE Std 802.11r-2008 (Fast BSS Transition)
+#CONFIG_IEEE80211R=y
+
+# Add support for writing debug log to a file (/tmp/wpa_supplicant-log-#.txt)
+#CONFIG_DEBUG_FILE=y
+
+# Send debug messages to syslog instead of stdout
+#CONFIG_DEBUG_SYSLOG=y
+# Set syslog facility for debug messages
+#CONFIG_DEBUG_SYSLOG_FACILITY=LOG_DAEMON
+
+# Add support for sending all debug messages (regardless of debug verbosity)
+# to the Linux kernel tracing facility. This helps debug the entire stack by
+# making it easy to record everything happening from the driver up into the
+# same file, e.g., using trace-cmd.
+#CONFIG_DEBUG_LINUX_TRACING=y
+
+# Add support for writing debug log to Android logcat instead of standard
+# output
+#CONFIG_ANDROID_LOG=y
+
+# Enable privilege separation (see README 'Privilege separation' for details)
+#CONFIG_PRIVSEP=y
+
+# Enable mitigation against certain attacks against TKIP by delaying Michael
+# MIC error reports by a random amount of time between 0 and 60 seconds
+#CONFIG_DELAYED_MIC_ERROR_REPORT=y
+
+# Enable tracing code for developer debugging
+# This tracks use of memory allocations and other registrations and reports
+# incorrect use with a backtrace of call (or allocation) location.
+#CONFIG_WPA_TRACE=y
+# For BSD, uncomment these.
+#LIBS += -lexecinfo
+#LIBS_p += -lexecinfo
+#LIBS_c += -lexecinfo
+
+# Use libbfd to get more details for developer debugging
+# This enables use of libbfd to get more detailed symbols for the backtraces
+# generated by CONFIG_WPA_TRACE=y.
+#CONFIG_WPA_TRACE_BFD=y
+# For BSD, uncomment these.
+#LIBS += -lbfd -liberty -lz
+#LIBS_p += -lbfd -liberty -lz
+#LIBS_c += -lbfd -liberty -lz
+
+# wpa_supplicant depends on strong random number generation being available
+# from the operating system. os_get_random() function is used to fetch random
+# data when needed, e.g., for key generation. On Linux and BSD systems, this
+# works by reading /dev/urandom. It should be noted that the OS entropy pool
+# needs to be properly initialized before wpa_supplicant is started. This is
+# important especially on embedded devices that do not have a hardware random
+# number generator and may by default start up with minimal entropy available
+# for random number generation.
+#
+# As a safety net, wpa_supplicant is by default trying to internally collect
+# additional entropy for generating random data to mix in with the data fetched
+# from the OS. This by itself is not considered to be very strong, but it may
+# help in cases where the system pool is not initialized properly. However, it
+# is very strongly recommended that the system pool is initialized with enough
+# entropy either by using hardware assisted random number generator or by
+# storing state over device reboots.
+#
+# wpa_supplicant can be configured to maintain its own entropy store over
+# restarts to enhance random number generation. This is not perfect, but it is
+# much more secure than using the same sequence of random numbers after every
+# reboot. This can be enabled with -e<entropy file> command line option. The
+# specified file needs to be readable and writable by wpa_supplicant.
+#
+# If the os_get_random() is known to provide strong random data (e.g., on
+# Linux/BSD, the board in question is known to have reliable source of random
+# data from /dev/urandom), the internal wpa_supplicant random pool can be
+# disabled. This will save some in binary size and CPU use. However, this
+# should only be considered for builds that are known to be used on devices
+# that meet the requirements described above.
+#CONFIG_NO_RANDOM_POOL=y
+
+# IEEE 802.11n (High Throughput) support (mainly for AP mode)
+#CONFIG_IEEE80211N=y
+
+# IEEE 802.11ac (Very High Throughput) support (mainly for AP mode)
+# (depends on CONFIG_IEEE80211N)
+#CONFIG_IEEE80211AC=y
+
+# Wireless Network Management (IEEE Std 802.11v-2011)
+# Note: This is experimental and not complete implementation.
+#CONFIG_WNM=y
+
+# Interworking (IEEE 802.11u)
+# This can be used to enable functionality to improve interworking with
+# external networks (GAS/ANQP to learn more about the networks and network
+# selection based on available credentials).
+#CONFIG_INTERWORKING=y
+
+# Hotspot 2.0
+#CONFIG_HS20=y
+
+# Disable roaming in wpa_supplicant
+#CONFIG_NO_ROAMING=y
+
+# AP mode operations with wpa_supplicant
+# This can be used for controlling AP mode operations with wpa_supplicant. It
+# should be noted that this is mainly aimed at simple cases like
+# WPA2-Personal while more complex configurations like WPA2-Enterprise with an
+# external RADIUS server can be supported with hostapd.
+#CONFIG_AP=y
+
+# P2P (Wi-Fi Direct)
+# This can be used to enable P2P support in wpa_supplicant. See README-P2P for
+# more information on P2P operations.
+#CONFIG_P2P=y
+
+# Enable TDLS support
+#CONFIG_TDLS=y
+
+# Wi-Fi Direct
+# This can be used to enable Wi-Fi Direct extensions for P2P using an external
+# program to control the additional information exchanges in the messages.
+#CONFIG_WIFI_DISPLAY=y
+
+# Autoscan
+# This can be used to enable automatic scan support in wpa_supplicant.
+# See wpa_supplicant.conf for more information on autoscan usage.
+#
+# Enabling directly a module will enable autoscan support.
+# For exponential module:
+#CONFIG_AUTOSCAN_EXPONENTIAL=y
+# For periodic module:
+#CONFIG_AUTOSCAN_PERIODIC=y
+
+# Password (and passphrase, etc.) backend for external storage
+# These optional mechanisms can be used to add support for storing passwords
+# and other secrets in external (to wpa_supplicant) location. This allows, for
+# example, operating system specific key storage to be used
+#
+# External password backend for testing purposes (developer use)
+#CONFIG_EXT_PASSWORD_TEST=y
+
+# Enable Fast Session Transfer (FST)
+#CONFIG_FST=y
+
+# Enable CLI commands for FST testing
+#CONFIG_FST_TEST=y
+
+# OS X builds. This is only for building eapol_test.
+CONFIG_OSX=y
+
+# EAP-FAST used to require OpenSSL patches, so it's not on by default.
+# enable it.
+CONFIG_EAP_FAST=y
diff --git a/scripts/ci/haproxy.conf b/scripts/ci/haproxy.conf
new file mode 100644
index 0000000..e451aed
--- /dev/null
+++ b/scripts/ci/haproxy.conf
@@ -0,0 +1,16 @@
+global
+ maxconn 100
+
+defaults
+ timeout connect 10s
+ timeout client 30s
+ timeout server 30s
+
+frontend example.org
+ bind 127.0.0.1:2084
+ default_backend radsec
+
+backend radsec
+ balance roundrobin
+ server localhost-radssec 127.0.0.1:2083 send-proxy
+
diff --git a/scripts/ci/ldap-setup.sh b/scripts/ci/ldap-setup.sh
new file mode 100755
index 0000000..ec3ba2c
--- /dev/null
+++ b/scripts/ci/ldap-setup.sh
@@ -0,0 +1,51 @@
+#!/bin/sh
+
+# Allow setup script to work with homebrew too
+export PATH="/usr/local/opt/openldap/libexec:$PATH"
+
+# Clean out any existing DB
+rm -rf /tmp/ldap/db
+# Create directory we can write DB files to
+mkdir -p /tmp/ldap/db/
+
+# Change db location to /tmp as we can't write to /var
+sed -i -e 's/\/var\/lib\/ldap/\/tmp\/ldap\/db/' src/tests/salt-test-server/salt/ldap/base.ldif
+
+# Create a directory we can link schema files into
+if [ -d /tmp/ldap/schema ]; then
+ echo "Schema dir already linked"
+# Debian
+elif [ -d /etc/ldap/schema ]; then
+ ln -fs /etc/ldap/schema /tmp/ldap/schema
+# Redhat
+elif [ -d /etc/openldap/schema ]; then
+ ln -fs /etc/openldap/schema /tmp/ldap/schema
+# macOS (homebrew)
+elif [ -d /usr/local/etc/openldap/schema ]; then
+ ln -fs /usr/local/etc/openldap/schema /tmp/ldap/schema
+else
+ echo "Can't locate OpenLDAP schema dir"
+ exit 1
+fi
+
+# Start slapd
+slapd -h "ldap://127.0.0.1:3890/" -f scripts/ci/ldap/slapd.conf &
+
+# Wait for LDAP to start
+sleep 1
+
+# Add test data
+count=0
+while [ $count -lt 10 ] ; do
+ if ldapadd -x -H ldap://127.0.0.1:3890/ -D "cn=admin,cn=config" -w secret -f src/tests/salt-test-server/salt/ldap/base.ldif ; then
+ break 2
+ else
+ count=$((count+1))
+ sleep 1
+ fi
+done
+
+if [ $? -ne 0 ]; then
+ echo "Error configuring server"
+ exit 1
+fi
diff --git a/scripts/ci/ldap/slapd.conf b/scripts/ci/ldap/slapd.conf
new file mode 100644
index 0000000..7782616
--- /dev/null
+++ b/scripts/ci/ldap/slapd.conf
@@ -0,0 +1,51 @@
+#
+###### SAMPLE 1 - SIMPLE DIRECTORY ############
+#
+# NOTES: inetorgperson picks up attributes and objectclasses
+# from all three schemas
+#
+# NB: RH Linux schemas in /etc/openldap
+#
+include /tmp/ldap/schema/core.schema
+include /tmp/ldap/schema/cosine.schema
+include /tmp/ldap/schema/inetorgperson.schema
+include /tmp/ldap/schema/nis.schema
+include doc/schemas/ldap/openldap/freeradius.schema
+include doc/schemas/ldap/openldap/freeradius-clients.schema
+pidfile /tmp/slapd.pid
+
+# enable a lot of logging - we might need it
+# but generates huge logs
+loglevel -1
+
+# MODULELOAD definitions
+# not required (comment out) before version 2.3
+moduleload back_mdb.la
+
+database config
+rootdn "cn=admin,cn=config"
+rootpw secret
+
+#######################################################################
+# mdb database definitions
+#
+# replace example and com below with a suitable domain
+#
+# If you don't have a domain you can leave it since example.com
+# is reserved for experimentation or change them to my and inc
+#
+#######################################################################
+
+database mdb
+suffix "dc=nodomain"
+
+# root or superuser
+rootdn "cn=admin,dc=nodomain"
+rootpw secret
+# The database directory MUST exist prior to running slapd AND
+# change path as necessary
+directory /tmp/ldap/db/
+
+# other database parameters
+# read more in slapd.conf reference section
+checkpoint 128 15
diff --git a/scripts/ci/ldap/slapd2.conf b/scripts/ci/ldap/slapd2.conf
new file mode 100644
index 0000000..52c16a7
--- /dev/null
+++ b/scripts/ci/ldap/slapd2.conf
@@ -0,0 +1,61 @@
+#
+###### SAMPLE 1 - SIMPLE DIRECTORY ############
+#
+# NOTES: inetorgperson picks up attributes and objectclasses
+# from all three schemas
+#
+# NB: RH Linux schemas in /etc/openldap
+#
+include /tmp/ldap2/schema/core.schema
+include /tmp/ldap2/schema/cosine.schema
+include /tmp/ldap2/schema/inetorgperson.schema
+include /tmp/ldap2/schema/nis.schema
+include doc/schemas/ldap/openldap/freeradius.schema
+include doc/schemas/ldap/openldap/freeradius-clients.schema
+pidfile /tmp/slapd2.pid
+
+# enable a lot of logging - we might need it
+# but generates huge logs
+loglevel -1
+
+# MODULELOAD definitions
+# not required (comment out) before version 2.3
+moduleload back_mdb.la
+
+database config
+rootdn "cn=admin,cn=config"
+rootpw secret
+
+#
+# Certificates for SSL/TLS connections
+# Note - these will not match the host name so clients need to use
+# the "allow" option when checking certificates
+#
+#TLSCACertificateFile /tmp/ldap2/certs/cacert.pem
+#TLSCertificateFile /tmp/ldap2/certs/servercert.pem
+#TLSCertificateKeyFile /tmp/ldap2/certs/serverkey.pem
+
+#######################################################################
+# mdb database definitions
+#
+# replace example and com below with a suitable domain
+#
+# If you don't have a domain you can leave it since example.com
+# is reserved for experimentation or change them to my and inc
+#
+#######################################################################
+
+database mdb
+suffix "dc=nodomain"
+
+# root or superuser
+rootdn "cn=admin,dc=nodomain"
+rootpw secret
+# The database directory MUST exist prior to running slapd AND
+# change path as necessary
+directory /tmp/ldap2/db/
+
+# other database parameters
+# read more in slapd.conf reference section
+checkpoint 128 15
+
diff --git a/scripts/ci/ldap2-setup.sh b/scripts/ci/ldap2-setup.sh
new file mode 100755
index 0000000..c274414
--- /dev/null
+++ b/scripts/ci/ldap2-setup.sh
@@ -0,0 +1,63 @@
+#!/bin/sh
+
+# Allow setup script to work with homebrew too
+export PATH="/usr/local/opt/openldap/libexec:$PATH"
+
+# Clean out any existing DB
+rm -rf /tmp/ldap2/db
+# Create directory we can write DB files to
+mkdir -p /tmp/ldap2/db/
+
+# Change db location to /tmp as we can't write to /var
+sed -i -e 's/\/var\/lib\/ldap/\/tmp\/ldap2\/db/' src/tests/salt-test-server/salt/ldap/base2.ldif
+
+# Create a directory we can link schema files into
+if [ -d /tmp/ldap2/schema ]; then
+ echo "Schema dir already linked"
+# Debian
+elif [ -d /etc/ldap/schema ]; then
+ ln -fs /etc/ldap/schema /tmp/ldap2/schema
+# Redhat
+elif [ -d /etc/openldap/schema ]; then
+ ln -fs /etc/openldap/schema /tmp/ldap2/schema
+# macOS (homebrew)
+elif [ -d /usr/local/etc/openldap/schema ]; then
+ ln -fs /usr/local/etc/openldap/schema /tmp/ldap2/schema
+else
+ echo "Can't locate OpenLDAP schema dir"
+ exit 1
+fi
+
+# Clean out any old certificates
+##rm -rf /tmp/ldap2/certs
+# Create certificate directory
+##mkdir -p /tmp/ldap2/certs
+
+# Copy certificates - whilst not stricltly LDAP certs they work fine for these tests
+##cp src/tests/certs/rsa/ca.pem /tmp/ldap2/certs/cacert.pem
+##cp src/tests/certs/rsa/server.pem /tmp/ldap2/certs/servercert.pem
+# OpenLDAP wants an un-encrypted key
+##openssl rsa -in src/tests/certs/rsa/server.key -out /tmp/ldap2/certs/serverkey.pem -passin pass:whatever
+
+# Start slapd
+slapd -h "ldap://127.0.0.1:3891/" -f scripts/ci/ldap/slapd2.conf &
+
+# Wait for LDAP to start
+sleep 1
+
+# Add test data
+count=0
+while [ $count -lt 10 ] ; do
+ if ldapadd -x -H ldap://127.0.0.1:3891/ -D "cn=admin,cn=config" -w secret -f src/tests/salt-test-server/salt/ldap/base2.ldif ; then
+ break 2
+ else
+ count=$((count+1))
+ sleep 1
+ fi
+done
+
+if [ $? -ne 0 ]; then
+ echo "Error configuring server"
+ exit 1
+fi
+
diff --git a/scripts/ci/mysql-setup.sh b/scripts/ci/mysql-setup.sh
new file mode 100755
index 0000000..12e0067
--- /dev/null
+++ b/scripts/ci/mysql-setup.sh
@@ -0,0 +1,19 @@
+#!/bin/sh -e
+
+echo "MySQL - Dropping existing database"
+mysql -h "${SQL_MYSQL_TEST_SERVER}" -u root -e 'DROP DATABASE radius;' || true
+
+echo "MySQL - Dropping existing user"
+mysql -h "${SQL_MYSQL_TEST_SERVER}" -u root -e 'DROP USER radius@localhost;' || true
+
+echo "MySQL - Creating database"
+mysql -h "${SQL_MYSQL_TEST_SERVER}" -u root -e 'CREATE DATABASE radius;'
+
+echo "MySQL - Executing schema.sql"
+mysql -h "${SQL_MYSQL_TEST_SERVER}" -u root radius < raddb/mods-config/sql/main/mysql/schema.sql
+
+echo "MySQL - Executing setup.sql"
+mysql -h "${SQL_MYSQL_TEST_SERVER}" -u root radius < raddb/mods-config/sql/main/mysql/setup.sql
+
+echo "MySQL - Grant radius user permissions"
+mysql -h "${SQL_MYSQL_TEST_SERVER}" -u root -e "GRANT ALL on radius.* TO radius@localhost; FLUSH PRIVILEGES;"
diff --git a/scripts/ci/openresty-setup.sh b/scripts/ci/openresty-setup.sh
new file mode 100755
index 0000000..eb55d67
--- /dev/null
+++ b/scripts/ci/openresty-setup.sh
@@ -0,0 +1,144 @@
+#!/bin/sh -e
+#
+# ### This is a script to setup an openresty web server for testing rlm_smtp
+#
+
+#
+# Declare the important path variables
+#
+
+# Base Directories
+BASEDIR=$(git rev-parse --show-toplevel)
+BUILDDIR="${BASEDIR}/build/ci/openresty"
+CIDIR="${BASEDIR}/scripts/ci"
+
+# Directories for openresty processes
+ROOTDIR="${BUILDDIR}/html"
+APIDIR="${BUILDDIR}/api"
+LOGDIR="${BUILDDIR}/logs"
+CERTDIR="${BUILDDIR}/certs"
+CERTSRCDIR="${BASEDIR}/raddb/restcerts"
+PASSWORD="whatever"
+
+# Important files for running openresty
+CONF="${BUILDDIR}/nginx.conf"
+
+#
+# Prepare the directories and files needed for running openresty
+#
+
+# Stop any currently running openresty instance
+echo "Checking for a running openresty instance"
+if [ -e "${LOGDIR}/nginx.pid" ]
+then
+ echo "Stopping the current openresty instance"
+ kill "$(cat ${LOGDIR}/nginx.pid)"
+ rm -r "${BUILDDIR}"
+fi
+
+# Create the directories
+mkdir -p "${BUILDDIR}" "${ROOTDIR}" "${APIDIR}" "${LOGDIR}" "${CERTDIR}"
+
+# Create the certificate
+echo "Generating the certificates"
+openssl pkcs8 -in ${CERTSRCDIR}/server.key -passin pass:${PASSWORD} -out ${CERTDIR}/server.key
+cat ${CERTSRCDIR}/server.pem ${CERTSRCDIR}/ca.pem > ${CERTDIR}/server.pem
+
+# Create nginx.conf file
+echo "Generating the openresty configuration file"
+touch "${CONF}"
+
+# Build nginx.conf
+echo "
+#
+worker_processes 1;
+error_log ${LOGDIR}/error.log;
+pid ${LOGDIR}/nginx.pid;
+
+events {
+ worker_connections 1024;
+}
+
+http {
+ include /usr/local/openresty/nginx/conf/mime.types;
+ default_type text/plain;
+
+ sendfile on;
+
+ server {
+ listen 8080;
+ server_name localhost;
+
+ location / {
+ root ${ROOTDIR};
+ index index.html;
+ }
+
+ location ~ ^/user(.*)$ {
+ default_type 'application/json';
+ add_header 'Content-Type' 'application/json';
+ content_by_lua_file ${APIDIR}/json-api.lua;
+ }
+
+ location ~ ^/post(.*)$ {
+ content_by_lua_file ${APIDIR}/post-api.lua;
+ }
+
+ location ~ ^/delay(.*)$ {
+ content_by_lua_file ${APIDIR}/delay-api.lua;
+ }
+ }
+
+ server {
+ listen 8443 ssl;
+ server_name localhost;
+
+ ssl_certificate ${CERTDIR}/server.pem;
+ ssl_certificate_key ${CERTDIR}/server.key;
+
+ ssl_session_cache shared:SSL:1m;
+ ssl_session_timeout 5m;
+
+ ssl_ciphers HIGH:!aNULL:!MD5;
+ ssl_prefer_server_ciphers on;
+
+ location / {
+ root ${ROOTDIR};
+ index index.html;
+ }
+
+ location ~ ^/user(.*)$ {
+ default_type 'application/json';
+ add_header 'Content-Type' 'application/json';
+ content_by_lua_file ${APIDIR}/json-api.lua;
+ }
+
+ location ~ ^/post(.*)$ {
+ content_by_lua_file ${APIDIR}/post-api.lua;
+ }
+
+ location ~ ^/auth(.*)$ {
+ content_by_lua_file ${APIDIR}/auth-api.lua;
+ auth_basic 'Auth Area';
+ auth_basic_user_file ${BUILDDIR}/.htpasswd;
+ }
+ }
+}
+
+" >"${CONF}"
+
+echo "Copy lua scripts into place"
+cp ${CIDIR}/openresty/*.lua "${APIDIR}"
+
+echo "Copy sample data into place"
+cp "${CIDIR}/openresty/test.txt" "${ROOTDIR}"
+
+echo "Copy htpasswd into place"
+cp "${CIDIR}/openresty/.htpasswd" "${BUILDDIR}"
+
+#
+# Run the openresty instance
+#
+echo "Starting openresty"
+openresty -c ${CONF} -p ${BUILDDIR}
+echo "Running openresty on port 8080 and 8443, accepting all local connections"
diff --git a/scripts/ci/openresty/.htpasswd b/scripts/ci/openresty/.htpasswd
new file mode 100644
index 0000000..028536a
--- /dev/null
+++ b/scripts/ci/openresty/.htpasswd
@@ -0,0 +1 @@
+Bob:$apr1$4AtMvgrH$pWCOxq7gq1N2AyeE7GT3R/
diff --git a/scripts/ci/openresty/auth-api.lua b/scripts/ci/openresty/auth-api.lua
new file mode 100644
index 0000000..8ea336c
--- /dev/null
+++ b/scripts/ci/openresty/auth-api.lua
@@ -0,0 +1,19 @@
+-- Simple API for checking POST data
+
+-- Get the request path
+local reqPath = ngx.var.uri
+-- Get the request method (POST, GET etc..)
+local reqMethod = ngx.var.request_method
+-- Get any URI arguments
+local uriArgs = ngx.req.get_uri_args()
+-- Get any POST arguments
+ngx.req.read_body()
+local postArgs = ngx.req.get_post_args()
+
+-- We only reply to POST requests
+if reqMethod ~= "POST"
+then
+ return false
+end
+
+ngx.say("Section: ", uriArgs.section, ", User: ", postArgs.user, ", Authenticated: true")
diff --git a/scripts/ci/openresty/delay-api.lua b/scripts/ci/openresty/delay-api.lua
new file mode 100644
index 0000000..aa4f61b
--- /dev/null
+++ b/scripts/ci/openresty/delay-api.lua
@@ -0,0 +1,6 @@
+-- Simple API represending a slow response for testing timeouts
+
+local t0 = os.clock()
+while os.clock() - t0 <= 2 do end
+
+ngx.say("Delayed response")
diff --git a/scripts/ci/openresty/json-api.lua b/scripts/ci/openresty/json-api.lua
new file mode 100644
index 0000000..4a574f7
--- /dev/null
+++ b/scripts/ci/openresty/json-api.lua
@@ -0,0 +1,145 @@
+-- Based on https://github.com/bambattajb/openresty-api-example
+
+-- Helper functions
+function strSplit(delim,str)
+ local t = {}
+
+ for substr in string.gmatch(str, "[^".. delim.. "]*") do
+ if substr ~= nil and string.len(substr) > 0 then
+ table.insert(t,substr)
+ end
+ end
+
+ return t
+end
+
+-- Read body being passed
+-- Required for ngx.req.get_body_data()
+ngx.req.read_body()
+-- Parser for sending JSON back to the client
+local cjson = require("cjson")
+-- Get the request path
+local reqPath = ngx.var.uri
+-- Get the request method (POST, GET etc..)
+local reqMethod = ngx.var.request_method
+-- Get any URI arguments
+local uriArgs = ngx.req.get_uri_args()
+-- Parse the body data as JSON
+local body = ngx.req.get_body_data() ==
+ -- This is like a ternary statement for Lua
+ -- It is saying if doesn't exist at least
+ -- define as empty object
+ nil and {} or cjson.decode(ngx.req.get_body_data());
+
+Api = {}
+Api.__index = Api
+-- Declare API not yet responded
+Api.responded = false;
+-- Function for checking input from client
+function Api.endpoint(method, path, callback)
+
+ -- return false if method doesn't match
+ if reqMethod ~= method
+ then
+ return false
+ end
+
+ -- If API already responded
+ if Api.responded then
+ return false
+ end
+
+ -- KeyData = params passed in path
+ local keyData = {}
+ -- Unaltered version of path
+ local origPath = reqPath
+ -- If this endpoint has params
+ if string.find(path, "<(.-)>")
+ then
+ -- Split origin and passed path sections
+ local splitPath = strSplit("/", path)
+ local splitReqPath = strSplit("/", reqPath)
+ -- Iterate over splitPath
+ for i, k in pairs(splitPath) do
+ -- If chunk contains <something>
+ if string.find(k, "<(.-)>")
+ then
+ if not splitReqPath[i] then
+ reqPath = origPath
+ return false
+ end
+ -- Add to keyData
+ keyData[string.match(k, "%<(%a+)%>")] = splitReqPath[i]
+ -- Replace matches with default for validation
+ reqPath = string.gsub(reqPath, splitReqPath[i], k)
+ end
+ end
+ end
+
+ -- return false if path doesn't match anything
+ if reqPath ~= path
+ then
+ reqPath = origPath
+ return false;
+ end
+
+ -- Make sure we don't run this again
+ Api.responded = true;
+
+ return callback(body, keyData);
+end
+
+-- Used in the accounting test
+Api.endpoint('POST', '/user/<username>/mac/<client>',
+ function(body, keyData)
+ local returnData = {}
+ returnData["control:Tmp-String-0"] = uriArgs.section
+ returnData["control:Tmp-String-1"] = {
+ reqMethod,
+ reqPath
+ }
+ returnData["control:User-Name"] = {
+ op = ":=",
+ value = keyData.username
+ }
+ returnData["control:NAS-IP-Address"] = {
+ op = "+=",
+ value = body.NAS or body['NAS-IP-Address'].value
+ }
+ returnData["control:Tmp-String-2"] = {
+ op = "^=",
+ value = keyData.username
+ }
+ return ngx.say(cjson.encode(returnData))
+ end
+)
+
+-- Used in the authorize test
+Api.endpoint('GET', '/user/<username>/mac/<client>',
+ function(body, keyData)
+ local returnData = {}
+ returnData["control:Tmp-String-0"] = uriArgs.section
+ returnData["control:Tmp-String-1"] = {
+ reqMethod,
+ reqPath
+ }
+ returnData["control:User-Name"] = {
+ op = ":=",
+ value = keyData.username
+ }
+ returnData["control:Tmp-String-2"] = {
+ op = "^=",
+ value = keyData.username
+ }
+ return ngx.say(cjson.encode(returnData))
+ end
+)
+
+-- Simple reflection of a URI argument
+Api.endpoint('GET', '/user/<username>/reflect/',
+ function(body, keyData)
+ local returnData = {}
+ returnData["station"] = uriArgs.station
+ return ngx.say(cjson.encode(returnData))
+ end
+)
diff --git a/scripts/ci/openresty/post-api.lua b/scripts/ci/openresty/post-api.lua
new file mode 100644
index 0000000..3f22960
--- /dev/null
+++ b/scripts/ci/openresty/post-api.lua
@@ -0,0 +1,19 @@
+-- Simple API for checking POST data
+
+-- Get the request path
+local reqPath = ngx.var.uri
+-- Get the request method (POST, GET etc..)
+local reqMethod = ngx.var.request_method
+-- Get any URI arguments
+local uriArgs = ngx.req.get_uri_args()
+-- Get any POST arguments
+ngx.req.read_body()
+local postArgs = ngx.req.get_post_args()
+
+-- We only reply to POST requests
+if reqMethod ~= "POST"
+then
+ return false
+end
+
+ngx.say("Section: ", uriArgs.section, ", User: ", postArgs.user)
diff --git a/scripts/ci/openresty/test.txt b/scripts/ci/openresty/test.txt
new file mode 100644
index 0000000..eceb6ed
--- /dev/null
+++ b/scripts/ci/openresty/test.txt
@@ -0,0 +1 @@
+Sample text response
diff --git a/scripts/ci/package-test.mk b/scripts/ci/package-test.mk
new file mode 100644
index 0000000..417784b
--- /dev/null
+++ b/scripts/ci/package-test.mk
@@ -0,0 +1,41 @@
+#
+# This Makefile performs some end to end tests against a package installed
+# within the CI environment.
+#
+# It reuses the eapol_test build-time tests, but runs them against the assets
+# installed by the distribution packaging.
+#
+# We want the run-time environment to be lean, typical of a fresh system
+# installation so that we catch any missing runtime dependancies, assets
+# missing from the packages, issues with the dynamic loader, etc.
+#
+# Therefore we skip the usual build framework so that we do not have so
+# configure the build tree and so that our only dependency is some non-ancient
+# version GNU Make. (Any version in a supported distribution will do.)
+#
+
+#
+# For the package tests we use the system version of radiusd on the standard
+# port
+#
+RADIUSD_BIN := $(shell which radiusd || which freeradius)
+PORT := 1812
+SECRET := testing123
+DICT_PATH := /usr/share/freeradius
+
+ifneq (,$(wildcard /etc/raddb/radiusd.conf))
+RADDB_PATH := /etc/raddb/
+else
+RADDB_PATH := /etc/freeradius/
+endif
+
+#
+# We prefer to use our exactly eapol_test version
+#
+EAPOL_TEST := $(shell ./scripts/ci/eapol_test-build.sh)
+
+MAKE_ARGS := RADIUSD_BIN=$(RADIUSD_BIN) PORT=$(PORT) SECRET="$(SECRET)" DICT_PATH=$(DICT_PATH) RADDB_PATH=$(RADDB_PATH)
+
+.PHONY: package-test
+package-test:
+ $(MAKE) -C src/tests $(MAKE_ARGS) tests.eap
diff --git a/scripts/ci/postgresql-setup.sh b/scripts/ci/postgresql-setup.sh
new file mode 100755
index 0000000..1e1abfb
--- /dev/null
+++ b/scripts/ci/postgresql-setup.sh
@@ -0,0 +1,26 @@
+#!/bin/sh -e
+
+#
+# To initialise on MacOS
+# sudo brew install postgresql
+# pg_ctl -D /usr/local/var/postgres start
+# /usr/local/opt/postgres/bin/createuser -s postgres
+#
+
+echo "Dropping existing database"
+psql -h "${SQL_POSTGRESQL_TEST_SERVER}" -c 'drop database radius;' -U postgres || true
+
+echo "Dropping existing database"
+psql -h "${SQL_POSTGRESQL_TEST_SERVER}" -c 'drop user radius;' -U postgres || true
+
+echo "PostgreSQL - Creating database"
+psql -h "${SQL_POSTGRESQL_TEST_SERVER}" -c 'create database radius;' -U postgres || true
+
+echo "PostgreSQL - Execute schema.sql"
+psql -h "${SQL_POSTGRESQL_TEST_SERVER}" -U postgres radius < raddb/mods-config/sql/main/postgresql/schema.sql
+
+echo "PostgreSQL - Execute setup.sql"
+psql -h "${SQL_POSTGRESQL_TEST_SERVER}" -U postgres radius < raddb/mods-config/sql/main/postgresql/setup.sql
+
+echo "PostgreSQL - Grant radius user permissions"
+psql -h "${SQL_POSTGRESQL_TEST_SERVER}" -c 'GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO radius;' -U postgres radius
diff --git a/scripts/ci/radsecproxy.conf b/scripts/ci/radsecproxy.conf
new file mode 100644
index 0000000..c6df5d1
--- /dev/null
+++ b/scripts/ci/radsecproxy.conf
@@ -0,0 +1,33 @@
+# radsecproxy -f -c radsecproxy.conf
+
+# If there's no ListenUDP config, then radsecproxy will listen on *:1812 by default. <sigh>
+ListenUDP *:1816
+
+tls default {
+ CACertificateFile ../../raddb/certs/CA.pem
+
+ # You must specify the below for TLS, we always present our certificate
+ CertificateFile ../../raddb/certs/client.pem
+ CertificateKeyFile ../../raddb/certs/client.key
+
+ # Optionally specify password if key is encrypted (not very secure)
+ CertificateKeyPassword "whatever"
+}
+
+client 127.0.0.1 {
+ type udp
+ secret testing123
+}
+
+server 127.0.0.1 {
+ type tls
+ port 2084
+ secret radsec
+
+ CertificateNameCheck off
+}
+
+
+realm * {
+ server 127.0.0.1
+}
diff --git a/scripts/ci/start.sh b/scripts/ci/start.sh
new file mode 100644
index 0000000..0408068
--- /dev/null
+++ b/scripts/ci/start.sh
@@ -0,0 +1,37 @@
+##TODO rip this apart into "configure , make , make deb, make scan and make install" functions
+export PANIC_ACTION="gdb -batch -x raddb/panic.gdb %e %p 1>&0 2>&0"
+
+#Configure
+if [ "${DO_BUILD}" = 'yes' ]; then
+ CFLAGS="${BUILD_CFLAGS}" ./configure -C\
+ --enable-werror \
+ --prefix=$HOME/freeradius\
+ --with-shared-libs=$LIBS_SHARED \
+ --with-threads=$LIBS_OPTIONAL \
+ --with-udpfromto=$LIBS_OPTIONAL \
+ --with-openssl=$LIBS_OPTIONAL \
+ --with-pcre=$LIBS_OPTIONAL \
+ --enable-reproducible-builds=${REPRODUCIBLE}
+fi
+
+if [ "${DO_BUILD}" = 'no' ]; then
+ ./configure -C --without-modules
+fi
+
+# Make
+if [ "${DO_BUILD}" = 'yes' ]; then
+ make -j8
+fi
+
+# Make scan
+if [ "${DO_BUILD}" = 'yes' -a ${CC} = 'clang' ]; then
+ make -j8 scan && [ "$(find build/plist/ -name *.html)" = '' ]
+fi
+
+if [ "${DO_BUILD}" = 'yes' ]; then
+ make ci-test
+fi
+
+if [ "${DO_BUILD}" = 'no' ]; then
+ cd doc/source; doxygen 3>&1 1>&2 2>&3 | grep -iv '^warning:' | tee doxygen_stderr.log && [ ! -n "$(cat doxygen_stderr.log)" ]
+fi
diff --git a/scripts/ci/stunnel.conf b/scripts/ci/stunnel.conf
new file mode 100644
index 0000000..a312d66
--- /dev/null
+++ b/scripts/ci/stunnel.conf
@@ -0,0 +1,16 @@
+;
+; Run via:
+;
+; stunnel stunnel.conf
+;
+; You will be prompted for the password. Type "whatever".
+;
+foreground = yes
+
+[radsec]
+client = yes
+accept = 127.0.0.1:20830
+connect = 127.0.0.1:2083
+cert = ../../raddb/certs/client.pem
+key = ../../raddb/certs/client.key
+;protocol=proxy
diff --git a/scripts/clients.pl b/scripts/clients.pl
new file mode 100755
index 0000000..40ed5ee
--- /dev/null
+++ b/scripts/clients.pl
@@ -0,0 +1,68 @@
+#!/usr/bin/env perl
+#
+# Convert old-style "clients" file to new "clients.conf" format.
+#
+# Usage: clients.pl clients [naslist] new-clients.conf
+# The "new-clients.conf" will be created if it does not exist.
+# If it does exist, it will be over-written.
+#
+#
+# $Id$
+#
+if (($#ARGV < 1) || ($#ARGV > 2)) {
+ print "Usage: clients.pl clients [naslist] new-clients.conf\n";
+ print " The \"new-clients.conf\" will be created if it does not exist.\n";
+ print " If it does exist, it will be over-written.\n";
+ exit(1);
+}
+
+$old = shift;
+$new = shift;
+
+if ($new =~ /naslist/) {
+ $naslist = $new;
+ $new = shift;
+}
+
+open OLD, "< $old" or die "Failed to open $old: $!\n";
+
+while (<OLD>) {
+ next if (/^\s*\#/);
+ next if (/^\s*$/);
+
+ split;
+
+ $clients{$_[0]}{"secret"} = $_[1];
+}
+close OLD;
+
+if (defined $naslist) {
+ open OLD, "< $naslist" or die "Failed to open $naslist: $!\n";
+
+ while (<OLD>) {
+ next if (/^\s*\#/);
+ next if (/^\s*$/);
+
+ split;
+
+ if (!defined $clients{$_[0]}) {
+ print "WARNING! client $_[0] is defined in naslist, but not in clients!";
+ next;
+ }
+
+ $clients{$_[0]}{"shortname"} = $_[1];
+ $clients{$_[0]}{"nas_type"} = $_[2];
+ }
+}
+
+open NEW, "> $new" or die "Failed to open $new: $!\n";
+foreach $client (keys %clients) {
+ print NEW "client $client {\n";
+ print NEW "\tsecret = ", $clients{$client}{"secret"}, "\n";
+ if (defined $clients{$client}{"shortname"}) {
+ print NEW "\tshortname = ", $clients{$client}{"shortname"}, "\n";
+ print NEW "\tnas_type = ", $clients{$client}{"nas_type"}, "\n";
+ }
+ print NEW "}\n";
+ print NEW "\n";
+}
diff --git a/scripts/collectd/radsniff_types.db b/scripts/collectd/radsniff_types.db
new file mode 100644
index 0000000..8f4fc57
--- /dev/null
+++ b/scripts/collectd/radsniff_types.db
@@ -0,0 +1,10 @@
+#
+# Collectd type definitions for radsniff probes
+#
+# $Id$
+#
+# Copyright 2013 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+#
+radius_count received:GAUGE:0:U, linked:GAUGE:0:U, unlinked:GAUGE:0:U, reused:GAUGE:0:U
+radius_latency smoothed:GAUGE:0:U, avg:GAUGE:0:U, high:GAUGE:0:U, low:GAUGE:0:U
+radius_rtx none:GAUGE:0:U, 1:GAUGE:0:U, 2:GAUGE:0:U, 3:GAUGE:0:U, 4:GAUGE:0:U, more:GAUGE:0:U, lost:GAUGE:0:U
diff --git a/scripts/create-users.pl b/scripts/create-users.pl
new file mode 100755
index 0000000..36d6f8a
--- /dev/null
+++ b/scripts/create-users.pl
@@ -0,0 +1,64 @@
+#!/usr/bin/perl
+
+# Purpose: create lots of random users and passes
+# for testing your radius server
+# Read doc/README.testing for more information
+
+$passfile = "./passwd";
+$shadfile = "./shadow";
+$radfile = "./radius.test";
+$nocrypt = "./passwd.nocrypt";
+$users = "./radius.users";
+
+if($ARGV[0] eq "") {
+ print "\n\tUsage: $0 <number of users>\n\n";
+ exit(1);
+} else {
+ $numusers = $ARGV[0];
+}
+$userlen = 6;
+$passlen = 6;
+
+open(PASS, ">$passfile") || die "Can't open $passfile";
+open(SHAD, ">$shadfile") || die "Can't open $shadfile";
+open(RAD, ">$radfile") || die "Can't open $radfile";
+open(NOCRYPT, ">$nocrypt") || die "Can't open $nocrypt";
+open(USERS, ">$users") || die "Can't open $users";
+
+for ($num=0; $num<$numusers; $num++) {
+ # generate username
+ $username = "";
+ for($i=0; $i<rand($userlen)+2; $i++) {
+ do { ($char = chr((rand 25)+97))} until $char=~/[A-Za-z]/;
+ $username .= $char;
+ }
+ # Make sure they're unique
+ if(($userlist{$username}) || (getpwnam($username))) {
+ $num--;
+ next;
+ }
+ $userlist{$username} = 1;
+
+ # generate password
+ $password = "";
+ for($i=0; $i<rand($passlen)+2; $i++) {
+ do { ($char = chr((rand 25)+97))} until $char=~/[A-Za-z]/;
+ $password .= $char;
+ }
+
+ if (length($num)%2==1) {
+ $num="0".$num;
+ }
+ printf PASS "$username:%s:1001:1001:Name:/dev/null:/dev/null\n", crypt($password, $password);
+ printf SHAD "$username:%s:1000:0:99999:7:::\n", crypt($password, $password);
+ printf RAD "User-Name=$username, User-Password=$password,NAS-IP-Address=127.0.0.1,NAS-Port-Id=0\n\n";
+ print NOCRYPT "$username:$password\n";
+ print USERS "$username Cleartext-Password := \"$password\"\n\tClass=\"0x$num\"\n\n";
+}
+
+close(PASS);
+close(SHAD);
+close(RAD);
+close(NOCRYPT);
+close(USERS);
+print "\nCreated $numusers random users and passwords\n\n";
diff --git a/scripts/cron/radiusd.cron.daily.in b/scripts/cron/radiusd.cron.daily.in
new file mode 100644
index 0000000..da631ba
--- /dev/null
+++ b/scripts/cron/radiusd.cron.daily.in
@@ -0,0 +1,34 @@
+#! /bin/sh
+#
+# radiusd Cron script to rotate radiusd log files daily.
+#
+
+prefix=@prefix@
+localstatedir=@localstatedir@
+logdir=@logdir@
+
+umask 027
+cd $logdir
+
+# Take care of the standard logfiles.
+cd $logdir
+if [ -f radius.log ]
+then
+ savelog -g adm -m 640 -c 3 radius.log > /dev/null
+fi
+
+# Rotate "details" files.
+if [ ! -d radacct/. ]
+then
+ exit 0
+fi
+cd radacct
+
+for LOG in */detail
+do
+ if [ -f $LOG ]
+ then
+ savelog -g adm -m 640 -u root -c 3 $LOG >/dev/null
+ fi
+done
+
diff --git a/scripts/cron/radiusd.cron.monthly.in b/scripts/cron/radiusd.cron.monthly.in
new file mode 100644
index 0000000..84d8246
--- /dev/null
+++ b/scripts/cron/radiusd.cron.monthly.in
@@ -0,0 +1,19 @@
+#! /bin/sh
+#
+# radiusd Cron script to rotate radwtmp file monthly.
+#
+
+prefix=@prefix@
+localstatedir=@localstatedir@
+logdir=@logdir@
+
+umask 022
+cd $logdir
+
+# Take care of the standard logfiles.
+cd $logdir
+if [ -f radwtmp ]
+then
+ savelog -g adm -m 644 -c 6 radwtmp > /dev/null
+fi
+
diff --git a/scripts/crossbuild/README.md b/scripts/crossbuild/README.md
new file mode 100644
index 0000000..0bcc2c4
--- /dev/null
+++ b/scripts/crossbuild/README.md
@@ -0,0 +1,122 @@
+# Crossbuild
+
+## Summary
+
+The "crossbuild" system is a way to build FreeRADIUS for multiple
+different operating systems, using Docker.
+
+The primary purpose is for developers to easily test FreeRADIUS on
+different systems.
+
+
+## Common Usage
+
+The systems supported can be listed with
+
+ make crossbuild.info
+
+A reminder of the make targets may be seen with
+
+ make crossbuild.help
+
+To make all the known systems (this may take quite a while, at
+least on the first run):
+
+ make crossbuild
+
+or for the most common systems (Debian, Ubuntu, CentOS):
+
+ make crossbuild.common
+
+
+## General operation
+
+The system works by building and then starting up Docker
+containers for the systems. When a build is triggered (either
+generally, as above, or for a specific OS) the current git commits
+are copied into the image and then `make test` run.
+
+The Docker containers are left running, and may be stopped with
+
+ make crossbuild.down
+
+The system tries to be as efficient as possible, so will not
+rebuild from scratch every time.
+
+
+## Global make targets
+
+The following targets will operate on the crossbuild system
+globally, or on all images (unless otherwise stated):
+
+
+### `make crossbuild`
+
+Create all docker images (if required), start them, build and test
+FreeRADIUS.
+
+
+### `make crossbuild.common`
+
+As `make crossbuild`, but only build and test the most common
+systems.
+
+
+### `make crossbuild.info`
+
+List all systems, together with the expected state. See
+`crossbuild.reset`.
+
+
+### `make crossbuild.down`
+
+Stop all containers.
+
+
+### `make crossbuild.reset`
+
+If containers are stopped or started outside Docker, crossbuild
+may get confused. This will clear the internal state which should
+try and start everything from be beginning again.
+
+
+### `make crossbuild.clean`
+
+Bring down all containers, clear state. This is a general "tidy
+up".
+
+
+### `make crossbuild.wipe`
+
+Don't just stop, but destroy all crossbuild docker images. This
+will mean they need to be recreated again upon next use.
+
+
+## Per-image make targets
+
+The following make targets may be used on a per-image basis:
+
+ * `make crossbuild.IMAGE`: build and test image
+ * `make crossbuild.IMAGE.log`: show latest build log
+ * `make crossbuild.IMAGE.up`: start container
+ * `make crossbuild.IMAGE.down`: stop container
+ * `make crossbuild.IMAGE.sh`: shell in container
+ * `make crossbuild.IMAGE.refresh`: push latest commits into container
+ * `make crossbuild.IMAGE.clean`: stop container and tidy up
+ * `make crossbuild.IMAGE.wipe`: remove Docker image
+
+For example, `make crossbuild.debian10` to create, build and test
+FreeRADIUS on Debian 10. `make crossbuild.debian10.down` will then
+stop the container.
+
+
+## Docker image and container names
+
+Docker images will be created with names in the form:
+
+ freeradius-build/debian10
+
+whil containers will have names like:
+
+ fr-crossbuild-debian10
+
diff --git a/scripts/crossbuild/build/.gitignore b/scripts/crossbuild/build/.gitignore
new file mode 100644
index 0000000..7bd9396
--- /dev/null
+++ b/scripts/crossbuild/build/.gitignore
@@ -0,0 +1,4 @@
+build.*
+configure.*
+log.*
+stamp-*
diff --git a/scripts/crossbuild/crossbuild.mk b/scripts/crossbuild/crossbuild.mk
new file mode 100644
index 0000000..da96506
--- /dev/null
+++ b/scripts/crossbuild/crossbuild.mk
@@ -0,0 +1,236 @@
+#
+# Include crossbuild targets, to test building on lots of
+# different OSes. Uses Docker.
+#
+ifeq ($(shell which docker 2> /dev/null),)
+.PHONY: crossbuild crossbuild.help
+crossbuild crossbuild.help :
+ @echo crossbuild requires Docker to be installed
+else
+
+#
+# Short list of common builds
+#
+CB_COMMON:=centos7 debian10 ubuntu18
+
+# Where the docker directories are
+DT:=scripts/crossbuild/docker
+
+# Where to put stamp files (subdirectory of where this makefile is)
+DD:=$(dir $(realpath $(lastword $(MAKEFILE_LIST))))/build
+
+# List of all the docker images (sorted for "crossbuild.info")
+CB_IMAGES:=$(sort $(patsubst $(DT)/%,%,$(wildcard $(DT)/*)))
+
+# Location of the .git dir (may be different for e.g. submodules)
+GITDIR:=$(shell perl -MCwd -e 'print Cwd::abs_path shift' $$(git rev-parse --git-dir))
+
+CB_CPREFIX:=fr-crossbuild-
+CB_IPREFIX:=freeradius-build
+
+#
+# This Makefile is included in-line, and not via the "boilermake"
+# wrapper. But it's still useful to use the same process for
+# seeing commands that are run.
+#
+ifeq "${VERBOSE}" ""
+ Q=@
+else
+ Q=
+endif
+
+#
+# Enter here: This builds everything
+#
+.PHONY: crossbuild crossbuild.common
+crossbuild: crossbuild.info $(foreach IMG,${CB_IMAGES},crossbuild.${IMG})
+crossbuild.common: crossbuild.info $(foreach IMG,${CB_COMMON},crossbuild.${IMG})
+
+#
+# Dump out some useful information on what images we're going to test
+#
+.PHONY: crossbuild.info crossbuild.info_header crossbuild.help
+crossbuild.info: crossbuild.info_header $(foreach IMG,${CB_IMAGES},crossbuild.${IMG}.status)
+ @echo Common images: $(CB_COMMON)
+
+crossbuild.info_header:
+ @echo Images:
+
+crossbuild.help: crossbuild.info
+ @echo ""
+ @echo "Make targets:"
+ @echo " crossbuild - build and test all images"
+ @echo " crossbuild.common - build and test common images"
+ @echo " crossbuild.info - list images"
+ @echo " crossbuild.down - stop all containers"
+ @echo " crossbuild.reset - remove cache of docker state"
+ @echo " crossbuild.clean - down and reset all targets"
+ @echo " crossbuild.wipe - destroy all crossbuild Docker images"
+ @echo ""
+ @echo "Per-image targets:"
+ @echo " crossbuild.IMAGE - build and test image <IMAGE>"
+ @echo " crossbuild.IMAGE.log - show latest build log"
+ @echo " crossbuild.IMAGE.up - start container"
+ @echo " crossbuild.IMAGE.down - stop container"
+ @echo " crossbuild.IMAGE.sh - shell in container"
+ @echo " crossbuild.IMAGE.refresh - push latest commits into container"
+ @echo " crossbuild.IMAGE.reset - remove cache of docker state"
+ @echo " crossbuild.IMAGE.clean - stop container and tidy up"
+ @echo " crossbuild.IMAGE.wipe - remove Docker image"
+
+#
+# Remove stamp files, so that we try and create images again
+#
+crossbuild.reset: $(foreach IMG,${CB_IMAGES},crossbuild.${IMG}.reset)
+
+#
+# Stop all containers
+#
+crossbuild.down: $(foreach IMG,${CB_IMAGES},crossbuild.${IMG}.down)
+
+#
+# Clean up: stop all containers, do a reset
+#
+crossbuild.clean: $(foreach IMG,${CB_IMAGES},crossbuild.${IMG}.clean)
+
+#
+# Remove all images
+#
+crossbuild.wipe: $(foreach IMG,${CB_IMAGES},crossbuild.${IMG}.wipe)
+
+#
+# Define rules for building a particular image
+#
+define CROSSBUILD_IMAGE_RULE
+#
+# Show status (based on stamp files)
+#
+.PHONY: crossbuild.${1}.status
+crossbuild.${1}.status:
+ ${Q}printf "%s" "`echo \" ${1} \" | cut -c 1-20`"
+ ${Q}if [ -e "$(DD)/stamp-up.${1}" ]; then echo "running"; \
+ elif [ -e "$(DD)/stamp-image.${1}" ]; then echo "built"; \
+ else echo "-"; fi
+#
+# Build the docker image
+#
+$(DD)/stamp-image.${1}:
+ ${Q}echo "BUILD ${1} ($(CB_IPREFIX)/${1}) > $(DD)/build.${1}"
+ ${Q}docker build $(DOCKER_BUILD_OPTS) $(DT)/${1} -f $(DT)/${1}/Dockerfile -t $(CB_IPREFIX)/${1} >$(DD)/build.${1} 2>&1
+ ${Q}touch $(DD)/stamp-image.${1}
+
+#
+# Start up the docker container
+#
+.PHONY: $(DD)/docker.up.${1}
+$(DD)/docker.up.${1}: $(DD)/stamp-image.${1}
+ ${Q}echo "START ${1} ($(CB_CPREFIX)${1})"
+ ${Q}docker container inspect $(CB_CPREFIX)${1} >/dev/null 2>&1 || \
+ docker run -d --rm \
+ --privileged --cap-add=ALL \
+ --mount=type=bind,source="$(GITDIR)",destination=/srv/src,ro \
+ --name $(CB_CPREFIX)${1} $(CB_IPREFIX)/${1} \
+ /bin/sh -c 'while true; do sleep 60; done' >/dev/null
+
+$(DD)/stamp-up.${1}: $(DD)/docker.up.${1}
+ ${Q}touch $(DD)/stamp-up.${1}
+
+.PHONY: crossbuild.${1}.up
+crossbuild.${1}.up: $(DD)/stamp-up.${1}
+
+#
+# Run tests in the container
+#
+.PHONY: $(DD)/docker.refresh.${1}
+$(DD)/docker.refresh.${1}: $(DD)/stamp-up.${1}
+ ${Q}echo "REFRESH ${1}"
+ ${Q}docker container exec $(CB_CPREFIX)${1} sh -c 'rsync -a /srv/src/ /srv/local-src/'
+ ${Q}docker container exec $(CB_CPREFIX)${1} sh -c 'git config -f /srv/local-src/config core.bare true'
+ ${Q}docker container exec $(CB_CPREFIX)${1} sh -c 'git config -f /srv/local-src/config --unset core.worktree || true'
+ ${Q}docker container exec $(CB_CPREFIX)${1} sh -c '[ -d /srv/build ] || git clone /srv/local-src /srv/build'
+ ${Q}docker container exec $(CB_CPREFIX)${1} sh -c '(cd /srv/build && git pull --rebase)'
+ ${Q}docker container exec $(CB_CPREFIX)${1} sh -c '[ -e /srv/build/config.log ] || echo CONFIGURE ${1}'
+ ${Q}docker container exec $(CB_CPREFIX)${1} sh -c '[ -e /srv/build/config.log ] || (cd /srv/build && ./configure -C)' > $(DD)/configure.${1} 2>&1
+
+.PHONY: $(DD)/docker.run.${1}
+$(DD)/docker.run.${1}: $(DD)/docker.refresh.${1}
+ ${Q}echo "TEST ${1} > $(DD)/log.${1}"
+ ${Q}docker container exec $(CB_CPREFIX)${1} sh -c '(cd /srv/build && make && make test)' > $(DD)/log.${1} 2>&1 || echo FAIL ${1}
+
+#
+# Stop the docker container
+#
+.PHONY: crossbuild.${1}.down
+crossbuild.${1}.down:
+ @echo STOP ${1}
+ ${Q}docker container kill $(CB_CPREFIX)${1} || true
+ @rm -f $(DD)/stamp-up.${1}
+
+.PHONY: crossbuild.${1}.clean
+crossbuild.${1}.clean: crossbuild.${1}.down crossbuild.${1}.reset
+
+#
+# Shell into container. cd to root first (will always succeed),
+# then try to change to build dir, which might not exist, then
+# run bash. (Default cwd is the wrong freeradius source in
+# /usr/local, which would be confusing)
+#
+.PHONY: crossbuild.${1}.sh
+crossbuild.${1}.sh: crossbuild.${1}.up
+ ${Q}docker exec -it $(CB_CPREFIX)${1} sh -c 'cd / ; cd /srv/build 2>/dev/null; bash' || true
+
+#
+# Show last build logs. Try and use the most sensible pager.
+#
+.PHONY: crossbuild.${1}.log
+crossbuild.${1}.log:
+ @if which less >/dev/null; then \
+ less +G $(DD)/log.${1};\
+ elif which more >/dev/null; then \
+ more $(DD)/log.${1};\
+ else cat $(DD)/log.${1}; fi
+
+#
+# Tidy up stamp files. This means on next run we'll do
+# everything. Required if e.g. system has been rebooted, so
+# containers are stopped, but the stamp file still exists.
+#
+.PHONY: crossbuild.${1}.reset
+crossbuild.${1}.reset:
+ ${Q}echo RESET ${1}
+ ${Q}rm -f $(DD)/stamp-up.${1}
+ ${Q}rm -f $(DD)/stamp-image.${1}
+
+#
+# Clean down images. Means on next run we'll rebuild the
+# container (rather than just starting it).
+#
+.PHONY: crossbuild.${1}.wipe
+crossbuild.${1}.wipe:
+ ${Q}echo CLEAN ${1}
+ ${Q}docker image rm $(CB_IPREFIX)/${1} >/dev/null 2>&1 || true
+ ${Q}rm -f $(DD)/stamp-image.${1}
+
+#
+# Refresh git repository within the docker image
+#
+.PHONY: crossbuild.${1}.refresh
+crossbuild.${1}.refresh: $(DD)/docker.refresh.${1}
+
+#
+# Run the build test
+#
+.PHONY: crossbuild.${1}
+crossbuild.${1}: $(DD)/docker.run.${1}
+
+endef
+
+#
+# Add all the image building rules
+#
+$(foreach IMAGE,$(CB_IMAGES),\
+ $(eval $(call CROSSBUILD_IMAGE_RULE,$(IMAGE))))
+
+
+# if docker is defined
+endif
diff --git a/scripts/crossbuild/docker/centos7/Dockerfile b/scripts/crossbuild/docker/centos7/Dockerfile
new file mode 100644
index 0000000..2f9e4ac
--- /dev/null
+++ b/scripts/crossbuild/docker/centos7/Dockerfile
@@ -0,0 +1,92 @@
+FROM centos:centos7
+
+#
+# Install devtools like make and git and the EPEL
+# repository for freetds and hiredis
+#
+RUN yum update -y
+RUN yum install -y rpmdevtools openssl epel-release git yum-utils rsync
+
+#
+# Install GCC that has the requisite support for C11 keywords and atomics
+#
+RUN yum install -y centos-release-scl
+RUN yum install -y devtoolset-8-gcc devtoolset-8-gcc-c++
+ENV CC=/opt/rh/devtoolset-8/root/usr/bin/gcc
+
+#
+# Remove the CentOS-SCLo repo which is apparently not valid?
+# See: https://bugs.centos.org/view.php?id=14773
+#
+RUN rm /etc/yum.repos.d/CentOS-SCLo-scl-rh.repo
+RUN rm /etc/yum.repos.d/CentOS-SCLo-scl.repo
+
+#
+# Documentation build dependecies
+#
+
+# - doxygen & JSON.pm
+RUN yum install -y doxygen graphviz perl-JSON
+# - antora (npm needed)
+RUN curl -sL https://rpm.nodesource.com/setup_10.x | bash -
+RUN yum install -y nodejs
+RUN npm i -g @antora/cli@2.1 @antora/site-generator-default@2.1
+# - pandoc
+RUN curl -o - -L $(curl -s https://api.github.com/repos/jgm/pandoc/releases/latest | grep "browser_download_url.*tar.gz" | cut -d '"' -f 4) | tar xzvf - -C /tmp/
+# "
+RUN mv /tmp/pandoc-*/bin/* /usr/local/bin
+# - asciidoctor
+RUN yum install -y rubygems-devel
+RUN gem install asciidoctor
+
+#
+# Setup a src dir in /usr/local
+#
+RUN mkdir -p /usr/local/src/repositories
+WORKDIR /usr/local/src/repositories
+
+#
+# Use LTB's openldap packages intead of the distribution version to avoid linking against NSS
+#
+RUN echo $'[ltb-project]\n\
+name=LTB project packages\n\
+baseurl=https://ltb-project.org/rpm/$releasever/$basearch\n\
+enabled=1\n\
+gpgcheck=1\n\
+gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-LTB-project'\
+> /etc/yum.repos.d/ltb-project.repo
+RUN rpm --import https://ltb-project.org/lib/RPM-GPG-KEY-LTB-project
+
+#
+# Shallow clone the FreeRADIUS source
+#
+WORKDIR /usr/local/src/repositories
+ARG source=https://github.com/FreeRADIUS/freeradius-server.git
+RUN git clone --depth 1 --no-single-branch ${source}
+
+#
+# Install build dependencies for all branches from v3 onwards
+# Nodesource has issues (no SRPMS in some repos) and is not needed here
+#
+WORKDIR freeradius-server
+RUN for i in $(git for-each-ref --format='%(refname:short)' refs/remotes/origin 2>/dev/null | sed -e 's#origin/##' | egrep "^(v[3-9]*\.[0-9x]*\.x|master)$");\
+ do \
+ git checkout $i; \
+ [ -e redhat/freeradius.spec ] && yum-builddep --disablerepo="nodesource*" -y redhat/freeradius.spec; \
+ done
+
+#
+# Which is required by fixture setup utilities
+#
+RUN yum install -y which
+
+#
+# Explicitly install libnl3-devel which is required for the EAP tests
+#
+RUN yum install -y libnl3-devel
+
+#
+# Create the RPM build tree
+#
+ENV BUILDDIR=/root/rpmbuild
+RUN rpmdev-setuptree
diff --git a/scripts/crossbuild/docker/centos8/Dockerfile b/scripts/crossbuild/docker/centos8/Dockerfile
new file mode 100644
index 0000000..bd856af
--- /dev/null
+++ b/scripts/crossbuild/docker/centos8/Dockerfile
@@ -0,0 +1,81 @@
+FROM centos:centos8
+
+#
+# Install devtools like make and git and the EPEL
+# repository for freetds and hiredis
+#
+RUN yum update -y
+RUN yum install -y rpmdevtools openssl epel-release git yum-utils rsync dnf-plugins-core
+RUN dnf config-manager --set-enabled powertools
+
+#
+# Install GCC that has the requisite support for C11 keywords and atomics
+#
+RUN yum install -y gcc-toolset-9
+
+#
+# Documentation build dependecies
+#
+# - doxygen & JSON.pm
+RUN yum install -y doxygen graphviz perl-JSON
+# - antora (npm needed)
+RUN curl -sL https://rpm.nodesource.com/setup_10.x | bash -
+RUN yum install -y nodejs
+RUN npm i -g @antora/cli@2.1 @antora/site-generator-default@2.1
+# - pandoc
+RUN curl -o - -L $(curl -s https://api.github.com/repos/jgm/pandoc/releases/latest | grep "browser_download_url.*tar.gz" | cut -d '"' -f 4) | tar xzvf - -C /tmp/
+RUN mv /tmp/pandoc-*/bin/* /usr/local/bin
+# - asciidoctor
+RUN yum install -y rubygems-devel
+RUN gem install asciidoctor
+
+#
+# Setup a src dir in /usr/local
+#
+RUN mkdir -p /usr/local/src/repositories
+WORKDIR /usr/local/src/repositories
+
+#
+# Use LTB's openldap packages intead of the distribution version to avoid linking against NSS
+#
+RUN echo $'[ltb-project]\n\
+name=LTB project packages\n\
+baseurl=https://ltb-project.org/rpm/$releasever/$basearch\n\
+enabled=1\n\
+gpgcheck=1\n\
+gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-LTB-project'\
+> /etc/yum.repos.d/ltb-project.repo
+RUN rpm --import https://ltb-project.org/lib/RPM-GPG-KEY-LTB-project
+
+#
+# Shallow clone the FreeRADIUS source
+#
+WORKDIR /usr/local/src/repositories
+ARG source=https://github.com/FreeRADIUS/freeradius-server.git
+RUN git clone --depth 1 --no-single-branch ${source}
+
+#
+# Install build dependencies for all branches from v3 onwards
+#
+WORKDIR freeradius-server
+RUN for i in $(git for-each-ref --format='%(refname:short)' refs/remotes/origin 2>/dev/null | sed -e 's#origin/##' | egrep "^(v[3-9]*\.[0-9x]*\.x|master)$");\
+ do \
+ git checkout $i; \
+ [ -e redhat/freeradius.spec ] && yum-builddep -y redhat/freeradius.spec; \
+ done
+
+#
+# Which is required by fixture setup utilities
+#
+RUN yum install -y which
+
+#
+# Explicitly install libnl3-devel which is required for the EAP tests
+#
+RUN yum install -y libnl3-devel
+
+#
+# Create the RPM build tree
+#
+ENV BUILDDIR=/root/rpmbuild
+RUN rpmdev-setuptree
diff --git a/scripts/crossbuild/docker/debian10/Dockerfile b/scripts/crossbuild/docker/debian10/Dockerfile
new file mode 100644
index 0000000..3eb13a7
--- /dev/null
+++ b/scripts/crossbuild/docker/debian10/Dockerfile
@@ -0,0 +1,89 @@
+FROM debian:buster
+
+ARG gccver=8
+ARG clangver=8
+ARG osname=buster
+
+ARG DEBIAN_FRONTEND=noninteractive
+
+#
+# Install add-apt-repository
+#
+RUN apt-get update && \
+ apt-get install -y software-properties-common gnupg2 procps && \
+ apt-get clean && \
+ rm -r /var/lib/apt/lists/*
+
+# For clang
+RUN add-apt-repository -y "deb http://apt.llvm.org/${osname}/ llvm-toolchain-${osname}-${clangver} main" && \
+ apt-key adv --fetch-keys http://apt.llvm.org/llvm-snapshot.gpg.key
+
+RUN apt-get update && \
+# Development utilities
+ apt-get install -y devscripts equivs git quilt rsync && \
+# Compilers
+ apt-get install -y g++-${gccver} llvm-${clangver} clang-${clangver} lldb-${clangver} && \
+# eapol_test dependencies
+ apt-get install -y libnl-3-dev libnl-genl-3-dev
+
+#
+# Documentation build dependecies
+#
+
+# - doxygen & JSON.pm
+RUN apt-get install -y doxygen graphviz libjson-perl
+# - antora (npm needed)
+RUN curl -sL https://deb.nodesource.com/setup_10.x | bash -
+RUN apt-get install -y nodejs
+RUN npm i -g @antora/cli@2.1 @antora/site-generator-default@2.1
+# - pandoc
+WORKDIR /tmp
+RUN curl -OL $(curl -s https://api.github.com/repos/jgm/pandoc/releases/latest | grep "browser_download_url.*deb" | cut -d '"' -f 4)
+RUN apt-get install -y ./pandoc-*.deb
+# - asciidoctor
+RUN apt-get install -y ruby-dev
+RUN gem install asciidoctor
+
+# set default things
+RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-${gccver} 50 \
+ --slave /usr/bin/g++ g++ /usr/bin/g++-${gccver} && \
+ update-alternatives --config gcc
+
+RUN update-alternatives --install /usr/bin/clang clang /usr/bin/clang-${clangver} 60 && \
+ update-alternatives --config clang
+
+RUN update-alternatives --install /usr/bin/lldb lldb /usr/bin/lldb-${clangver} 60 && \
+ update-alternatives --config lldb
+
+
+#
+# Setup a src dir in /usr/local
+#
+RUN mkdir -p /usr/local/src/repositories
+WORKDIR /usr/local/src/repositories
+
+
+#
+# Shallow clone the FreeRADIUS source
+#
+WORKDIR /usr/local/src/repositories
+ARG source=https://github.com/FreeRADIUS/freeradius-server.git
+RUN git clone --depth 1 --no-single-branch ${source}
+
+
+#
+# Install build dependencies for all v3 branches
+#
+WORKDIR freeradius-server
+RUN for i in $(git for-each-ref --format='%(refname:short)' refs/remotes/origin 2>/dev/null | sed -e 's#origin/##' | egrep "^v3\..*\.x");\
+ do \
+ git checkout $i; \
+ if [ -e ./debian/control.in ] ; then \
+ debian/rules debian/control ; \
+ fi ; \
+ echo Installing dependencies for $i ; \
+ mk-build-deps debian/control ; \
+ apt-get --no-install-recommends -y -V install ./freeradius-build-deps*.deb || true ; \
+ apt-get -y -f remove freeradius-build-deps libiodbc2-dev || true ; \
+ rm ./freeradius-build-deps*.deb ; \
+ done
diff --git a/scripts/crossbuild/docker/debian8/Dockerfile b/scripts/crossbuild/docker/debian8/Dockerfile
new file mode 100644
index 0000000..094faa3
--- /dev/null
+++ b/scripts/crossbuild/docker/debian8/Dockerfile
@@ -0,0 +1,84 @@
+FROM debian:jessie
+
+ARG gccver=4.9
+ARG clangver=5.0
+ARG osname=jessie
+
+ARG DEBIAN_FRONTEND=noninteractive
+
+#
+# Install add-apt-repository
+#
+RUN apt-get update && \
+ apt-get install -y software-properties-common python-software-properties apt-transport-https curl && \
+ apt-get clean && \
+ rm -r /var/lib/apt/lists/*
+
+# Requires GCC-4.9 as it has support for C11 keywords and atomics
+
+# For clang
+RUN add-apt-repository -y "deb http://apt.llvm.org/${osname}/ llvm-toolchain-${osname}-${clangver} main" && \
+ curl -o /tmp/llvm-snapshot.gpg.key https://apt.llvm.org/llvm-snapshot.gpg.key && \
+ apt-key add /tmp/llvm-snapshot.gpg.key
+
+RUN apt-get update && \
+# Development utilities
+ apt-get install -y devscripts equivs git quilt rsync && \
+# Compilers
+ apt-get install -y g++-${gccver} llvm-${clangver} clang-${clangver} lldb-${clangver} && \
+# eapol_test dependencies
+ apt-get install -y libnl-3-dev libnl-genl-3-dev
+
+#
+# Documentation build dependecies
+#
+
+# - doxygen & JSON.pm
+RUN apt-get install -y doxygen graphviz libjson-perl
+# - antora (npm needed)
+RUN curl -sL https://deb.nodesource.com/setup_10.x | bash -
+RUN apt-get install -y nodejs
+RUN npm i -g @antora/cli@2.1 @antora/site-generator-default@2.1
+# - pandoc
+WORKDIR /tmp
+RUN curl -OL $(curl -s https://api.github.com/repos/jgm/pandoc/releases/latest | grep "browser_download_url.*deb" | cut -d '"' -f 4)
+RUN dpkg -i ./pandoc-*.deb
+RUN apt-get install -fy
+# - asciidoctor
+RUN apt-get install -y ruby
+RUN gem install asciidoctor
+
+# set default things
+RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-${gccver} 50 \
+ --slave /usr/bin/g++ g++ /usr/bin/g++-${gccver} && \
+ update-alternatives --config gcc
+
+RUN update-alternatives --install /usr/bin/clang clang /usr/bin/clang-${clangver} 60 && \
+ update-alternatives --config clang
+
+RUN update-alternatives --install /usr/bin/lldb lldb /usr/bin/lldb-${clangver} 60 && \
+ update-alternatives --config lldb
+
+
+#
+# Setup a src dir in /usr/local
+#
+RUN mkdir -p /usr/local/src/repositories
+WORKDIR /usr/local/src/repositories
+
+
+#
+# Shallow clone the FreeRADIUS source
+#
+ARG source=https://github.com/FreeRADIUS/freeradius-server.git
+RUN git clone --depth 1 --no-single-branch ${source}
+
+#
+# Install build dependencies for all branches from v3 onwards
+#
+WORKDIR freeradius-server
+RUN for i in $(git for-each-ref --format='%(refname:short)' refs/remotes/origin 2>/dev/null | sed -e 's#origin/##' | egrep "^(v[3-9]*\.[0-9x]*\.x|master)$");\
+ do \
+ git checkout $i; \
+ if [ -e ./debian/control.in ] ; then debian/rules debian/control ; fi ; echo 'y' | mk-build-deps -irt'apt-get -yV' debian/control ; \
+ done
diff --git a/scripts/crossbuild/docker/debian9/Dockerfile b/scripts/crossbuild/docker/debian9/Dockerfile
new file mode 100644
index 0000000..9b47832
--- /dev/null
+++ b/scripts/crossbuild/docker/debian9/Dockerfile
@@ -0,0 +1,84 @@
+FROM debian:stretch
+
+ARG gccver=6
+ARG clangver=5.0
+ARG osname=stretch
+
+ARG DEBIAN_FRONTEND=noninteractive
+
+#
+# Install add-apt-repository
+#
+RUN apt-get update && \
+ apt-get install -y software-properties-common gnupg2 apt-transport-https curl && \
+ apt-get clean && \
+ rm -r /var/lib/apt/lists/*
+
+# Stretch uses GCC-6.3 by default, so it doesn't need to be updated to get C11 functionality.
+
+# For clang
+RUN add-apt-repository -y "deb http://apt.llvm.org/${osname}/ llvm-toolchain-${osname}-${clangver} main" && \
+ curl -o /tmp/llvm-snapshot.gpg.key https://apt.llvm.org/llvm-snapshot.gpg.key && \
+ apt-key add /tmp/llvm-snapshot.gpg.key
+
+RUN apt-get update && \
+# Development utilities
+ apt-get install -y devscripts equivs git quilt rsync && \
+# Compilers
+ apt-get install -y g++-${gccver} llvm-${clangver} clang-${clangver} lldb-${clangver} && \
+# eapol_test dependencies
+ apt-get install -y libnl-3-dev libnl-genl-3-dev
+
+#
+# Documentation build dependecies
+#
+
+# - doxygen & JSON.pm
+RUN apt-get install -y doxygen graphviz libjson-perl
+# - antora (npm needed)
+RUN curl -sL https://deb.nodesource.com/setup_10.x | bash -
+RUN apt-get install -y npm
+RUN npm i -g @antora/cli@2.1 @antora/site-generator-default@2.1
+# - pandoc
+WORKDIR /tmp
+RUN curl -OL $(curl -s https://api.github.com/repos/jgm/pandoc/releases/latest | grep "browser_download_url.*deb" | cut -d '"' -f 4)
+RUN apt-get install -y ./pandoc-*.deb
+# - asciidoctor
+RUN apt-get install -y ruby-dev
+RUN gem install asciidoctor
+
+# set default things
+RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-${gccver} 50 \
+ --slave /usr/bin/g++ g++ /usr/bin/g++-${gccver} && \
+ update-alternatives --config gcc
+
+RUN update-alternatives --install /usr/bin/clang clang /usr/bin/clang-${clangver} 60 && \
+ update-alternatives --config clang
+
+RUN update-alternatives --install /usr/bin/lldb lldb /usr/bin/lldb-${clangver} 60 && \
+ update-alternatives --config lldb
+
+
+#
+# Setup a src dir in /usr/local
+#
+RUN mkdir -p /usr/local/src/repositories
+WORKDIR /usr/local/src/repositories
+
+
+#
+# Shallow clone the FreeRADIUS source
+#
+WORKDIR /usr/local/src/repositories
+ARG source=https://github.com/FreeRADIUS/freeradius-server.git
+RUN git clone --depth 1 --no-single-branch ${source}
+
+#
+# Install build dependencies for all branches from v3 onwards
+#
+WORKDIR freeradius-server
+RUN for i in $(git for-each-ref --format='%(refname:short)' refs/remotes/origin 2>/dev/null | sed -e 's#origin/##' | egrep "^(v[3-9]*\.[0-9x]*\.x|master)$");\
+ do \
+ git checkout $i; \
+ if [ -e ./debian/control.in ] ; then debian/rules debian/control ; fi ; echo 'y' | mk-build-deps -irt'apt-get -yV' debian/control ; \
+ done
diff --git a/scripts/crossbuild/docker/debian9/README b/scripts/crossbuild/docker/debian9/README
new file mode 100644
index 0000000..f7a6135
--- /dev/null
+++ b/scripts/crossbuild/docker/debian9/README
@@ -0,0 +1,15 @@
+
+Build source image
+
+ docker build . -f Dockerfile.source -t freeradius:debian9-source
+
+Then either build and run jenkins image
+
+ docker build . -f Dockerfile.jenkins -t freeradius:debian9-jenkins
+ docker run -d -p 2222:22 freeradius:debian9-jenkins
+
+or build and run the server
+
+ docker build . -t freeradius:debian9
+ docker run -d -p 1812:1812/udp -p 1813:1813/udp freeradius:debian9
+
diff --git a/scripts/crossbuild/docker/ubuntu16/Dockerfile b/scripts/crossbuild/docker/ubuntu16/Dockerfile
new file mode 100644
index 0000000..dbec6f9
--- /dev/null
+++ b/scripts/crossbuild/docker/ubuntu16/Dockerfile
@@ -0,0 +1,86 @@
+FROM ubuntu:16.04
+
+ARG gccver=4.9
+ARG clangver=5.0
+ARG osname=xenial
+
+ARG DEBIAN_FRONTEND=noninteractive
+
+#
+# Install add-apt-repository
+#
+RUN apt-get update && \
+ apt-get install -y software-properties-common python-software-properties apt-transport-https curl && \
+ apt-get clean && \
+ rm -r /var/lib/apt/lists/*
+
+# Requires GCC-4.9 as it has support for C11 keywords and atomics
+
+# For clang
+RUN add-apt-repository -y "deb http://apt.llvm.org/${osname}/ llvm-toolchain-${osname}-${clangver} main" && \
+ curl -o /tmp/llvm-snapshot.gpg.key https://apt.llvm.org/llvm-snapshot.gpg.key && \
+ apt-key add /tmp/llvm-snapshot.gpg.key && \
+# For GCC
+ add-apt-repository -y ppa:ubuntu-toolchain-r/test
+
+RUN apt-get update && \
+# Development utilities
+ apt-get install -y devscripts equivs git quilt rsync && \
+# Compilers
+ apt-get install -y g++-${gccver} llvm-${clangver} clang-${clangver} lldb-${clangver} && \
+# eapol_test dependencies
+ apt-get install -y libnl-3-dev libnl-genl-3-dev
+
+#
+# Documentation build dependecies
+#
+
+# - doxygen & JSON.pm
+RUN apt-get install -y doxygen graphviz libjson-perl
+# - antora (npm needed)
+RUN curl -sL https://deb.nodesource.com/setup_10.x | bash -
+RUN apt-get install -y nodejs
+RUN npm i -g @antora/cli@2.1 @antora/site-generator-default@2.1
+# - pandoc
+WORKDIR /tmp
+RUN curl -OL $(curl -s https://api.github.com/repos/jgm/pandoc/releases/latest | grep "browser_download_url.*deb" | cut -d '"' -f 4)
+RUN apt-get install -y ./pandoc-*.deb
+# - asciidoctor
+RUN apt-get install -y ruby-dev
+RUN gem install asciidoctor
+
+# set default things
+RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-${gccver} 50 \
+ --slave /usr/bin/g++ g++ /usr/bin/g++-${gccver} && \
+ update-alternatives --config gcc
+
+RUN update-alternatives --install /usr/bin/clang clang /usr/bin/clang-${clangver} 60 && \
+ update-alternatives --config clang
+
+RUN update-alternatives --install /usr/bin/lldb lldb /usr/bin/lldb-${clangver} 60 && \
+ update-alternatives --config lldb
+
+
+#
+# Setup a src dir in /usr/local
+#
+RUN mkdir -p /usr/local/src/repositories
+WORKDIR /usr/local/src/repositories
+
+
+#
+# Shallow clone the FreeRADIUS source
+#
+WORKDIR /usr/local/src/repositories
+ARG source=https://github.com/FreeRADIUS/freeradius-server.git
+RUN git clone --depth 1 --no-single-branch ${source}
+
+#
+# Install build dependencies for all branches from v3 onwards
+#
+WORKDIR freeradius-server
+RUN for i in $(git for-each-ref --format='%(refname:short)' refs/remotes/origin 2>/dev/null | sed -e 's#origin/##' | egrep "^(v[3-9]*\.[0-9x]*\.x|master)$");\
+ do \
+ git checkout $i; \
+ if [ -e ./debian/control.in ] ; then debian/rules debian/control ; fi ; echo 'y' | mk-build-deps -irt'apt-get -yV' debian/control ; \
+ done
diff --git a/scripts/crossbuild/docker/ubuntu18/Dockerfile b/scripts/crossbuild/docker/ubuntu18/Dockerfile
new file mode 100644
index 0000000..874e3ec
--- /dev/null
+++ b/scripts/crossbuild/docker/ubuntu18/Dockerfile
@@ -0,0 +1,65 @@
+FROM ubuntu:18.04
+
+ARG gccver=4.9
+ARG clangver=5.0
+ARG osname=bionic
+
+ARG DEBIAN_FRONTEND=noninteractive
+
+#
+# Install add-apt-repository
+#
+RUN apt-get update && \
+ apt-get install -y software-properties-common && \
+ apt-get clean && \
+ rm -r /var/lib/apt/lists/*
+
+RUN apt-get update && \
+# Development utilities
+ apt-get install -y devscripts equivs git quilt rsync && \
+# Compilers
+ apt-get install -y g++ llvm clang lldb && \
+# eapol_test dependencies
+ apt-get install -y libnl-3-dev libnl-genl-3-dev
+
+#
+# Documentation build dependecies
+#
+
+# - doxygen & JSON.pm
+RUN apt-get install -y doxygen graphviz libjson-perl
+# - antora (npm needed)
+RUN curl -sL https://deb.nodesource.com/setup_10.x | bash -
+RUN apt-get install -y nodejs
+RUN npm i -g @antora/cli@2.1 @antora/site-generator-default@2.1
+# - pandoc
+WORKDIR /tmp
+RUN curl -OL $(curl -s https://api.github.com/repos/jgm/pandoc/releases/latest | grep "browser_download_url.*deb" | cut -d '"' -f 4)
+RUN apt-get install -y ./pandoc-*.deb
+# - asciidoctor
+RUN apt-get install -y ruby-dev
+RUN gem install asciidoctor
+
+#
+# Setup a src dir in /usr/local
+#
+RUN mkdir -p /usr/local/src/repositories
+WORKDIR /usr/local/src/repositories
+
+
+#
+# Shallow clone the FreeRADIUS source
+#
+WORKDIR /usr/local/src/repositories
+ARG source=https://github.com/FreeRADIUS/freeradius-server.git
+RUN git clone --depth 1 --no-single-branch ${source}
+
+#
+# Install build dependencies for all branches from v3 onwards
+#
+WORKDIR freeradius-server
+RUN for i in $(git for-each-ref --format='%(refname:short)' refs/remotes/origin 2>/dev/null | sed -e 's#origin/##' | egrep "^(v[3-9]*\.[0-9x]*\.x|master)$");\
+ do \
+ git checkout $i; \
+ if [ -e ./debian/control.in ] ; then debian/rules debian/control ; fi ; echo 'y' | mk-build-deps -irt'apt-get -yV' debian/control ; \
+ done
diff --git a/scripts/crossbuild/docker/ubuntu20/Dockerfile b/scripts/crossbuild/docker/ubuntu20/Dockerfile
new file mode 100644
index 0000000..c813b2f
--- /dev/null
+++ b/scripts/crossbuild/docker/ubuntu20/Dockerfile
@@ -0,0 +1,65 @@
+FROM ubuntu:20.04
+
+ARG gccver=4.9
+ARG clangver=5.0
+ARG osname=bionic
+
+ARG DEBIAN_FRONTEND=noninteractive
+
+#
+# Install add-apt-repository
+#
+RUN apt-get update && \
+ apt-get install -y software-properties-common && \
+ apt-get clean && \
+ rm -r /var/lib/apt/lists/*
+
+RUN apt-get update && \
+# Development utilities
+ apt-get install -y devscripts equivs git quilt rsync && \
+# Compilers
+ apt-get install -y g++ llvm clang lldb && \
+# eapol_test dependencies
+ apt-get install -y libnl-3-dev libnl-genl-3-dev
+
+#
+# Documentation build dependecies
+#
+
+# - doxygen & JSON.pm
+RUN apt-get install -y doxygen graphviz libjson-perl
+# - antora (npm needed)
+RUN curl -sL https://deb.nodesource.com/setup_10.x | bash -
+RUN apt-get install -y nodejs
+RUN npm i -g @antora/cli@2.1 @antora/site-generator-default@2.1
+# - pandoc
+WORKDIR /tmp
+RUN curl -OL $(curl -s https://api.github.com/repos/jgm/pandoc/releases/latest | grep "browser_download_url.*deb" | cut -d '"' -f 4)
+RUN apt-get install -y ./pandoc-*.deb
+# - asciidoctor
+RUN apt-get install -y ruby-dev
+RUN gem install asciidoctor
+
+#
+# Setup a src dir in /usr/local
+#
+RUN mkdir -p /usr/local/src/repositories
+WORKDIR /usr/local/src/repositories
+
+
+#
+# Shallow clone the FreeRADIUS source
+#
+WORKDIR /usr/local/src/repositories
+ARG source=https://github.com/FreeRADIUS/freeradius-server.git
+RUN git clone --depth 1 --no-single-branch ${source}
+
+#
+# Install build dependencies for all branches from v3 onwards
+#
+WORKDIR freeradius-server
+RUN for i in $(git for-each-ref --format='%(refname:short)' refs/remotes/origin 2>/dev/null | sed -e 's#origin/##' | egrep "^(v[3-9]*\.[0-9x]*\.x|master)$");\
+ do \
+ git checkout $i; \
+ if [ -e ./debian/control.in ] ; then debian/rules debian/control ; fi ; echo 'y' | mk-build-deps -irt'apt-get -yV' debian/control ; \
+ done
diff --git a/scripts/cryptpasswd.in b/scripts/cryptpasswd.in
new file mode 100755
index 0000000..dbc0f4f
--- /dev/null
+++ b/scripts/cryptpasswd.in
@@ -0,0 +1,83 @@
+#!@PERL@
+#
+# cryptpasswd Generate or check md5 and DES hashed passwords.
+#
+# 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) 2001 The FreeRADIUS Project http://www.freeradius.org
+#
+# Written by Miquel van Smoorenburg <miquels@cistron-office.nl>
+#
+# $Id$
+#
+
+use Getopt::Long;
+
+sub check_des {
+ return (crypt("fnord", "aa") =~ m/^aa/);
+}
+
+sub check_md5 {
+ return (crypt("fnord", "\$1\$aa") =~ m/^\$1\$/);
+}
+
+sub usage {
+ $name = $0;
+ $name =~ s,.*/,,;
+
+ die "Usage: $name [--des|--md5|--check] plaintext_password [crypted_password]\n";
+}
+
+@saltc = ( '.', '/', '0'..'9', 'A'..'Z', 'a'..'z' );
+
+#
+# MAIN
+#
+sub main {
+
+ Getopt::Long::Configure("no_ignore_case", "bundling");
+ my @options = ( "des|d+", "md5|m+", "check|c+" );
+ usage() unless (eval { Getopt::Long::GetOptions(@options) } );
+
+ if ($opt_check) {
+ usage unless ($#ARGV == 1);
+ if (crypt($ARGV[0], $ARGV[1]) ne $ARGV[1]) {
+ print "Password BAD\n";
+ return 0;
+ } else {
+ print "Password OK\n";
+ return 1;
+ }
+ }
+
+ $opt_des = 1 unless ($opt_des || $opt_md5);
+ usage() unless ($#ARGV == 0);
+
+ die "DES password hashing not available\n"
+ if ($opt_des && !check_des());
+ die "MD5 password hashing not available\n"
+ if ($opt_md5 && !check_md5());
+
+ $salt = ($opt_md5 ? '$1$' : '');
+ for ($i = 0; $i < ($opt_md5 ? 8 : 2); $i++) {
+ $salt .= $saltc[rand 64];
+ }
+ $salt .= '$' if ($opt_md5);
+ print crypt($ARGV[0], $salt), "\n";
+
+ 1;
+}
+
+exit !main();
diff --git a/scripts/dhcp/isc2ippool.pl b/scripts/dhcp/isc2ippool.pl
new file mode 100755
index 0000000..6fb9612
--- /dev/null
+++ b/scripts/dhcp/isc2ippool.pl
@@ -0,0 +1,189 @@
+#!/usr/bin/perl
+
+# isc2ippool Insert ISC DHCPD lease entries into SQL database (ippool).
+#
+# 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) 2012 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
+
+use warnings;
+use strict;
+
+use DateTime;
+use DateTime::Format::Strptime;
+use DateTime::Format::DBI;
+
+use Getopt::Long;
+use Text::DHCPLeases;
+use DBI;
+
+my $lease_file = '/var/db/dhcpd.leases';
+my $sql_type = 'mysql';
+my $sql_host = 'localhost';
+my $sql_user = 'radius';
+my $sql_pass = 'radpass';
+my $sql_database = 'radius';
+my $sql_table = 'dhcpippool';
+my $pool_name = '';
+my $insert_only = 0;
+
+my $verbose;
+my $help;
+
+sub error {
+ print STDERR @_, "\n";
+ exit(64);
+}
+
+sub notice {
+ if ($verbose) {
+ printf(shift . "\n", @_);
+ }
+}
+
+sub help {
+ my @this = split('/', $0);
+ print <<HELP
+$this[$#this] [options] <pool>
+
+Options:
+ -leases <lease file> - The lease file to parse (defaults to '$lease_file')
+ -no-update - Don't update existing lease entries
+ -type - SQL database type (defaults to '$sql_type')
+ -table - SQL table (defaults to '$sql_table')
+ -h | -host - SQL host to connect to
+ -u | -user - SQL user
+ -p | -pass - SQL password
+ -v - Verbose
+ -help - This help text
+HELP
+;
+ exit(0);
+}
+
+GetOptions (
+ 'leases=s' => \$lease_file,
+ 'no-update' => \$insert_only,
+ 'type=s' => \$sql_type,
+ 'table=s' => \$sql_table,
+ 'h|host=s' => \$sql_host,
+ 'u|user=s' => \$sql_user,
+ 'p|pass=s' => \$sql_pass,
+ 'v' => \$verbose,
+ 'help' => \$help
+) or error('Failed parsing options');
+
+#
+# Poolname must be provided, and we need at least some arguments...
+#
+help if !scalar @ARGV or ($pool_name = $ARGV[$#ARGV]) =~ /^-/;
+
+-r $lease_file or
+ error("Lease file ($lease_file) doesn\'t exist or isn't readable");
+
+my $leases = Text::DHCPLeases->new(file => $lease_file) or
+ error("Failed parsing leases file (or lease file empty)");
+
+my $handle = DBI->connect(
+ "DBI:$sql_type:database=$sql_database;host=$sql_host",
+ $sql_user, $sql_pass, {RaiseError => 1}
+);
+
+my $dt_isc = DateTime::Format::Strptime->new(pattern => '%Y/%m/%d %H:%M:%S');
+my $dt_sql = DateTime::Format::DBI->new($handle);
+
+for my $lease ($leases->get_objects) {
+ next unless ($lease->binding_state && $lease->binding_state eq 'active');
+
+ my($query, @result);
+ eval {
+ $query = $handle->prepare("
+ SELECT expiry_time, framedipaddress FROM $sql_table
+ WHERE pool_name = ?
+ AND pool_key = ?;"
+ , undef);
+
+ $query->bind_param(1, $pool_name);
+ $query->bind_param(2, $lease->mac_address);
+
+ $query->execute();
+
+ @result = $query->fetchrow_array();
+ };
+
+ error($@) if $@;
+
+ my $ends_isc = $dt_isc->parse_datetime($lease->ends =~ m{^(?:[0-9]+) (.+)});
+
+ if (!$query->rows) {
+ eval {
+ $handle->do("
+ INSERT INTO $sql_table (
+ pool_name, framedipaddress,
+ expiry_time, pool_key)
+ VALUES (?, ?, ?, ?);"
+ , undef
+ , $pool_name
+ , $lease->ip_address
+ , $dt_sql->format_datetime($ends_isc)
+ , $lease->mac_address
+ );
+ };
+
+ error($@) if $@;
+
+ notice("MAC:'%s' inserted with IP:'%s'.",
+ $lease->mac_address, $lease->ip_address);
+
+ next;
+ }
+
+ my $ends_sql = $dt_sql->parse_datetime($result[0]);
+
+ if ($insert_only && (($result[1] ne $lease->ip_address) ||
+ (DateTime->compare($ends_sql, $ends_isc) < 0))) {
+
+ eval {
+ $handle->do("
+ UPDATE $sql_table
+ SET
+ pool_key = ?, expiry_time = ?
+ WHERE pool_name = ?
+ AND framedipaddress = ?;"
+ , undef
+ , $lease->mac_address
+ , $dt_sql->format_datetime($ends_isc)
+ , $pool_name
+ , $lease->ip_address
+ );
+ };
+
+ error($@) if $@;
+
+ notice("MAC:'%s' updated. ISC-TS: '%s', SQL-TS: '%s', ISC-IP: '%s', SQL-IP: '%s'.",
+ $lease->mac_address,
+ $dt_sql->format_datetime($ends_isc),
+ $dt_sql->format_datetime($ends_sql),
+ $lease->ip_address,
+ $result[1]);
+
+ next;
+ }
+
+ notice("MAC:'%s' skipped (no update %s). ",
+ $lease->mac_address, $insert_only ? 'allowed' : 'needed');
+}
+
+exit(0);
diff --git a/scripts/dhcp/rlm_iscfixed2ippool b/scripts/dhcp/rlm_iscfixed2ippool
new file mode 100755
index 0000000..4ef9365
--- /dev/null
+++ b/scripts/dhcp/rlm_iscfixed2ippool
@@ -0,0 +1,422 @@
+#!/usr/bin/perl -Tw
+
+######################################################################
+#
+# Copyright (C) 2020 Network RADIUS
+#
+# $Id$
+#
+######################################################################
+#
+# Helper script to parse an ISC DHCP config file and extract fixed
+# leases for populating FreeRADIUS ippool tables.
+#
+# This script reads an ISC DCHP config file and extracts any fixed
+# leases. If Net::DNS is available, then any host names are resolved.
+# The resulting list of hardware mac addresses and IP addresses are
+# then formatted as SQL to update a standard FreeRADIUS DHCP ippool
+# table.
+#
+# rlm_iscfixed2ippool -c <dhcpd.conf> -t <table_name> \
+# (-d <sql_dialect> | -f <raddb_dir> [-i <instance>]) \
+# -k <mac|id>
+#
+
+use warnings;
+use strict;
+
+my $dns_available = 0;
+my $resolver;
+eval {
+ require Net::DNS;
+ $dns_available = 1;
+ $resolver = Net::DNS::Resolver->new;
+};
+
+#
+# Option defaults
+#
+my $opts = {
+ dhcpdconf => '/etc/dhcp/dhcpd.conf',
+ key => 'mac'
+};
+
+#
+# Parse the command line arguments
+#
+my $opt = '';
+for (my $i = 0; $i <= $#ARGV; $i++) {
+ if ($ARGV[$i] =~ m/^-(.)$/) {
+ if ($1 eq 'c') {
+ $opt = 'dhcpdconf';
+ } elsif ($1 eq 't') {
+ $opt = 'table_name';
+ } elsif ($1 eq 'd') {
+ $opt = 'dialect';
+ } elsif ($1 eq 'f') {
+ $opt = 'raddb_dir';
+ } elsif ($1 eq 'i') {
+ $opt = 'instance';
+ } elsif ($1 eq 'k') {
+ $opt = 'key'
+ } else {
+ &usage();
+ exit 1;
+ }
+ } else {
+ if ($opt eq '') {
+ &usage();
+ exit 1;
+ } else {
+ $opts->{$opt} = $ARGV[$i]
+ }
+ }
+}
+
+if (($opts->{key} ne 'mac') && ($opts->{key} ne 'id')) {
+ &usage();
+ exit(1);
+}
+
+#
+# If a raddb dir is set then we parse the mods-enabled config
+#
+
+if ($opts->{raddb_dir}) {
+ my $found = 0;
+ if (-d $opts->{raddb_dir}.'/mods-enabled') {
+ opendir(my $dh, $opts->{raddb_dir}.'/mods-enabled') || die 'ERROR: Could not open directory '.$opts->{raddb_dir}.'/mods-enabled';
+ my @dir = grep { -f "$opts->{raddb_dir}/mods-enabled/$_" } readdir($dh);
+ closedir($dh);
+ my $instance = $opts->{instance};
+ foreach my $file (@dir) {
+ open (my $fh, $opts->{raddb_dir}.'/mods-enabled/'.$file);
+ my $level = 0;
+ my $section = '';
+ my $subsection = '';
+ while (<$fh>) {
+ if ($found) {
+ $_ =~ s/#.*//; # Remove comments
+ if ($_ =~ m/\s*([a-z_]+)\s*=\s*(.*)/) {
+ my $param = $1;
+ my $value = $2;
+ $value =~ s/^"//;
+ $value =~ s/"\s*$//;
+ if ($level == 1) {
+ $opts->{$param} = $value;
+ } elsif ($level == 2) {
+ $opts->{$section}->{$param} = $value;
+ } elsif ($level == 3) {
+ $opts->{$section}->{$subsection}->{$param} = $value;
+ }
+ }
+ if ($_ =~ m/([a-z_]*)\s+\{/) { # Find nested sectinos
+ $level++ ;
+ if ($level == 2) {
+ $section = $1;
+ } elsif ($level == 3) {
+ $subsection = $1;
+ }
+ }
+ $level-- if ($_ =~ m/\s+\}/); # Close of nesting
+ last if ($level == 0); # We've got to the end of the instance
+ }
+ if ($_ =~ m/\b$instance\s+\{/) {
+ # We've found the specified SQL instance
+ $found = 1;
+ $level = 1;
+ }
+ }
+ close ($fh);
+ if ($found) {
+ last;
+ }
+ }
+ } else {
+ die 'ERROR: Specified FreeRADIUS config directory does not contain mods-enabled';
+ }
+ if ($found == 0) {
+ die 'ERROR: SQL instance not found in FreeRADIUS config';
+ }
+}
+
+#
+# The SQL dialect and table name must be set
+#
+if ((!($opts->{dialect})) || (!($opts->{table_name}))) {
+ &usage();
+ exit 1;
+}
+
+
+open (my $fh, '<', $opts->{dhcpdconf}) or die "ERROR: Cannot open ISC DHCP config for reading: $opts->{dhcpdconf}";
+
+my $inhost = 0;
+my @hosts;
+my $host = {key => ''};
+while (my $line = <$fh>) {
+ $line = lc($line);
+ if ($inhost == 0) {
+ $inhost = 1 if ($line =~ m/host\s+\S+\s+{/); # We've found the beginning of a host record
+ }
+ if ($inhost) {
+ if (($opts->{key} eq 'mac') && ($line =~ m/hardware\s+ethernet\s+(([0-9a-f]{2}([:;]|\s)){6})/)) {
+ $host->{key} = $1;
+ $host->{key} =~ s/;$//;
+ }
+ if (($opts->{key} eq 'id') && ($line =~ m/dhcp-client-identifier\s+(.*?)\s*;/)) {
+ $host->{key} = $1;
+ }
+ if ($line =~ m/fixed-address\s+(.+);/) {
+ my @addresses = split(',', $1);
+ foreach my $address (@addresses) {
+ $address =~ s/^\s+//;
+ $address =~ s/\s+$//;
+ if ($address =~ m/(([0-9]{1,3}(\.|$)){4})/) {
+ push (@{$host->{ips}}, $1);
+ } elsif ($dns_available) {
+ my $reply = $resolver->search($1, 'A');
+ if ($reply) {
+ foreach my $rr ($reply->answer) {
+ push (@{$host->{ips}}, $rr->address) if ($rr->can('address'))
+ }
+ }
+ }
+ }
+ }
+ if ($line =~ m/}/) { # End of the host record - store the results and clear up
+ push (@hosts, $host) if (($host->{key}) && ($#{$host->{ips}} >= 0));
+ $host = {key => ''};
+ $inhost = 0;
+ }
+ }
+}
+
+close($fh);
+
+my ($template, $queries) = &load_templates($opts->{table_name});
+
+unless (defined $template->{$opts->{dialect}}) {
+ print STDERR "Unknown dialect. Pick one of: ";
+ print STDERR "$_ " foreach sort keys %{$template};
+ print STDERR "\n";
+ exit 1;
+}
+
+if ($opts->{radius_db}) {
+ &call_database($opts, $queries, @hosts);
+} else {
+ my $tt_available = 0;
+ eval {
+ require Template;
+ $tt_available = 1;
+ };
+ if ($tt_available) {
+ my $tt=Template->new();
+ $tt->process(\$template->{$opts->{dialect}}, {tablename => $opts->{table_name}, hosts => \@hosts}) || die $tt->error();
+ } else {
+ die "ERROR: Template Toolkit is not available. Install the Template Perl module.";
+ }
+}
+
+exit(0);
+
+sub usage {
+ print STDERR <<'EOF'
+Usage:
+ rlm_iscfixed2ippool -c <dhcpd.conf> -t <table_name> (-d <sql_dialect> | -f <raddb_dir> [ -i <instance> ]) [-k <mac|id> ]
+
+EOF
+}
+
+
+sub call_database {
+
+ my $opts = shift;
+ my $queries = shift;
+ my @entries = @_;
+
+ my $dbi_avail = 0;
+ eval {
+ require DBI;
+ $dbi_avail = 1;
+ };
+ unless($dbi_avail) {
+ die "ERROR: DBI is not available. Install the DBI Perl module.";
+ }
+
+ my $dsn;
+ if ($opts->{dialect} eq 'mysql') {
+ $dsn = "DBI:mysql:database=$opts->{radius_db};host=$opts->{server}";
+ if (defined($opts->{mysql}->{tls})) {
+ $dsn .= ';mysql_ssl=1';
+ $dsn .= ';mysql_ssl_ca_file='.$opts->{mysql}->{tls}->{ca_file} if ($opts->{mysql}->{tls}->{ca_file});
+ $dsn .= ';mysql_ssl_ca_path='.$opts->{mysql}->{tls}->{ca_path} if ($opts->{mysql}->{tls}->{ca_path});
+ $dsn .= ';mysql_ssl_client_key='.$opts->{mysql}->{tls}->{private_key_file} if ($opts->{mysql}->{tls}->{private_key_file});
+ $dsn .= ';mysql_ssl_client_cert='.$opts->{mysql}->{tls}->{certificate_file} if ($opts->{mysql}->{tls}->{certificate_file});
+ $dsn .= ';mysql_ssl_cipher='.$opts->{mysql}->{tls}->{cipher} if ($opts->{mysql}->{tls}->{cipher});
+ }
+ } elsif ($opts->{dialect} eq 'postgresql') {
+ # Parse FreeRADIUS alternative connection string
+ if ($opts->{radius_db} =~ m/host=(.+?)\b/) {
+ $opts->{server} = $1;
+ }
+ if ($opts->{radius_db} =~ m/user=(.+?)\b/) {
+ $opts->{login} = $1;
+ }
+ if ($opts->{radius_db} =~ m/password=(.+?)\b/) {
+ $opts->{password} = $1;
+ }
+ if ($opts->{radius_db} =~ m/sslmode=(.+?)\b/) {
+ $opts->{sslmode} = $1;
+ }
+ if ($opts->{radius_db} =~ m/dbname=(.+?)\b/) {
+ $opts->{radius_db} = $1;
+ }
+ $dsn = "DBI:Pg:dbname=$opts->{radius_db};host=$opts->{server}";
+ #
+ # DBD doesn't have all the options used by FreeRADIUS - just enable ssl if
+ # FreeRADIUS has SSL options enabled
+ #
+ $dsn .= ';sslmode=prefer' if ($opts->{sslmode});
+ } elsif ($opts->{dialect} eq 'sqlite') {
+ $dsn = "DBI:SQLite:dbname=$opts->{sqlite}->{filename}";
+ } elsif ($opts->{dialect} eq 'mssql') {
+ if ($opts->{driver} eq 'rlm_sql_unixodbc') {
+ $dsn = "DBI:ODBC:DSN=$opts->{server}";
+ } else {
+ $dsn = "DBI:Sybase:server=$opts->{server};database=$opts->{radius_db}";
+ }
+ } elsif ($opts->{dialect} eq 'oracle') {
+ # Extract data from Oracle connection string as used by FreeRADIUS
+ if ($opts->{radius_db} =~ m/HOST=(.+?)\)/) {
+ $opts->{server} = $1;
+ }
+ if ($opts->{radius_db} =~ m/PORT=(.+?)\)/) {
+ $opts->{port} =$1;
+ }
+ if ($opts->{radius_db} =~ m/SID=(.+?)\)/) {
+ $opts->{sid} = $1;
+ }
+ $dsn = "DBI:Oracle:host=$opts->{server};sid=$opts->{sid}";
+ } else {
+ $dsn = "DBI:$opts->{dialect}:database=$opts->{radius_db};host=$opts->{server}";
+ }
+ $dsn .= ";port=$opts->{port}" if ($opts->{port}) && ($opts->{driver} ne 'rlm_sql_unixodbc');
+
+ # Read the results by running our query against the database
+ my $dbh = DBI->connect($dsn, $opts->{login}, $opts->{password}) || die "Unable to connect to database";
+
+ $dbh->do($queries->{$opts->{dialect}}->{pre}) if ($queries->{$opts->{dialect}}->{pre});
+
+ my $sth = $dbh->prepare($queries->{$opts->{dialect}}->{update});
+ foreach my $h (@hosts) {
+ foreach my $i (@{$h->{ips}}) {
+ $sth->execute($h->{key}, $i);
+ }
+ }
+ $sth->finish();
+
+ $dbh->do($queries->{$opts->{dialect}}->{post}) if ($queries->{$opts->{dialect}}->{post});
+
+ $dbh->disconnect();
+}
+
+
+#
+# SQL dialect templates
+#
+
+sub load_templates {
+
+ my $tablename = shift;
+
+ my $template;
+ my $queries;
+#
+# MySQL / MariaDB
+#
+ $queries->{'mysql'}->{pre} = 'START TRANSACTION';
+ $queries->{'mysql'}->{update} = 'UPDATE'.$tablename.' SET pool_key = ?, `status` = "static" WHERE framedipaddress = ?';
+ $queries->{'mysql'}->{post} = 'COMMIT';
+
+ $template->{'mysql'} = $queries->{'mysql'}->{pre}.";\n";
+ $template->{'mysql'} .= <<'END_mysql';
+[%- FOREACH h IN hosts %]
+[%- FOREACH i IN h.ips %]
+UPDATE [% tablename %] SET pool_key = '[% h.key %]', `status` = 'static' WHERE framedipaddress = '[% i %]';
+[%- END %]
+[%- END %]
+END_mysql
+ $template->{'mysql'} .= $queries->{'mysql'}->{post}.";\n";
+
+#
+# PostgreSQL
+#
+ $queries->{'postgresql'}->{pre} = 'START TRANSACTION';
+ $queries->{'postgresql'}->{update} = 'UPDATE'.$tablename.' SET pool_key = ?, status = "static" WHERE framedipaddress = ?';
+ $queries->{'postgresql'}->{post} = 'COMMIT';
+
+ $template->{'postgresql'} = $queries->{'postgresql'}->{pre}.";\n";
+ $template->{'postgresql'} .= <<'END_postgresql';
+[%- FOREACH h IN hosts %]
+[%- FOREACH i IN h.ips %]
+UPDATE [% tablename %] SET pool_key = '[% h.key %]', status = 'static' WHERE framedipaddress = '[% i %]';
+[%- END %]
+[%- END %]
+END_postgresql
+ $template->{'postgresql'} .= $queries->{'postgresql'}->{post}.";\n";
+#
+# Oracle
+#
+ $queries->{'oracle'}->{pre} = '';
+ $queries->{'oracle'}->{update} = 'UPDATE '.$tablename.' SET pool_key = ?, status_id = (SELECT status_id FROM dhcpstatus WHERE status = \'static\') WHERE FramedIPAddress = ?';
+ $queries->{'oracle'}->{post} = 'COMMIT';
+
+ $template->{'oracle'} = <<'END_oracle';
+[%- FOREACH h IN hosts %]
+[%- FOREACH i IN h.ips %]
+UPDATE [% tablename %] SET pool_key = '[% h.key %]', status_id = (SELECT status_id FROM dhcpstatus WHERE status = 'static') WHERE framedipaddress = '[% i %]';
+[%- END %]
+[%- END %]
+END_oracle
+ $template->{'oracle'} .= $queries->{'oracle'}->{post}.";\n";
+
+#
+# SQLite
+#
+ $queries->{'sqlite'}->{pre} = 'BEGIN TRANSACTION';
+ $queries->{'sqlite'}->{update} = 'UPDATE '.$tablename.' SET pool_key = ?, status_id = (SELECT status_id FROM dhcpstatus WHERE status = \'static\') WHERE framedipaddress = ?';
+ $queries->{'sqlite'}->{post} = 'COMMIT';
+
+ $template->{'sqlite'} = $queries->{'sqlite'}->{pre}.";\n";
+ $template->{'sqlite'} .= <<'END_sqlite';
+[%- FOREACH h IN hosts %]
+[%- FOREACH i IN h.ips %]
+UPDATE [% tablename %] SET pool_key = '[% h.key %]', status_id = (SELECT status_id FROM dhcpstatus WHERE status = 'static') WHERE framedipaddress = '[% i %]';
+[%- END %]
+[%- END %]
+END_sqlite
+ $template->{'sqlite'} .= $queries->{'sqlite'}->{post}.";\n";
+
+#
+# MS SQL
+#
+ $queries->{'mssql'}->{pre} = 'BEGIN TRAN';
+ $queries->{'mssql'}->{update} = 'UPDATE '.$tablename.' SET pool_key = ?, status_id = (SELECT status_id FROM dhcpstatus WHERE status = \'static\') WHERE framedipaddress = ?';
+ $queries->{'mssql'}->{post} = 'COMMIT TRAN';
+
+ $template->{'mssql'} = $queries->{'mssql'}->{pre}.";\n";
+ $template->{'mssql'} .= <<'END_mssql';
+[%- FOREACH h IN hosts %]
+[%- FOREACH i IN h.ips %]
+UPDATE [% tablename %] SET pool_key = '[% h.key %]', status_id = (SELECT status_id FROM dhcpstatus WHERE status = 'static') WHERE framedipaddress = '[% i %]';
+[%- END %]
+[%- END %]
+END_mssql
+ $template->{'mssql'} .= $queries->{'mssql'}->{post}.";\n";
+
+ return ($template, $queries);
+
+}
+
diff --git a/scripts/dict_alias.sh b/scripts/dict_alias.sh
new file mode 100755
index 0000000..b573668
--- /dev/null
+++ b/scripts/dict_alias.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+#
+# Print out "ALIAS NAME OID", which lets us import the v3 names into v4.
+#
+
+RADATTR=$(echo $0 | sed 's,dict_alias.sh,../../build/make/jlibtool --quiet --mode=execute ./build/bin/radattr,')
+DICTDIR=$(echo $0 | sed 's,dict_alias.sh,../../share,')
+
+#
+# Print out the attributes,
+# sorted by vendor,
+# split off the comment showing the vendor,
+# reformat so that the name is in a 40-character field
+#
+# The output is ordered by vendor, which makes it easy to split them manually.
+#
+# The output is also ordered by name, instead of by OID. Which is
+# fine, as ordering it by OID is hard. Both for "radattr", and for
+# simple shell scripts.
+#
+$RADATTR -A -D $DICTDIR | sort -n -k5 | sed 's/ #.*//' | awk '{printf "%s\t%-40s\t%s\n", $1, $2, $3 }'
diff --git a/scripts/docker/README.md b/scripts/docker/README.md
new file mode 100644
index 0000000..f6e9ae6
--- /dev/null
+++ b/scripts/docker/README.md
@@ -0,0 +1,200 @@
+# What is FreeRADIUS?
+
+The FreeRADIUS Server Project is a high performance and highly
+configurable multi-protocol policy server, supporting RADIUS, DHCPv4
+and VMPS. Using RADIUS allows authentication and authorization for a network
+to be centralized, and minimizes the number of changes that have to
+be done when adding or deleting new users to a network.
+
+FreeRADIUS can authenticate users on systems such as 802.1x
+(WiFi), dialup, PPPoE, VPN's, VoIP, and many others. It supports
+back-end databases such as MySQL, PostgreSQL, Oracle, Microsoft
+Active Directory, Redis, OpenLDAP. It is used daily to
+authenticate the Internet access for hundreds of millions of
+people, in sites ranging from 10 to 10 million+ users.
+
+> [wikipedia.org/wiki/FreeRADIUS](https://en.wikipedia.org/wiki/FreeRADIUS)
+
+
+# How to use this image
+
+## Starting the server
+
+```console
+$ docker run --name my-radius -d freeradius/freeradius-server
+```
+
+The image contains only the default FreeRADIUS configuration which
+has no users, and accepts test clients on 127.0.0.1. In order to
+use it in production, as a minimum you will need to add clients to
+the `clients.conf` file, and users to the "users" file in
+`mods-config/files/authorize`.
+
+**Without building a local image with a configuration, the
+container will refuse to answer any queries.**
+
+
+## Defining a local configuration
+
+Create a local `Dockerfile` based on the required image and
+COPY in the server configuration.
+
+```Dockerfile
+FROM freeradius/freeradius-server:latest
+COPY raddb/ /etc/raddb/
+```
+
+The `raddb` directory could contain, for example:
+
+```
+clients.conf
+mods-config/
+mods-config/files/
+mods-config/files/authorize
+```
+
+Where `clients.conf` contains a simple client definition
+
+```
+client dockernet {
+ ipaddr = 172.17.0.0/16
+ secret = testing123
+}
+```
+
+and the `authorize` "users" file contains a test user:
+
+```
+bob Cleartext-Password := "test"
+```
+
+Build the image locally:
+
+```console
+$ docker build -t my-radius-image -f Dockerfile .
+```
+
+
+## Using the local configuration
+
+It should now be possible to test authentication against the
+server from the host machine, using the `radtest` utility supplied
+with FreeRADIUS and the credentials defined above.
+
+Start the local container. Ports will need to be forwarded to the
+server, typically 1812/udp and/or 1813/udp, for example:
+
+```console
+docker run --rm -d --name my-radius -p 1812-1813:1812-1813/udp my-radius-image
+```
+
+Send a test request, you will need the `radtest` utility:
+
+```console
+$ radtest bob test 127.0.0.1 0 testing123
+```
+
+which should return an "Access-Accept".
+
+The image can now be stopped with:
+
+```console
+docker stop my-radius
+```
+
+
+## Running in debug mode
+
+FreeRADIUS should always be tested in debug mode, using option
+`-X`. Coloured debug output also requres `-t` be passed to docker.
+
+```console
+$ docker run --rm --name my-radius -t -p 1812-1813:1812-1813/udp freeradius/freeradius-server -X
+```
+
+Guidelines for how to read and interpret the debug output are on the
+[FreeRADIUS Wiki](https://wiki.freeradius.org/radiusd-X).
+
+
+## Security notes
+
+The configuration in the docker image comes with self-signed
+certificates for convenience. These should not be used in a
+production environment, but replaced with new certificates. See
+the file `raddb/certs/README.md` for more information.
+
+
+## Debugging
+
+By default if you try to use `gdb` in a Docker container, the
+pattach call will fail, and you will not be able to trace
+processes.
+
+In order to allow tracing, the ``--privileged`` flag must be
+passed to ``docker run``, this restores any Linux ``cap``
+privileges that would not ordinarily be given.
+
+
+# Image variants
+
+## `freeradius/freeradius-server:<version>`
+
+The de-facto image which should be used unless you know you need
+another image. It is based on
+[Ubuntu Linux](https://hub.docker.com/_/ubuntu/) Docker images.
+
+
+## `freeradius/freeradius-server:<version>-alpine`
+
+Image based on the [Alpine Linux](https://hub.docker.com/_/alpine/)
+Docker images, which are much smaller than most Linux
+distributions. To keep the basic size as small as possible, **this
+image does not include libraries for all modules that have been
+built** (especially the languages such as Perl or Python). Therefore
+these extra libraries will need to be installed with `apk add` in
+your own Dockerfile if you intend on using modules that require
+them.
+
+
+# Building Docker images
+
+The FreeRADIUS source contains Dockerfiles for several Linux
+distributions. They are in
+[`freeradius-server/scripts/docker/<os_name>`](https://github.com/FreeRADIUS/freeradius-server/tree/v3.2.x/scripts/docker).
+
+Build an image with
+
+```bash
+$ cd scripts/docker/<os_name>
+$ docker build . -t freeradius-<os_name>
+```
+
+This will download the OS base image, install/build any dependencies
+as necessary, perform a shallow clone of the FreeRADIUS source and
+build the server.
+
+Once built, running ``docker images`` should show the image.
+
+```bash
+$ docker images
+REPOSITORY TAG IMAGE ID CREATED SIZE
+freeradius-ubuntu16 latest 289b3c7aca94 4 minutes ago 218MB
+freeradius-alpine latest d7fb3041bea2 2 hours ago 88.6MB
+```
+
+
+## Build args
+
+Two ARGs are defined in the Dockerfiles that specify the source
+repository and git tag that the release will be built from. These
+are
+
+- source: the git repository URL
+- release: the git commit/tag
+
+To build the image from a specific repository and git tag, set one
+or both of these args:
+
+```console
+$ docker build . --build-arg=release=v3.2.x --build-arg=source=https://github.com/FreeRADIUS/freeradius-server.git -t freeradius-<os_name>
+```
diff --git a/scripts/docker/alpine/Dockerfile b/scripts/docker/alpine/Dockerfile
new file mode 100644
index 0000000..2965525
--- /dev/null
+++ b/scripts/docker/alpine/Dockerfile
@@ -0,0 +1,83 @@
+ARG from=alpine:3.13
+FROM ${from} as build
+
+#
+# Install build tools
+#
+RUN apk update
+RUN apk add git gcc make
+
+#
+# Create build directory
+#
+RUN mkdir -p /usr/local/src/repositories
+WORKDIR /usr/local/src/repositories
+
+#
+# Shallow clone the FreeRADIUS source
+#
+ARG source=https://github.com/FreeRADIUS/freeradius-server.git
+ARG release=v3.2.x
+
+RUN git clone --depth 1 --single-branch --branch ${release} ${source}
+WORKDIR freeradius-server
+
+#
+# Install build dependencies
+#
+# essential
+RUN apk add libc-dev talloc-dev
+RUN apk add openssl openssl-dev
+RUN apk add linux-headers
+# general
+RUN apk add pcre-dev libidn-dev krb5-dev samba-dev curl-dev json-c-dev
+RUN apk add openldap-dev unbound-dev
+# languages
+RUN apk add ruby-dev perl-dev python2-dev
+# databases
+RUN apk add hiredis-dev libmemcached-dev gdbm-dev libcouchbase-dev
+# sql
+RUN apk add postgresql-dev mariadb-dev unixodbc-dev sqlite-dev
+
+#
+# Build the server
+#
+RUN ./configure --prefix=/opt
+RUN make -j2
+RUN make install
+RUN rm /opt/lib/*.a
+
+#
+# Clean environment and run the server
+#
+FROM ${from}
+COPY --from=build /opt /opt
+
+#
+# These are needed for the server to start
+#
+RUN apk update \
+ && apk add talloc libressl pcre libwbclient tzdata \
+ \
+#
+# Libraries that are needed dependent on which modules are used
+# Some of these (especially the languages) are huge. A reasonable
+# selection has been enabled here. If you use modules needing
+# other dependencies then install any others required in your
+# local Dockerfile.
+#
+ && apk add libcurl json-c libldap hiredis sqlite-dev \
+#RUN apk add libidn krb5
+#RUN apk add unbound-libs
+#RUN apk add ruby-libs perl python2-dev
+#RUN apk add libmemcached gdbm libcouchbase
+#RUN apk add postgresql-dev mariadb-dev unixodbc-dev
+ \
+ && ln -s /opt/etc/raddb /etc/raddb
+
+COPY docker-entrypoint.sh /
+RUN chmod +x /docker-entrypoint.sh
+
+EXPOSE 1812/udp 1813/udp
+ENTRYPOINT ["/docker-entrypoint.sh"]
+CMD ["radiusd"]
diff --git a/scripts/docker/alpine/docker-entrypoint.sh b/scripts/docker/alpine/docker-entrypoint.sh
new file mode 100755
index 0000000..e0f9f6f
--- /dev/null
+++ b/scripts/docker/alpine/docker-entrypoint.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+set -e
+
+PATH=/opt/sbin:/opt/bin:$PATH
+export PATH
+
+# this if will check if the first argument is a flag
+# but only works if all arguments require a hyphenated flag
+# -v; -SL; -f arg; etc will work, but not arg1 arg2
+if [ "$#" -eq 0 ] || [ "${1#-}" != "$1" ]; then
+ set -- radiusd "$@"
+fi
+
+# check for the expected command
+if [ "$1" = 'radiusd' ]; then
+ shift
+ exec radiusd -f "$@"
+fi
+
+# debian people are likely to call "freeradius" as well, so allow that
+if [ "$1" = 'freeradius' ]; then
+ shift
+ exec radiusd -f "$@"
+fi
+
+# else default to run whatever the user wanted like "bash" or "sh"
+exec "$@"
diff --git a/scripts/docker/centos7/Dockerfile b/scripts/docker/centos7/Dockerfile
new file mode 100644
index 0000000..efa56eb
--- /dev/null
+++ b/scripts/docker/centos7/Dockerfile
@@ -0,0 +1,96 @@
+ARG from=centos:centos7
+FROM ${from} as build
+
+#
+# Install build tools
+#
+RUN yum groupinstall -y "Development Tools"
+RUN yum install -y rpmdevtools
+RUN yum install -y openssl
+
+#
+# Create build directory
+#
+RUN mkdir -p /usr/local/src/repositories
+WORKDIR /usr/local/src/repositories
+
+#
+# Shallow clone the FreeRADIUS source
+#
+ARG source=https://github.com/FreeRADIUS/freeradius-server.git
+ARG release=v3.2.x
+
+RUN git clone --depth 1 --single-branch --branch ${release} ${source}
+WORKDIR freeradius-server
+
+#
+# Other requirements
+#
+
+# Use LTB's openldap packages intead of the distribution version to avoid linking against NSS
+RUN echo $'[ltb-project]\n\
+name=LTB project packages\n\
+baseurl=https://ltb-project.org/rpm/$releasever/$basearch\n\
+enabled=1\n\
+gpgcheck=1\n\
+gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-LTB-project'\
+> /etc/yum.repos.d/ltb-project.repo
+RUN rpm --import https://ltb-project.org/lib/RPM-GPG-KEY-LTB-project
+
+# EPEL repository for freetds and hiredis
+RUN yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
+
+#
+# Install build dependencies
+#
+RUN [ -e redhat/freeradius.spec ] && yum-builddep -y redhat/freeradius.spec
+
+#
+# Create RPM build environment
+#
+ENV BUILDDIR=/root/rpmbuild
+RUN rpmdev-setuptree
+
+RUN ./configure
+RUN make freeradius-server-$(cat VERSION).tar.bz2
+RUN cp freeradius-server-$(cat VERSION).tar.bz2 $BUILDDIR/SOURCES/
+RUN cp -r redhat/* $BUILDDIR/SOURCES/
+RUN cp -r redhat/freeradius.spec $BUILDDIR/SPECS/
+WORKDIR $BUILDDIR
+
+#
+# Build the server
+#
+ENV QA_RPATHS=0x0003
+RUN rpmbuild -bb --define '_release $release' "$BUILDDIR/SPECS/freeradius.spec"
+
+RUN mkdir /root/rpms
+RUN mv $BUILDDIR/RPMS/*/*.rpm /root/rpms/
+
+#
+# Clean environment and run the server
+#
+FROM ${from}
+COPY --from=build /root/rpms /tmp/
+
+# Use LTB's openldap packages intead of the distribution version to avoid linking against NSS
+RUN echo $'[ltb-project]\n\
+name=LTB project packages\n\
+baseurl=https://ltb-project.org/rpm/$releasever/$basearch\n\
+enabled=1\n\
+gpgcheck=1\n\
+gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-LTB-project'\
+> /etc/yum.repos.d/ltb-project.repo \
+ && rpm --import https://ltb-project.org/lib/RPM-GPG-KEY-LTB-project \
+ \
+# EPEL repository for freetds and hiredis
+ && yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm \
+ \
+ && yum install -y /tmp/*.rpm
+
+COPY docker-entrypoint.sh /
+RUN chmod +x /docker-entrypoint.sh
+
+EXPOSE 1812/udp 1813/udp
+ENTRYPOINT ["/docker-entrypoint.sh"]
+CMD ["radiusd"]
diff --git a/scripts/docker/centos7/docker-entrypoint.sh b/scripts/docker/centos7/docker-entrypoint.sh
new file mode 100755
index 0000000..900ad6b
--- /dev/null
+++ b/scripts/docker/centos7/docker-entrypoint.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+set -e
+
+# this if will check if the first argument is a flag
+# but only works if all arguments require a hyphenated flag
+# -v; -SL; -f arg; etc will work, but not arg1 arg2
+if [ "$#" -eq 0 ] || [ "${1#-}" != "$1" ]; then
+ set -- radiusd "$@"
+fi
+
+# check for the expected command
+if [ "$1" = 'radiusd' ]; then
+ shift
+ exec radiusd -f "$@"
+fi
+
+# debian people are likely to call "freeradius" as well, so allow that
+if [ "$1" = 'freeradius' ]; then
+ shift
+ exec radiusd -f "$@"
+fi
+
+# else default to run whatever the user wanted like "bash" or "sh"
+exec "$@"
diff --git a/scripts/docker/debian10/Dockerfile b/scripts/docker/debian10/Dockerfile
new file mode 100644
index 0000000..441bed7
--- /dev/null
+++ b/scripts/docker/debian10/Dockerfile
@@ -0,0 +1,59 @@
+ARG from=debian:buster
+FROM ${from} as build
+
+ARG DEBIAN_FRONTEND=noninteractive
+
+#
+# Install build tools
+#
+RUN apt-get update
+RUN apt-get install -y devscripts equivs git quilt gcc
+
+#
+# Create build directory
+#
+RUN mkdir -p /usr/local/src/repositories
+WORKDIR /usr/local/src/repositories
+
+#
+# Shallow clone the FreeRADIUS source
+#
+ARG source=https://github.com/FreeRADIUS/freeradius-server.git
+ARG release=v3.2.x
+
+RUN git clone --depth 1 --single-branch --branch ${release} ${source}
+WORKDIR freeradius-server
+
+#
+# Install build dependencies
+#
+RUN git checkout ${release}; \
+ if [ -e ./debian/control.in ]; then \
+ debian/rules debian/control; \
+ fi; \
+ echo 'y' | mk-build-deps -irt'apt-get -yV' debian/control
+
+#
+# Build the server
+#
+RUN make -j2 deb
+
+#
+# Clean environment and run the server
+#
+FROM ${from}
+COPY --from=build /usr/local/src/repositories/*.deb /tmp/
+
+RUN apt-get update \
+ && apt-get install -y /tmp/*.deb \
+ && apt-get clean \
+ && rm -r /var/lib/apt/lists/* /tmp/*.deb \
+ \
+ && ln -s /etc/freeradius /etc/raddb
+
+COPY docker-entrypoint.sh /
+RUN chmod +x /docker-entrypoint.sh
+
+EXPOSE 1812/udp 1813/udp
+ENTRYPOINT ["/docker-entrypoint.sh"]
+CMD ["freeradius"]
diff --git a/scripts/docker/debian10/docker-entrypoint.sh b/scripts/docker/debian10/docker-entrypoint.sh
new file mode 100755
index 0000000..93141b0
--- /dev/null
+++ b/scripts/docker/debian10/docker-entrypoint.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+set -e
+
+# this if will check if the first argument is a flag
+# but only works if all arguments require a hyphenated flag
+# -v; -SL; -f arg; etc will work, but not arg1 arg2
+if [ "$#" -eq 0 ] || [ "${1#-}" != "$1" ]; then
+ set -- freeradius "$@"
+fi
+
+# check for the expected command
+if [ "$1" = 'freeradius' ]; then
+ shift
+ exec freeradius -f "$@"
+fi
+
+# many people are likely to call "radiusd" as well, so allow that
+if [ "$1" = 'radiusd' ]; then
+ shift
+ exec freeradius -f "$@"
+fi
+
+# else default to run whatever the user wanted like "bash" or "sh"
+exec "$@"
diff --git a/scripts/docker/debian11/Dockerfile b/scripts/docker/debian11/Dockerfile
new file mode 100644
index 0000000..7a9931c
--- /dev/null
+++ b/scripts/docker/debian11/Dockerfile
@@ -0,0 +1,64 @@
+ARG from=debian:bullseye
+FROM ${from} as build
+
+ARG DEBIAN_FRONTEND=noninteractive
+
+#
+# Install build tools
+#
+RUN apt-get update
+RUN apt-get install -y devscripts equivs git quilt gcc
+
+#
+# Create build directory
+#
+RUN mkdir -p /usr/local/src/repositories
+WORKDIR /usr/local/src/repositories
+
+#
+# Shallow clone the FreeRADIUS source
+#
+ARG source=https://github.com/FreeRADIUS/freeradius-server.git
+ARG release=v3.2.x
+
+RUN git clone --depth 1 --single-branch --branch ${release} ${source}
+WORKDIR freeradius-server
+
+#
+# Install build dependencies
+#
+RUN git checkout ${release}; \
+ if [ -e ./debian/control.in ]; then \
+ debian/rules debian/control; \
+ fi; \
+ echo 'y' | mk-build-deps -irt'apt-get -yV' debian/control
+
+#
+# Build the server
+#
+RUN make -j2 deb
+
+#
+# Clean environment and run the server
+#
+FROM ${from}
+COPY --from=build /usr/local/src/repositories/*.deb /tmp/
+
+ARG freerad_uid=101
+ARG freerad_gid=101
+
+RUN groupadd -g ${freerad_gid} -r freerad \
+ && useradd -u ${freerad_uid} -g freerad -r -M -d /etc/freeradius -s /usr/sbin/nologin freerad \
+ && apt-get update \
+ && apt-get install -y /tmp/*.deb \
+ && apt-get clean \
+ && rm -r /var/lib/apt/lists/* /tmp/*.deb \
+ \
+ && ln -s /etc/freeradius /etc/raddb
+
+COPY docker-entrypoint.sh /
+RUN chmod +x /docker-entrypoint.sh
+
+EXPOSE 1812/udp 1813/udp
+ENTRYPOINT ["/docker-entrypoint.sh"]
+CMD ["freeradius"]
diff --git a/scripts/docker/debian11/docker-entrypoint.sh b/scripts/docker/debian11/docker-entrypoint.sh
new file mode 100755
index 0000000..93141b0
--- /dev/null
+++ b/scripts/docker/debian11/docker-entrypoint.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+set -e
+
+# this if will check if the first argument is a flag
+# but only works if all arguments require a hyphenated flag
+# -v; -SL; -f arg; etc will work, but not arg1 arg2
+if [ "$#" -eq 0 ] || [ "${1#-}" != "$1" ]; then
+ set -- freeradius "$@"
+fi
+
+# check for the expected command
+if [ "$1" = 'freeradius' ]; then
+ shift
+ exec freeradius -f "$@"
+fi
+
+# many people are likely to call "radiusd" as well, so allow that
+if [ "$1" = 'radiusd' ]; then
+ shift
+ exec freeradius -f "$@"
+fi
+
+# else default to run whatever the user wanted like "bash" or "sh"
+exec "$@"
diff --git a/scripts/docker/debian9/Dockerfile b/scripts/docker/debian9/Dockerfile
new file mode 100644
index 0000000..1a34f7f
--- /dev/null
+++ b/scripts/docker/debian9/Dockerfile
@@ -0,0 +1,59 @@
+ARG from=debian:stretch
+FROM ${from} as build
+
+ARG DEBIAN_FRONTEND=noninteractive
+
+#
+# Install build tools
+#
+RUN apt-get update
+RUN apt-get install -y devscripts equivs git quilt gcc
+
+#
+# Create build directory
+#
+RUN mkdir -p /usr/local/src/repositories
+WORKDIR /usr/local/src/repositories
+
+#
+# Shallow clone the FreeRADIUS source
+#
+ARG source=https://github.com/FreeRADIUS/freeradius-server.git
+ARG release=v3.2.x
+
+RUN git clone --depth 1 --single-branch --branch ${release} ${source}
+WORKDIR freeradius-server
+
+#
+# Install build dependencies
+#
+RUN git checkout ${release}; \
+ if [ -e ./debian/control.in ]; then \
+ debian/rules debian/control; \
+ fi; \
+ echo 'y' | mk-build-deps -irt'apt-get -yV' debian/control
+
+#
+# Build the server
+#
+RUN make -j2 deb
+
+#
+# Clean environment and run the server
+#
+FROM ${from}
+COPY --from=build /usr/local/src/repositories/*.deb /tmp/
+
+RUN apt-get update \
+ && apt-get install -y /tmp/*.deb \
+ && apt-get clean \
+ && rm -r /var/lib/apt/lists/* /tmp/*.deb \
+ \
+ && ln -s /etc/freeradius /etc/raddb
+
+COPY docker-entrypoint.sh /
+RUN chmod +x /docker-entrypoint.sh
+
+EXPOSE 1812/udp 1813/udp
+ENTRYPOINT ["/docker-entrypoint.sh"]
+CMD ["freeradius"]
diff --git a/scripts/docker/debian9/docker-entrypoint.sh b/scripts/docker/debian9/docker-entrypoint.sh
new file mode 100755
index 0000000..93141b0
--- /dev/null
+++ b/scripts/docker/debian9/docker-entrypoint.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+set -e
+
+# this if will check if the first argument is a flag
+# but only works if all arguments require a hyphenated flag
+# -v; -SL; -f arg; etc will work, but not arg1 arg2
+if [ "$#" -eq 0 ] || [ "${1#-}" != "$1" ]; then
+ set -- freeradius "$@"
+fi
+
+# check for the expected command
+if [ "$1" = 'freeradius' ]; then
+ shift
+ exec freeradius -f "$@"
+fi
+
+# many people are likely to call "radiusd" as well, so allow that
+if [ "$1" = 'radiusd' ]; then
+ shift
+ exec freeradius -f "$@"
+fi
+
+# else default to run whatever the user wanted like "bash" or "sh"
+exec "$@"
diff --git a/scripts/docker/debiansid/Dockerfile b/scripts/docker/debiansid/Dockerfile
new file mode 100644
index 0000000..191ec49
--- /dev/null
+++ b/scripts/docker/debiansid/Dockerfile
@@ -0,0 +1,64 @@
+ARG from=debian:sid
+FROM ${from} as build
+
+ARG DEBIAN_FRONTEND=noninteractive
+
+#
+# Install build tools
+#
+RUN apt-get update
+RUN apt-get install -y devscripts equivs git quilt gcc
+
+#
+# Create build directory
+#
+RUN mkdir -p /usr/local/src/repositories
+WORKDIR /usr/local/src/repositories
+
+#
+# Shallow clone the FreeRADIUS source
+#
+ARG source=https://github.com/FreeRADIUS/freeradius-server.git
+ARG release=v3.2.x
+
+RUN git clone --depth 1 --single-branch --branch ${release} ${source}
+WORKDIR freeradius-server
+
+#
+# Install build dependencies
+#
+RUN git checkout ${release}; \
+ if [ -e ./debian/control.in ]; then \
+ debian/rules debian/control; \
+ fi; \
+ echo 'y' | mk-build-deps -irt'apt-get -yV' debian/control
+
+#
+# Build the server
+#
+RUN make -j2 deb
+
+#
+# Clean environment and run the server
+#
+FROM ${from}
+COPY --from=build /usr/local/src/repositories/*.deb /tmp/
+
+ARG freerad_uid=101
+ARG freerad_gid=101
+
+RUN groupadd -g ${freerad_gid} -r freerad \
+ && useradd -u ${freerad_uid} -g freerad -r -M -d /etc/freeradius -s /usr/sbin/nologin freerad \
+ && apt-get update \
+ && apt-get install -y /tmp/*.deb \
+ && apt-get clean \
+ && rm -r /var/lib/apt/lists/* /tmp/*.deb \
+ \
+ && ln -s /etc/freeradius /etc/raddb
+
+COPY docker-entrypoint.sh /
+RUN chmod +x /docker-entrypoint.sh
+
+EXPOSE 1812/udp 1813/udp
+ENTRYPOINT ["/docker-entrypoint.sh"]
+CMD ["freeradius"]
diff --git a/scripts/docker/debiansid/docker-entrypoint.sh b/scripts/docker/debiansid/docker-entrypoint.sh
new file mode 100755
index 0000000..93141b0
--- /dev/null
+++ b/scripts/docker/debiansid/docker-entrypoint.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+set -e
+
+# this if will check if the first argument is a flag
+# but only works if all arguments require a hyphenated flag
+# -v; -SL; -f arg; etc will work, but not arg1 arg2
+if [ "$#" -eq 0 ] || [ "${1#-}" != "$1" ]; then
+ set -- freeradius "$@"
+fi
+
+# check for the expected command
+if [ "$1" = 'freeradius' ]; then
+ shift
+ exec freeradius -f "$@"
+fi
+
+# many people are likely to call "radiusd" as well, so allow that
+if [ "$1" = 'radiusd' ]; then
+ shift
+ exec freeradius -f "$@"
+fi
+
+# else default to run whatever the user wanted like "bash" or "sh"
+exec "$@"
diff --git a/scripts/docker/docker.mk b/scripts/docker/docker.mk
new file mode 100644
index 0000000..9773625
--- /dev/null
+++ b/scripts/docker/docker.mk
@@ -0,0 +1,86 @@
+#
+# Docker-related targets
+#
+# Intended for internal use to publish Docker images to docker hub. Likely need to run
+# "docker login" before any push commands.
+#
+# Examples:
+#
+# Publish to Dockerhub "freeradius-server"
+# make DOCKER_VERSION=3.2.0 DOCKER_BUILD_ARGS="--no-cache" docker-publish
+#
+# Build and push "freeradius-dev" image to Dockerhub (e.g. CI on every commit):
+# make DOCKER_VERSION=latest DOCKER_COMMIT=v3.2.x DOCKER_TAG="freeradius-dev-3.2.x" DOCKER_BUILD_ARGS="--no-cache" docker-push
+#
+# Push to local repository:
+# make DOCKER_VERSION=3.2.0 DOCKER_TAG="our-freeradius-build" DOCKER_REGISTRY="docker.somewhere.example" docker-publish
+#
+# See what is going to happen:
+# make Q=": " ...
+#
+#
+# Variables:
+#
+# Which version to tag as, e.g. "3.2.0". If this is not an actual release
+# version, DOCKER_COMMIT _must_ also be set.
+DOCKER_VERSION := $(RADIUSD_VERSION_STRING)
+#
+# Commit hash/tag/branch to build, will be taken from VERSION above if not overridden, e.g. "release_3_2_0"
+DOCKER_COMMIT := release_$(shell echo $(DOCKER_VERSION) | tr .- __)
+#
+# Build args, most likely "--no-cache"
+DOCKER_BUILD_ARGS :=
+#
+# Tag name, likely "freeradius-server" for releases, or "freeradius-dev" for nightlies.
+DOCKER_TAG := freeradius-server
+#
+# Repository name
+DOCKER_REPO := freeradius
+#
+# Registry to push to
+DOCKER_REGISTRY :=
+#
+
+ifneq "$(DOCKER_REPO)" ""
+ override DOCKER_REPO := $(DOCKER_REPO)/
+endif
+
+ifneq "$(DOCKER_REGISTRY)" ""
+ override DOCKER_REGISTRY := $(DOCKER_REGISTRY)/
+endif
+
+
+.PHONY: docker-ubuntu
+docker-ubuntu:
+ @echo Building ubuntu $(DOCKER_COMMIT)
+ $(Q)docker build $(DOCKER_BUILD_ARGS) scripts/docker/ubuntu22 --build-arg=release=$(DOCKER_COMMIT) -t $(DOCKER_REGISTRY)$(DOCKER_REPO)$(DOCKER_TAG):$(DOCKER_VERSION)
+
+.PHONY: docker-alpine
+docker-alpine:
+ @echo Building alpine $(DOCKER_COMMIT)
+ $(Q)docker build $(DOCKER_BUILD_ARGS) scripts/docker/alpine --build-arg=release=$(DOCKER_COMMIT) -t $(DOCKER_REGISTRY)$(DOCKER_REPO)$(DOCKER_TAG):$(DOCKER_VERSION)-alpine
+
+.PHONY: docker
+docker: docker-ubuntu docker-alpine
+
+.PHONY: docker-push
+docker-push: docker
+ $(Q)docker push $(DOCKER_REGISTRY)$(DOCKER_REPO)$(DOCKER_TAG):$(DOCKER_VERSION)
+ $(Q)docker push $(DOCKER_REGISTRY)$(DOCKER_REPO)$(DOCKER_TAG):$(DOCKER_VERSION)-alpine
+
+.PHONY: docker-tag-latest
+docker-tag-latest: docker
+ $(Q)docker tag $(DOCKER_REGISTRY)$(DOCKER_REPO)$(DOCKER_TAG):$(DOCKER_VERSION) $(DOCKER_REGISTRY)$(DOCKER_REPO)$(DOCKER_TAG):latest
+ $(Q)docker tag $(DOCKER_REGISTRY)$(DOCKER_REPO)$(DOCKER_TAG):$(DOCKER_VERSION)-alpine $(DOCKER_REGISTRY)$(DOCKER_REPO)$(DOCKER_TAG):latest-alpine
+ $(Q)docker tag $(DOCKER_REGISTRY)$(DOCKER_REPO)$(DOCKER_TAG):$(DOCKER_VERSION) $(DOCKER_REGISTRY)$(DOCKER_REPO)$(DOCKER_TAG):latest-3.2
+ $(Q)docker tag $(DOCKER_REGISTRY)$(DOCKER_REPO)$(DOCKER_TAG):$(DOCKER_VERSION)-alpine $(DOCKER_REGISTRY)$(DOCKER_REPO)$(DOCKER_TAG):latest-3.2-alpine
+
+.PHONY: docker-push-latest
+docker-push-latest: docker-push docker-tag-latest
+ $(Q)docker push $(DOCKER_REGISTRY)$(DOCKER_REPO)$(DOCKER_TAG):latest
+ $(Q)docker push $(DOCKER_REGISTRY)$(DOCKER_REPO)$(DOCKER_TAG):latest-alpine
+ $(Q)docker push $(DOCKER_REGISTRY)$(DOCKER_REPO)$(DOCKER_TAG):latest-3.2
+ $(Q)docker push $(DOCKER_REGISTRY)$(DOCKER_REPO)$(DOCKER_TAG):latest-3.2-alpine
+
+.PHONY: docker-publish
+docker-publish: docker-push-latest
diff --git a/scripts/docker/rocky8/Dockerfile b/scripts/docker/rocky8/Dockerfile
new file mode 100644
index 0000000..ca821a3
--- /dev/null
+++ b/scripts/docker/rocky8/Dockerfile
@@ -0,0 +1,108 @@
+ARG from=rockylinux/rockylinux:8
+FROM ${from} as build
+
+RUN rpmkeys --import /etc/pki/rpm-gpg/RPM-GPG-KEY-rockyofficial
+
+#
+# Install build tools
+#
+RUN yum groupinstall -y "Development Tools"
+RUN yum install -y rpmdevtools openssl dnf-utils
+
+#
+# Create build directory
+#
+RUN mkdir -p /usr/local/src/repositories
+WORKDIR /usr/local/src/repositories
+
+#
+# Shallow clone the FreeRADIUS source
+#
+ARG source=https://github.com/FreeRADIUS/freeradius-server.git
+ARG release=v3.2.x
+
+RUN git clone --depth 1 --single-branch --branch ${release} ${source}
+WORKDIR freeradius-server
+
+#
+# Other requirements
+#
+
+# Use LTB's openldap packages intead of the distribution version to avoid linking against NSS
+RUN echo $'[ltb-project]\n\
+name=LTB project packages\n\
+baseurl=https://ltb-project.org/rpm/$releasever/$basearch\n\
+enabled=1\n\
+gpgcheck=1\n\
+gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-LTB-project'\
+> /etc/yum.repos.d/ltb-project.repo
+RUN rpm --import https://ltb-project.org/lib/RPM-GPG-KEY-LTB-project
+
+# EPEL repository for freetds and hiredis
+RUN yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm
+
+RUN yum config-manager --enable powertools
+# Currently needed for hiredis-devel
+RUN yum config-manager --enable epel-testing
+
+#
+# Install build dependencies
+#
+RUN [ -e redhat/freeradius.spec ] && yum-builddep -y redhat/freeradius.spec
+
+#
+# Create RPM build environment
+#
+ENV BUILDDIR=/root/rpmbuild
+RUN rpmdev-setuptree
+
+RUN ./configure
+RUN make freeradius-server-$(cat VERSION).tar.bz2
+RUN cp freeradius-server-$(cat VERSION).tar.bz2 $BUILDDIR/SOURCES/
+RUN cp -r redhat/* $BUILDDIR/SOURCES/
+RUN cp -r redhat/freeradius.spec $BUILDDIR/SPECS/
+WORKDIR $BUILDDIR
+
+#
+# Build the server
+#
+ENV QA_RPATHS=0x0003
+RUN rpmbuild -bb --define '_release $release' "$BUILDDIR/SPECS/freeradius.spec"
+
+RUN mkdir /root/rpms
+RUN mv $BUILDDIR/RPMS/*/*.rpm /root/rpms/
+
+#
+# Clean environment and run the server
+#
+FROM ${from}
+COPY --from=build /root/rpms /tmp/
+
+# Use LTB's openldap packages intead of the distribution version to avoid linking against NSS
+RUN echo $'[ltb-project]\n\
+name=LTB project packages\n\
+baseurl=https://ltb-project.org/rpm/$releasever/$basearch\n\
+enabled=1\n\
+gpgcheck=1\n\
+gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-LTB-project'\
+> /etc/yum.repos.d/ltb-project.repo \
+ && rpm --import https://ltb-project.org/lib/RPM-GPG-KEY-LTB-project \
+ \
+# EPEL repository for freetds and hiredis
+ && yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm \
+ && yum install -y dnf-utils \
+ && yum config-manager --enable epel-testing
+
+ARG radiusd_uid=95
+ARG radiusd_gid=95
+
+RUN groupadd -g ${radiusd_gid} -r radiusd \
+ && useradd -u ${radiusd_uid} -g radiusd -r -M -d /home/radiusd -s /sbin/nologin radiusd \
+ && yum install -y /tmp/*.rpm
+
+COPY docker-entrypoint.sh /
+RUN chmod +x /docker-entrypoint.sh
+
+EXPOSE 1812/udp 1813/udp
+ENTRYPOINT ["/docker-entrypoint.sh"]
+CMD ["radiusd"]
diff --git a/scripts/docker/rocky8/docker-entrypoint.sh b/scripts/docker/rocky8/docker-entrypoint.sh
new file mode 100755
index 0000000..900ad6b
--- /dev/null
+++ b/scripts/docker/rocky8/docker-entrypoint.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+set -e
+
+# this if will check if the first argument is a flag
+# but only works if all arguments require a hyphenated flag
+# -v; -SL; -f arg; etc will work, but not arg1 arg2
+if [ "$#" -eq 0 ] || [ "${1#-}" != "$1" ]; then
+ set -- radiusd "$@"
+fi
+
+# check for the expected command
+if [ "$1" = 'radiusd' ]; then
+ shift
+ exec radiusd -f "$@"
+fi
+
+# debian people are likely to call "freeradius" as well, so allow that
+if [ "$1" = 'freeradius' ]; then
+ shift
+ exec radiusd -f "$@"
+fi
+
+# else default to run whatever the user wanted like "bash" or "sh"
+exec "$@"
diff --git a/scripts/docker/ubuntu18/Dockerfile b/scripts/docker/ubuntu18/Dockerfile
new file mode 100644
index 0000000..7322026
--- /dev/null
+++ b/scripts/docker/ubuntu18/Dockerfile
@@ -0,0 +1,59 @@
+ARG from=ubuntu:18.04
+FROM ${from} as build
+
+ARG DEBIAN_FRONTEND=noninteractive
+
+#
+# Install build tools
+#
+RUN apt-get update
+RUN apt-get install -y devscripts equivs git quilt gcc
+
+#
+# Create build directory
+#
+RUN mkdir -p /usr/local/src/repositories
+WORKDIR /usr/local/src/repositories
+
+#
+# Shallow clone the FreeRADIUS source
+#
+ARG source=https://github.com/FreeRADIUS/freeradius-server.git
+ARG release=v3.2.x
+
+RUN git clone --depth 1 --single-branch --branch ${release} ${source}
+WORKDIR freeradius-server
+
+#
+# Install build dependencies
+#
+RUN git checkout ${release}; \
+ if [ -e ./debian/control.in ]; then \
+ debian/rules debian/control; \
+ fi; \
+ echo 'y' | mk-build-deps -irt'apt-get -yV' debian/control
+
+#
+# Build the server
+#
+RUN make -j2 deb
+
+#
+# Clean environment and run the server
+#
+FROM ${from}
+COPY --from=build /usr/local/src/repositories/*.deb /tmp/
+
+RUN apt-get update \
+ && apt-get install -y /tmp/*.deb \
+ && apt-get clean \
+ && rm -r /var/lib/apt/lists/* /tmp/*.deb \
+ \
+ && ln -s /etc/freeradius /etc/raddb
+
+COPY docker-entrypoint.sh /
+RUN chmod +x /docker-entrypoint.sh
+
+EXPOSE 1812/udp 1813/udp
+ENTRYPOINT ["/docker-entrypoint.sh"]
+CMD ["freeradius"]
diff --git a/scripts/docker/ubuntu18/docker-entrypoint.sh b/scripts/docker/ubuntu18/docker-entrypoint.sh
new file mode 100755
index 0000000..93141b0
--- /dev/null
+++ b/scripts/docker/ubuntu18/docker-entrypoint.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+set -e
+
+# this if will check if the first argument is a flag
+# but only works if all arguments require a hyphenated flag
+# -v; -SL; -f arg; etc will work, but not arg1 arg2
+if [ "$#" -eq 0 ] || [ "${1#-}" != "$1" ]; then
+ set -- freeradius "$@"
+fi
+
+# check for the expected command
+if [ "$1" = 'freeradius' ]; then
+ shift
+ exec freeradius -f "$@"
+fi
+
+# many people are likely to call "radiusd" as well, so allow that
+if [ "$1" = 'radiusd' ]; then
+ shift
+ exec freeradius -f "$@"
+fi
+
+# else default to run whatever the user wanted like "bash" or "sh"
+exec "$@"
diff --git a/scripts/docker/ubuntu20/Dockerfile b/scripts/docker/ubuntu20/Dockerfile
new file mode 100644
index 0000000..783ebc9
--- /dev/null
+++ b/scripts/docker/ubuntu20/Dockerfile
@@ -0,0 +1,61 @@
+ARG from=ubuntu:20.04
+FROM ${from} as build
+
+ARG DEBIAN_FRONTEND=noninteractive
+
+#
+# Install build tools
+#
+RUN apt-get update
+RUN apt-get install -y devscripts equivs git quilt gcc
+
+#
+# Create build directory
+#
+RUN mkdir -p /usr/local/src/repositories
+WORKDIR /usr/local/src/repositories
+
+#
+# Shallow clone the FreeRADIUS source
+#
+ARG source=https://github.com/FreeRADIUS/freeradius-server.git
+ARG release=v3.2.x
+
+RUN git clone --depth 1 --single-branch --branch ${release} ${source}
+WORKDIR freeradius-server
+
+#
+# Install build dependencies
+#
+RUN git checkout ${release}; \
+ if [ -e ./debian/control.in ]; then \
+ debian/rules debian/control; \
+ fi; \
+ echo 'y' | mk-build-deps -irt'apt-get -yV' debian/control
+
+#
+# Build the server
+#
+RUN make -j2 deb
+
+#
+# Clean environment and run the server
+#
+FROM ${from}
+COPY --from=build /usr/local/src/repositories/*.deb /tmp/
+
+ARG DEBIAN_FRONTEND=noninteractive
+
+RUN apt-get update \
+ && apt-get install -y /tmp/*.deb \
+ && apt-get clean \
+ && rm -r /var/lib/apt/lists/* /tmp/*.deb \
+ \
+ && ln -s /etc/freeradius /etc/raddb
+
+COPY docker-entrypoint.sh /
+RUN chmod +x /docker-entrypoint.sh
+
+EXPOSE 1812/udp 1813/udp
+ENTRYPOINT ["/docker-entrypoint.sh"]
+CMD ["freeradius"]
diff --git a/scripts/docker/ubuntu20/docker-entrypoint.sh b/scripts/docker/ubuntu20/docker-entrypoint.sh
new file mode 100755
index 0000000..93141b0
--- /dev/null
+++ b/scripts/docker/ubuntu20/docker-entrypoint.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+set -e
+
+# this if will check if the first argument is a flag
+# but only works if all arguments require a hyphenated flag
+# -v; -SL; -f arg; etc will work, but not arg1 arg2
+if [ "$#" -eq 0 ] || [ "${1#-}" != "$1" ]; then
+ set -- freeradius "$@"
+fi
+
+# check for the expected command
+if [ "$1" = 'freeradius' ]; then
+ shift
+ exec freeradius -f "$@"
+fi
+
+# many people are likely to call "radiusd" as well, so allow that
+if [ "$1" = 'radiusd' ]; then
+ shift
+ exec freeradius -f "$@"
+fi
+
+# else default to run whatever the user wanted like "bash" or "sh"
+exec "$@"
diff --git a/scripts/docker/ubuntu22/Dockerfile b/scripts/docker/ubuntu22/Dockerfile
new file mode 100644
index 0000000..9e6aa57
--- /dev/null
+++ b/scripts/docker/ubuntu22/Dockerfile
@@ -0,0 +1,66 @@
+ARG from=ubuntu:22.04
+FROM ${from} as build
+
+ARG DEBIAN_FRONTEND=noninteractive
+
+#
+# Install build tools
+#
+RUN apt-get update
+RUN apt-get install -y devscripts equivs git quilt gcc
+
+#
+# Create build directory
+#
+RUN mkdir -p /usr/local/src/repositories
+WORKDIR /usr/local/src/repositories
+
+#
+# Shallow clone the FreeRADIUS source
+#
+ARG source=https://github.com/FreeRADIUS/freeradius-server.git
+ARG release=v3.2.x
+
+RUN git clone --depth 1 --single-branch --branch ${release} ${source}
+WORKDIR freeradius-server
+
+#
+# Install build dependencies
+#
+RUN git checkout ${release}; \
+ if [ -e ./debian/control.in ]; then \
+ debian/rules debian/control; \
+ fi; \
+ echo 'y' | mk-build-deps -irt'apt-get -yV' debian/control
+
+#
+# Build the server
+#
+RUN make -j2 deb
+
+#
+# Clean environment and run the server
+#
+FROM ${from}
+COPY --from=build /usr/local/src/repositories/*.deb /tmp/
+
+ARG freerad_uid=101
+ARG freerad_gid=101
+
+ARG DEBIAN_FRONTEND=noninteractive
+
+RUN groupadd -g ${freerad_gid} -r freerad \
+ && useradd -u ${freerad_uid} -g freerad -r -M -d /etc/freeradius -s /usr/sbin/nologin freerad \
+ && apt-get update \
+ && apt-get install -y /tmp/*.deb \
+ && apt-get clean \
+ && rm -r /var/lib/apt/lists/* /tmp/*.deb \
+ \
+ && ln -s /etc/freeradius /etc/raddb
+
+COPY docker-entrypoint.sh /
+RUN chmod +x /docker-entrypoint.sh
+
+EXPOSE 1812/udp 1813/udp
+ENTRYPOINT ["/docker-entrypoint.sh"]
+CMD ["freeradius"]
diff --git a/scripts/docker/ubuntu22/docker-entrypoint.sh b/scripts/docker/ubuntu22/docker-entrypoint.sh
new file mode 100755
index 0000000..93141b0
--- /dev/null
+++ b/scripts/docker/ubuntu22/docker-entrypoint.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+set -e
+
+# this if will check if the first argument is a flag
+# but only works if all arguments require a hyphenated flag
+# -v; -SL; -f arg; etc will work, but not arg1 arg2
+if [ "$#" -eq 0 ] || [ "${1#-}" != "$1" ]; then
+ set -- freeradius "$@"
+fi
+
+# check for the expected command
+if [ "$1" = 'freeradius' ]; then
+ shift
+ exec freeradius -f "$@"
+fi
+
+# many people are likely to call "radiusd" as well, so allow that
+if [ "$1" = 'radiusd' ]; then
+ shift
+ exec freeradius -f "$@"
+fi
+
+# else default to run whatever the user wanted like "bash" or "sh"
+exec "$@"
diff --git a/scripts/exec-program-wait b/scripts/exec-program-wait
new file mode 100755
index 0000000..a851309
--- /dev/null
+++ b/scripts/exec-program-wait
@@ -0,0 +1,62 @@
+#!/bin/sh
+#
+# $Id$
+#
+# Sample script to add Attribute/Value pairs in the reply sent to
+# the NAS.
+#
+# Before version 2.0 of FreeRADIUS, the script could be run from the
+# deprecated attributes 'Exec-Program' and 'Exec-Program-Wait'.
+# However, these attributes are no longer supported and you have to
+# use the module 'rlm_exec' instead.
+#
+# An entry for the module 'rlm_exec' must be added to the file
+# 'radiusd.conf' with the path of the script.
+#
+#modules {
+# exec {
+# program = "/path/to/program/exec-program-wait"
+# wait = yes
+# input_pairs = request
+# output_pairs = reply
+# }
+# ...
+#}
+#
+#authorize {
+# ...
+# exec
+# ...
+#}
+#
+# Each of the attributes in the request will be available in an
+# environment variable. The name of the variable depends on the
+# name of the attribute. All letters are converted to upper case,
+# and all hyphens '-' to underlines.
+#
+# For example, the User-Name attribute will be in the $USER_NAME
+# environment variable. If you want to see the list of all of
+# the variables, try adding a line 'printenv > /tmp/exec-program-wait'
+# to the script. Then look in the file for a complete list of
+# variables.
+#
+# The return value of the program run determines the result
+# of the exec instance call as follows:
+# (See doc/configurable_failover for details)
+# < 0 : fail the module failed
+# = 0 : ok the module succeeded
+# = 1 : reject the module rejected the user
+# = 2 : fail the module failed
+# = 3 : ok the module succeeded
+# = 4 : handled the module has done everything to handle the request
+# = 5 : invalid the user's configuration entry was invalid
+# = 6 : userlock the user was locked out
+# = 7 : notfound the user was not found
+# = 8 : noop the module did nothing
+# = 9 : updated the module updated information in the request
+# > 9 : fail the module failed
+#
+echo "Reply-Message += \"Hello, %u\","
+echo "Reply-Message += \"PATH=$PATH\","
+echo Framed-IP-Address = 255.255.255.255
+exit 0
diff --git a/scripts/git/post-receive b/scripts/git/post-receive
new file mode 100755
index 0000000..3f44994
--- /dev/null
+++ b/scripts/git/post-receive
@@ -0,0 +1,151 @@
+#!/bin/sh
+# git Post-receive configuration update script
+#
+# To install:
+# * Enable r/w control socket for the user you're pushing with
+# * cd <config-dir>/raddb git config receive.denyCurrentBranch ignore
+# * cp ./post-receive <config-dir>/raddb/.git/hooks/
+# * # Edit the capitalized variables below to match your environment.
+#
+# Copyright 2012 Arran Cudbard-Bell <a.cudbard-bell@freeradius.org>
+
+PATH=/bin:/usr/bin:/usr/sbin:/sbin
+# Tag to update when we successfully manage to start the server with a new configuration
+: ${STABLE_TAG='stable'}
+
+# Descriptive name of daemon
+: ${DAEMON_DESC='FreeRADIUS'}
+
+# Init script for radiusd
+: ${DAEMON_STATUS='/etc/init.d/radiusd status'}
+
+# Command used to restart the RADIUS daemon
+: ${DAEMON_REST='radmin -e hup'}
+
+# Command used to verify the new configuration
+: ${DAEMON_CONF='radiusd -Cxl stdout'}
+
+# Command used to execute git functions
+: ${GIT_EXEC='env -i git'}
+
+# Abort if there are local untracked files
+: ${ABORT_UNTRACKED=true}
+
+# Push changes to any remotes we have configured
+: ${PUSH_TO_REMOTES=false}
+
+while read oldrev newrev refname
+do
+:
+done
+
+status () {
+ if [ $1 -ne 0 ]; then
+ echo "failed"
+ else
+ echo "ok"
+ fi
+}
+
+conf_rollback () {
+ # Use stable tag if it exists...
+ if $GIT_EXEC show-ref $STABLE_TAG > /dev/null 2>&1; then
+ echo -n "Attempting to roll config back to tag: \"$STABLE_TAG\"... "
+ $GIT_EXEC reset --hard $STABLE_TAG; ret=$?
+ else
+ echo -n "Attempting to roll config back to commit: \"$oldrev\"... "
+ $GIT_EXEC reset --hard $oldrev; ret=$?
+ fi
+
+ status $ret
+ return $ret
+}
+
+conf_check () {
+ echo -n "Checking new configuration... "
+ $DAEMON_CONF; ret=$?
+
+ status $ret
+ return $ret
+}
+
+daemon_status () {
+ echo -n "Checking if radiusd is running ... "
+ $DAEMON_STATUS; ret=$?
+
+ return $ret
+}
+
+daemon_restart () {
+ echo -n "Restarting server... "
+
+ $DAEMON_REST > /dev/null 2>&1; ret=$?
+
+ status $ret
+ return $ret
+}
+
+# Reset the current working directory state
+cd ..
+
+# Friendly update of working copy to head state
+$GIT_EXEC checkout -f
+if $ABORT_UNTRACKED && [ `$GIT_EXEC status --porcelain | wc -l` -gt 0 ]; then
+ echo "WARNING: Untracked changes have been made to this git repository,"
+ echo "changes have been committed but untracked files should be removed,"
+ echo "committed or added to .gitignore and $DAEMON_DESC restarted manually."
+ $GIT_EXEC status --short
+
+ if ! conf_check; then
+ exit 64
+ fi
+
+ echo "WARNING: $DAEMON_DESC found errors in the configuration,"
+ echo "these errors should be corrected before updating working copy."
+ exit 65
+fi
+
+# Clean out all untracked files and directories (if there are local files you
+# wish to keep, they should be add to .gitignore)
+if ! $GIT_EXEC clean -d -f
+ then exit $?
+fi
+
+# Reset all tracked files to the HEAD state
+if ! $GIT_EXEC reset --hard
+ then exit $?
+fi
+
+# Check if the server finds any errors in the new config
+if ! conf_check; then
+ echo "WARNING: $DAEMON_DESC found errors in the configuration,"
+ echo "please fix the errors and push the corrected configuration."
+
+ conf_rollback
+ exit 64
+else
+ if daemon_status && ! daemon_restart ; then
+ if ! conf_rollback; then
+ echo "WARNING: Manually verify $DAEMON_DESC status immediately!"
+ exit 64
+ fi
+
+ if ! daemon_restart; then
+ echo "WARNING: Manually verify $DAEMON_DESC status immediately!"
+ exit 64
+ fi
+
+ exit 64
+ fi
+
+ $GIT_EXEC tag -f $STABLE_TAG $newrev
+fi
+
+if $PUSH_TO_REMOTES; then
+ echo "Pushing to remote repositories"
+ for remote in `$GIT_EXEC remote`; do
+ $GIT_EXEC push "$remote"
+ done
+fi
+
+exit 0
diff --git a/scripts/install.mk b/scripts/install.mk
new file mode 100644
index 0000000..9164115
--- /dev/null
+++ b/scripts/install.mk
@@ -0,0 +1,250 @@
+# boilermake: A reusable, but flexible, boilerplate Makefile.
+#
+# Copyright 2008, 2009, 2010 Dan Moulding, Alan T. DeKok
+#
+# 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 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# ADD_INSTALL_RULE.* - Parameterized "functions" that adds a new
+# installation to the Makefile. There should be one ADD_INSTALL_RULE
+# definition for each type of target that is used in the build.
+#
+# New rules can be added by copying one of the existing ones, and
+# replacing the line after the "mkdir"
+#
+
+#
+# You can watch what it's doing by:
+#
+# $ VERBOSE=1 make ... args ...
+#
+ifeq "${VERBOSE}" ""
+ Q=@
+else
+ Q=
+endif
+
+# ADD_INSTALL_RULE.exe - Parameterized "function" that adds a new rule
+# and phony target for installing an executable.
+#
+# USE WITH EVAL
+#
+define ADD_INSTALL_RULE.exe
+ ALL_INSTALL += $${${1}_INSTALLDIR}/$(notdir ${1})
+
+ # Global install depends on ${1}
+ install: $${${1}_INSTALLDIR}/$(notdir ${1})
+
+ # Install executable ${1}
+ $${${1}_INSTALLDIR}/$(notdir ${1}): ${JLIBTOOL} $${${1}_BUILD}/${1} | $${${1}_INSTALLDIR}
+ @$(ECHO) INSTALL ${1}
+ $(Q)$${PROGRAM_INSTALL} -c -m 755 $${BUILD_DIR}/bin/${1} $${${1}_INSTALLDIR}/
+ $(Q)$${${1}_POSTINSTALL}
+
+endef
+
+# ADD_INSTALL_RULE.a - Parameterized "function" that adds a new rule
+# and phony target for installing a static library
+#
+# USE WITH EVAL
+#
+define ADD_INSTALL_RULE.a
+ ALL_INSTALL += $${${1}_INSTALLDIR}/$(notdir ${1})
+
+ # Global install depends on ${1}
+ install: $${${1}_INSTALLDIR}/$(notdir ${1})
+
+ # Install static library ${1}
+ $${${1}_INSTALLDIR}/$(notdir ${1}): ${JLIBTOOL} ${1} | $${${1}_INSTALLDIR}
+ @$(ECHO) INSTALL ${1}
+ $(Q)$${PROGRAM_INSTALL} -c -m 755 $${BUILD_DIR}/lib/${1} $${${1}_INSTALLDIR}/
+ $(Q)$${${1}_POSTINSTALL}
+
+endef
+
+# ADD_INSTALL_RULE.la - Parameterized "function" that adds a new rule
+# and phony target for installing a libtool library
+#
+# FIXME: The libtool install *also* installs a bunch of other files.
+# ensure that those are removed, too.
+#
+# USE WITH EVAL
+#
+define ADD_INSTALL_RULE.la
+ ALL_INSTALL += $${${1}_INSTALLDIR}/$(notdir ${1})
+
+ # Global install depends on ${1}
+ install: $${${1}_INSTALLDIR}/$(notdir ${1})
+
+ # Install libtool library ${1}
+ $${${1}_INSTALLDIR}/$(notdir ${1}): ${JLIBTOOL} $${${1}_BUILD}/${1} | $${${1}_INSTALLDIR}
+ @$(ECHO) INSTALL ${1}
+ $(Q)$${PROGRAM_INSTALL} -c -m 755 $${LOCAL_FLAGS_MIN} $${BUILD_DIR}/lib/${1} $${${1}_INSTALLDIR}/
+ $(Q)$${${1}_POSTINSTALL}
+
+endef
+
+# ADD_INSTALL_RULE.man - Parameterized "function" that adds a new rule
+# and phony target for installing a "man" page. It will take care of
+# installing it into the correct subdirectory of "man".
+#
+# USE WITH EVAL
+#
+define ADD_INSTALL_RULE.man
+ ALL_INSTALL += ${2}/$(notdir ${1})
+
+ # Global install depends on ${1}
+ install: ${2}/$(notdir ${1})
+
+ # Install manual page ${1}
+ ${2}/$(notdir ${1}): ${JLIBTOOL} ${1} | ${2}
+ @$(ECHO) INSTALL $(notdir ${1})
+ $(Q)$${PROGRAM_INSTALL} -c -m 644 ${1} ${2}/
+
+endef
+
+
+# ADD_INSTALL_RULE.dir - Parameterized "function" that adds a new rule
+# and phony target for installing a directory
+#
+# USE WITH EVAL
+#
+define ADD_INSTALL_RULE.dir
+ # Install directory
+ .PHONY: ${1}
+ ${1}: ${JLIBTOOL}
+ @$(ECHO) INSTALL -d -m 755 ${1}
+ $(Q)$${PROGRAM_INSTALL} -d -m 755 ${1}
+endef
+
+
+# ADD_INSTALL_TARGET - Parameterized "function" that adds a new rule
+# which installs everything for the target.
+#
+# USE WITH EVAL
+#
+define ADD_INSTALL_TARGET
+ # Figure out which target rule to use for installation.
+ ifeq "$${${1}_SUFFIX}" ".exe"
+ ifeq "$${TGT_INSTALLDIR}" ".."
+ TGT_INSTALLDIR := $${bindir}
+ endif
+ else
+ ifeq "$${TGT_INSTALLDIR}" ".."
+ TGT_INSTALLDIR := $${libdir}
+ endif
+ endif
+
+ # add rules to install the target
+ ifneq "$${TGT_INSTALLDIR}" ""
+ ${1}_INSTALLDIR := ${LL}$${DESTDIR}$${TGT_INSTALLDIR}
+
+ $$(eval $$(call ADD_INSTALL_RULE$${${1}_SUFFIX},${1}))
+ endif
+
+ # add rules to install the MAN pages.
+ ifneq "$$(strip $${${1}_MAN})" ""
+ ifeq "$${mandir}" ""
+ $$(error You must define 'mandir' in order to be able to install MAN pages.)
+ endif
+
+ MAN := $$(call QUALIFY_PATH,$${DIR},$${MAN})
+ MAN := $$(call CANONICAL_PATH,$${MAN})
+
+ $$(foreach PAGE,$${MAN},\
+ $$(eval $$(call ADD_INSTALL_RULE.man,$${PAGE},\
+ $${DESTDIR}$${mandir}/man$$(subst .,,$$(suffix $${PAGE})))))
+ endif
+endef
+
+.PHONY: install
+install:
+
+ALL_INSTALL :=
+
+# Define reasonable defaults for all of the installation directories.
+# The user can over-ride these, but these are the defaults.
+ifeq "${prefix}" ""
+ prefix = /usr/local
+endif
+ifeq "${exec_prefix}" ""
+ exec_prefix = ${prefix}
+endif
+ifeq "${bindir}" ""
+ bindir = ${exec_prefix}/bin
+endif
+ifeq "${sbindir}" ""
+ sbindir = ${exec_prefix}/sbin
+endif
+ifeq "${libdir}" ""
+ libdir = ${exec_prefix}/lib
+endif
+ifeq "${sysconfdir}" ""
+ sysconfdir = ${prefix}/etc
+endif
+ifeq "${localstatedir}" ""
+ localstatedir = ${prefix}/var
+endif
+ifeq "${datarootdir}" ""
+ datarootdir = ${prefix}/share
+endif
+ifeq "${datadir}" ""
+ datadir = ${prefix}/share
+endif
+ifeq "${mandir}" ""
+ mandir = ${datadir}/man
+endif
+ifeq "${docdir}" ""
+ ifneq "${PROJECT_NAME}" ""
+ docdir = ${datadir}/doc/${PROJECT_NAME}
+ endif
+endif
+ifeq "${logdir}" ""
+ logdir = ${localstatedir}/log/
+endif
+ifeq "${includedir}" ""
+ includedir = ${prefix}/include
+endif
+
+
+# Un-install any installed programs. We DON'T want to depend on the
+# install target. Doing so would cause "make uninstall" to build it,
+# install it, and then remove it.
+#
+# We also want to uninstall only when there are "install_foo" targets.
+.PHONY: uninstall
+uninstall:
+ $(Q)rm -f ${ALL_INSTALL} ./.no_such_file
+
+# Wrapper around INSTALL
+ifeq "${PROGRAM_INSTALL}" ""
+ PROGRAM_INSTALL := ${INSTALL}
+
+endif
+
+# Make just the installation directories
+.PHONY: installdirs
+installdirs:
+
+# Be nice to the user. If there is no INSTALL program, then print out
+# a helpful message. Without this check, the "install" rules defined
+# above would try to run a command-line with a blank INSTALL, and give
+# some inscrutable error.
+ifeq "${INSTALL}" ""
+install: install_ERROR
+
+.PHONY: install_ERROR
+install_ERROR:
+ @$(ECHO) Please define INSTALL in order to enable the installation rules.
+ $(Q)exit 1
+endif
diff --git a/scripts/jlibtool.c b/scripts/jlibtool.c
new file mode 100644
index 0000000..77b7db2
--- /dev/null
+++ b/scripts/jlibtool.c
@@ -0,0 +1,2608 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#if !defined(__MINGW32__)
+# include <sys/wait.h>
+#endif
+
+#include <unistd.h>
+#include <dirent.h>
+#include <errno.h>
+#include <assert.h>
+
+#ifdef __EMX__
+# define SHELL_CMD "sh"
+# define GEN_EXPORTS "emxexp"
+# define DEF2IMPLIB_CMD "emximp"
+# define SHARE_SW "-Zdll -Zmtd"
+# define USE_OMF 1
+# define TRUNCATE_DLL_NAME
+# define DYNAMIC_LIB_EXT "dll"
+# define EXE_EX ".exe"
+/* OMF is the native format under OS/2 */
+# if USE_OMF
+
+# define STATIC_LIB_EXT "lib"
+# define OBJECT_EXT "obj"
+# define LIBRARIAN "emxomfar"
+# define LIBRARIAN_OPTS "cr"
+# else
+/* but the alternative, a.out, can fork() which is sometimes necessary */
+# define STATIC_LIB_EXT "a"
+# define OBJECT_EXT "o"
+# define LIBRARIAN "ar"
+# define LIBRARIAN_OPTS "cr"
+# endif
+#endif
+
+#if defined(__APPLE__)
+# define SHELL_CMD "/bin/sh"
+# define DYNAMIC_LIB_EXT "dylib"
+# define MODULE_LIB_EXT "bundle"
+# define STATIC_LIB_EXT "a"
+# define OBJECT_EXT "o"
+# define LIBRARIAN "ar"
+# define LIBRARIAN_OPTS "cr"
+/* man libtool(1) documents ranlib option of -c. */
+# define RANLIB "ranlib"
+# define PIC_FLAG "-fPIC -fno-common"
+# define SHARED_OPTS "-dynamiclib"
+# define MODULE_OPTS "-bundle -dynamic"
+# define DYNAMIC_LINK_OPTS "-flat_namespace"
+# define DYNAMIC_LINK_UNDEFINED "-undefined suppress"
+# define dynamic_link_version_func darwin_dynamic_link_function
+# define DYNAMIC_INSTALL_NAME "-install_name"
+# define DYNAMIC_LINK_NO_INSTALL "-dylib_file"
+# define HAS_REALPATH
+/*-install_name /Users/jerenk/apache-2.0-cvs/lib/libapr.0.dylib -compatibility_version 1 -current_version 1.0 */
+# define LD_LIBRARY_PATH "DYLD_LIBRARY_PATH"
+# define LD_LIBRARY_PATH_LOCAL "DYLD_FALLBACK_LIBRARY_PATH"
+#endif
+
+#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || (defined(__sun) && defined(__GNUC__))
+# define SHELL_CMD "/bin/sh"
+# define DYNAMIC_LIB_EXT "so"
+# define MODULE_LIB_EXT "so"
+# define STATIC_LIB_EXT "a"
+# define OBJECT_EXT "o"
+# define LIBRARIAN "ar"
+# define LIBRARIAN_OPTS "cr"
+# define RANLIB "ranlib"
+# define PIC_FLAG "-fPIC"
+# define RPATH "-rpath"
+# define SHARED_OPTS "-shared"
+# define MODULE_OPTS "-shared"
+# define LINKER_FLAG_PREFIX "-Wl,"
+#if !defined(__sun)
+# define DYNAMIC_LINK_OPTS LINKER_FLAG_PREFIX "-export-dynamic"
+#else
+# define DYNAMIC_LINK_OPTS ""
+#endif
+# define ADD_MINUS_L
+# define LD_RUN_PATH "LD_RUN_PATH"
+# define LD_LIBRARY_PATH "LD_LIBRARY_PATH"
+# define LD_LIBRARY_PATH_LOCAL LD_LIBRARY_PATH
+#endif
+
+#if defined(__sun) && !defined(__GNUC__)
+# define SHELL_CMD "/bin/sh"
+# define DYNAMIC_LIB_EXT "so"
+# define MODULE_LIB_EXT "so"
+# define STATIC_LIB_EXT "a"
+# define OBJECT_EXT "o"
+# define LIBRARIAN "ar"
+# define LIBRARIAN_OPTS "cr"
+# define RANLIB "ranlib"
+# define PIC_FLAG "-fPIC"
+# define RPATH "-R"
+# define SHARED_OPTS "-G"
+# define MODULE_OPTS "-G"
+# define DYNAMIC_LINK_OPTS ""
+# define LINKER_FLAG_NO_EQUALS
+# define ADD_MINUS_L
+# define HAS_REALPATH
+# define LD_RUN_PATH "LD_RUN_PATH"
+# define LD_LIBRARY_PATH "LD_LIBRARY_PATH"
+# define LD_LIBRARY_PATH_LOCAL LD_LIBRARY_PATH
+#endif
+
+#if defined(_OSD_POSIX)
+# define SHELL_CMD "/usr/bin/sh"
+# define DYNAMIC_LIB_EXT "so"
+# define MODULE_LIB_EXT "so"
+# define STATIC_LIB_EXT "a"
+# define OBJECT_EXT "o"
+# define LIBRARIAN "ar"
+# define LIBRARIAN_OPTS "cr"
+# define SHARED_OPTS "-G"
+# define MODULE_OPTS "-G"
+# define LINKER_FLAG_PREFIX "-Wl,"
+# define NEED_SNPRINTF
+#endif
+
+#if defined(sinix) && defined(mips) && defined(__SNI_TARG_UNIX)
+# define SHELL_CMD "/usr/bin/sh"
+# define DYNAMIC_LIB_EXT "so"
+# define MODULE_LIB_EXT "so"
+# define STATIC_LIB_EXT "a"
+# define OBJECT_EXT "o"
+# define LIBRARIAN "ar"
+# define LIBRARIAN_OPTS "cr"
+# define RPATH "-Brpath"
+# define SHARED_OPTS "-G"
+# define MODULE_OPTS "-G"
+# define LINKER_FLAG_PREFIX "-Wl,"
+# define DYNAMIC_LINK_OPTS LINKER_FLAG_PREFIX "-Blargedynsym"
+
+# define NEED_SNPRINTF
+# define LD_RUN_PATH "LD_RUN_PATH"
+# define LD_LIBRARY_PATH "LD_LIBRARY_PATH"
+# define LD_LIBRARY_PATH_LOCAL LD_LIBRARY_PATH
+#endif
+
+#if defined(__MINGW32__)
+# define SHELL_CMD "sh"
+# define DYNAMIC_LIB_EXT "dll"
+# define MODULE_LIB_EXT "dll"
+# define STATIC_LIB_EXT "a"
+# define OBJECT_EXT "o"
+# define LIBRARIAN "ar"
+# define LIBRARIAN_OPTS "cr"
+# define RANLIB "ranlib"
+# define LINKER_FLAG_PREFIX "-Wl,"
+# define SHARED_OPTS "-shared"
+# define MODULE_OPTS "-shared"
+# define MKDIR_NO_UMASK
+# define EXE_EXT ".exe"
+#endif
+
+#ifndef CC
+#define CC "clang"
+#endif
+
+#ifndef CXX
+#define CXX "g++"
+#endif
+
+#ifndef LINK_C
+#define LINK_C "clang"
+#endif
+
+#ifndef LINK_CXX
+#define LINK_CXX "g++"
+#endif
+
+#ifndef LIBDIR
+#define LIBDIR "/usr/local/lib"
+#endif
+
+#define OBJDIR ".libs"
+
+#ifndef SHELL_CMD
+#error Unsupported platform: Please add defines for SHELL_CMD etc. for your platform.
+#endif
+
+#ifdef NEED_SNPRINTF
+#include <stdarg.h>
+#endif
+
+#ifdef __EMX__
+#include <process.h>
+#endif
+
+#ifndef PATH_MAX
+#define PATH_MAX 1024
+#endif
+
+
+/* We want to say we are libtool 1.4 for shlibtool compatibility. */
+#define VERSION "1.4"
+
+#define DEBUG(fmt, ...) if(cmd->options.debug) printf(fmt, ## __VA_ARGS__)
+#define NOTICE(fmt, ...) if(!cmd->options.silent) printf(fmt, ## __VA_ARGS__)
+#define ERROR(fmt, ...) fprintf(stderr, fmt, ## __VA_ARGS__)
+
+enum tool_mode {
+ MODE_UNKNOWN,
+ MODE_COMPILE,
+ MODE_LINK,
+ MODE_EXECUTE,
+ MODE_INSTALL,
+};
+
+enum output_type {
+ OUT_GENERAL,
+ OUT_OBJECT,
+ OUT_PROGRAM,
+ OUT_LIB,
+ OUT_STATIC_LIB_ONLY,
+ OUT_DYNAMIC_LIB_ONLY,
+ OUT_MODULE,
+};
+
+enum pic_mode {
+ PIC_UNKNOWN,
+ PIC_PREFER,
+ PIC_AVOID,
+};
+
+enum shared_mode {
+ SHARE_UNSET,
+ SHARE_STATIC,
+ SHARE_SHARED,
+};
+
+enum lib_type {
+ TYPE_UKNOWN,
+ TYPE_STATIC_LIB,
+ TYPE_DYNAMIC_LIB,
+ TYPE_MODULE_LIB,
+ TYPE_OBJECT,
+};
+
+typedef struct {
+ char const **vals;
+ int num;
+} count_chars;
+
+typedef struct {
+ char const *normal;
+ char const *install;
+} library_name;
+
+typedef struct {
+ count_chars *normal;
+ count_chars *install;
+ count_chars *dependencies;
+} library_opts;
+
+typedef struct {
+ int silent;
+ int debug;
+ enum shared_mode shared;
+ int export_all;
+ int dry_run;
+ enum pic_mode pic_mode;
+ int export_dynamic;
+ int no_install;
+} options_t;
+
+typedef struct {
+ enum tool_mode mode;
+ enum output_type output;
+ options_t options;
+
+ char const *output_name;
+ char const *fake_output_name;
+ char const *basename;
+
+ char const *install_path;
+ char const *compiler;
+ char const *program;
+ count_chars *program_opts;
+
+ count_chars *arglist;
+ count_chars *tmp_dirs;
+ count_chars *obj_files;
+ count_chars *dep_rpaths;
+ count_chars *rpaths;
+
+ library_name static_name;
+ library_name shared_name;
+ library_name module_name;
+
+ library_opts static_opts;
+ library_opts shared_opts;
+
+ char const *version_info;
+ char const *undefined_flag;
+} command_t;
+
+#ifdef RPATH
+static void add_rpath(count_chars *cc, char const *path);
+#endif
+
+static void usage(int code)
+{
+ printf("Usage: jlibtool [OPTIONS...] COMMANDS...\n");
+ printf("jlibtool is a replacement for GNU libtool with similar functionality.\n\n");
+
+ printf(" --config show all configuration variables\n");
+ printf(" --debug enable verbose shell tracing\n");
+ printf(" --dry-run display commands without modifying any files\n");
+ printf(" --help display this help message and exit\n");
+ printf(" --mode=MODE use operational mode MODE (you *must* set mode)\n");
+
+ printf(" --silent don't print informational messages\n");
+ printf(" --tag=TAG Ignored for libtool compatibility\n");
+ printf(" --version print version information\n");
+
+
+ printf(" --shared Build shared libraries when using --mode=link\n");
+ printf(" --export-all Try to export 'def' file on some platforms\n");
+
+ printf("\nMODE must be one of the following:\n\n");
+ printf(" compile compile a source file into a jlibtool object\n");
+ printf(" execute automatically set library path, then run a program\n");
+ printf(" install install libraries or executables\n");
+ printf(" link create a library or an executable\n");
+
+ printf("\nMODE-ARGS can be the following:\n\n");
+ printf(" -export-dynamic accepted and ignored\n");
+ printf(" -module create a module when linking\n");
+ printf(" -shared create a shared library when linking\n");
+ printf(" -prefer-pic prefer position-independent-code when compiling\n");
+ printf(" -prefer-non-pic prefer non position-independent-code when compiling\n");
+ printf(" -static create a static library when linking\n");
+ printf(" -no-install link libraries locally\n");
+ printf(" -rpath arg Set install path for shared libraries\n");
+ printf(" -l arg pass '-l arg' to the link stage\n");
+ printf(" -L arg pass '-L arg' to the link stage\n");
+ printf(" -R dir add 'dir' to runtime library search path.\n");
+ printf(" -Zexe accepted and ignored\n");
+ printf(" -avoid-version accepted and ignored\n");
+
+ exit(code);
+}
+
+#if defined(NEED_SNPRINTF)
+/* Write at most n characters to the buffer in str, return the
+ * number of chars written or -1 if the buffer would have been
+ * overflowed.
+ *
+ * This is portable to any POSIX-compliant system has /dev/null
+ */
+static FILE *f = NULL;
+static int vsnprintf(char *str, size_t n, char const *fmt, va_list ap)
+{
+ int res;
+
+ if (!f) {
+ f = fopen("/dev/null","w");
+ }
+
+ if (!f) {
+ return -1;
+ }
+
+ setvbuf(f, str, _IOFBF, n);
+
+ res = vfprintf(f, fmt, ap);
+
+ if ((res > 0) && (res < n)) {
+ res = vsprintf( str, fmt, ap );
+ }
+ return res;
+}
+
+static int snprintf(char *str, size_t n, char const *fmt, ...)
+{
+ va_list ap;
+ int res;
+
+ va_start(ap, fmt);
+ res = vsnprintf(str, n, fmt, ap);
+ va_end(ap);
+ return res;
+}
+#endif
+
+static void *lt_malloc(size_t size)
+{
+ void *out;
+
+ out = malloc(size);
+ if (!out) {
+ ERROR("Failed allocating %zu bytes, OOM\n", size);
+ exit(1);
+ }
+
+ return out;
+}
+
+static void lt_const_free(const void *ptr)
+{
+ void *tmp;
+
+ memcpy(&tmp, &ptr, sizeof(tmp));
+ free(tmp);
+}
+
+static void init_count_chars(count_chars *cc)
+{
+ cc->vals = (char const**) lt_malloc(PATH_MAX*sizeof(char*));
+ cc->num = 0;
+}
+
+static count_chars *alloc_countchars(void)
+{
+ count_chars *out;
+ out = lt_malloc(sizeof(count_chars));
+ if (!out) {
+ exit(1);
+ }
+ init_count_chars(out);
+
+ return out;
+}
+
+static void clear_count_chars(count_chars *cc)
+{
+ int i;
+ for (i = 0; i < cc->num; i++) {
+ cc->vals[i] = NULL;
+ }
+
+ cc->num = 0;
+}
+
+static void push_count_chars(count_chars *cc, char const *newval)
+{
+ cc->vals[cc->num++] = newval;
+}
+
+static char const *pop_count_chars(count_chars *cc)
+{
+ if (!cc->num) {
+ return NULL;
+ }
+ return cc->vals[--cc->num];
+}
+
+static void insert_count_chars(count_chars *cc, char const *newval, int position)
+{
+ int i;
+
+ for (i = cc->num; i > position; i--) {
+ cc->vals[i] = cc->vals[i-1];
+ }
+
+ cc->vals[position] = newval;
+ cc->num++;
+}
+
+static void append_count_chars(count_chars *cc, count_chars *cctoadd)
+{
+ int i;
+ for (i = 0; i < cctoadd->num; i++) {
+ if (cctoadd->vals[i]) {
+ push_count_chars(cc, cctoadd->vals[i]);
+ }
+ }
+}
+
+static char const *flatten_count_chars(count_chars *cc, char delim)
+{
+ int i, size;
+ char *newval;
+
+ size = 0;
+ for (i = 0; i < cc->num; i++) {
+ if (cc->vals[i]) {
+ size += strlen(cc->vals[i]) + 1;
+ if (delim) {
+ size++;
+ }
+ }
+ }
+
+ newval = (char*)lt_malloc(size + 1);
+ newval[0] = '\0';
+
+ for (i = 0; i < cc->num; i++) {
+ if (cc->vals[i]) {
+ strcat(newval, cc->vals[i]);
+ if (delim) {
+ size_t len = strlen(newval);
+ newval[len] = delim;
+ newval[len + 1] = '\0';
+ }
+ }
+ }
+
+ return newval;
+}
+
+static char *shell_esc(char const *str)
+{
+ int in_quote = 0;
+ char *cmd;
+ uint8_t *d;
+ uint8_t const *s;
+
+ cmd = (char *)lt_malloc(2 * strlen(str) + 3);
+ d = (unsigned char *)cmd;
+ s = (const unsigned char *)str;
+
+#ifdef __MINGW32__
+ *d++ = '\"';
+#endif
+
+ for (; *s; ++s) {
+ if (*s == '"') {
+ *d++ = '\\';
+ in_quote++;
+ }
+ else if (*s == '\\' || (*s == ' ' && (in_quote % 2))) {
+ *d++ = '\\';
+ }
+ *d++ = *s;
+ }
+
+#ifdef __MINGW32__
+ *d++ = '\"';
+#endif
+
+ *d = '\0';
+ return cmd;
+}
+
+static int external_spawn(command_t *cmd, char const *file, char const **argv)
+{
+ file = file; /* -Wunused */
+
+ if (!cmd->options.silent) {
+ char const **argument = argv;
+ NOTICE("Executing: ");
+ while (*argument) {
+ NOTICE("%s ", *argument);
+ argument++;
+ }
+ puts("");
+ }
+
+ if (cmd->options.dry_run) {
+ return 0;
+ }
+#if defined(__EMX__) || defined(__MINGW32__)
+ return spawnvp(P_WAIT, argv[0], argv);
+#else
+ {
+ pid_t pid;
+ pid = fork();
+ if (pid == 0) {
+ return execvp(argv[0], (char**)argv);
+ }
+ else {
+ int status;
+ waitpid(pid, &status, 0);
+
+ /*
+ * Exited via exit(status)
+ */
+ if (WIFEXITED(status)) {
+ return WEXITSTATUS(status);
+ }
+
+#ifdef WTERMSIG
+ if (WIFSIGNALED(status)) {
+ return WTERMSIG(status);
+ }
+#endif
+
+ /*
+ * Some other failure.
+ */
+ return 1;
+ }
+ }
+#endif
+}
+
+static int run_command(command_t *cmd, count_chars *cc)
+{
+ int ret;
+ char *command;
+ char *tmp;
+ char const *raw;
+ char const *spawn_args[4];
+ count_chars tmpcc;
+
+ init_count_chars(&tmpcc);
+
+ if (cmd->program) {
+ push_count_chars(&tmpcc, cmd->program);
+ }
+
+ append_count_chars(&tmpcc, cmd->program_opts);
+
+ append_count_chars(&tmpcc, cc);
+
+ raw = flatten_count_chars(&tmpcc, ' ');
+ command = shell_esc(raw);
+
+ memcpy(&tmp, &raw, sizeof(tmp));
+ free(tmp);
+
+ spawn_args[0] = SHELL_CMD;
+ spawn_args[1] = "-c";
+ spawn_args[2] = command;
+ spawn_args[3] = NULL;
+ ret = external_spawn(cmd, spawn_args[0], spawn_args);
+
+ free(command);
+
+ return ret;
+}
+
+/*
+ * print configuration
+ * shlibpath_var is used in configure.
+ */
+#define printc(_x,_y) if (!value || !strcmp(value, _x)) printf(_x "=\"%s\"\n", _y)
+
+static void print_config(char const *value)
+{
+#ifdef LD_RUN_PATH
+ printc("runpath_var", LD_RUN_PATH);
+#endif
+#ifdef LD_LIBRARY_PATH
+ printc("shlibpath_var", LD_LIBRARY_PATH);
+#endif
+#ifdef LD_LIBRARY_PATH_LOCAL
+ printc("shlocallibpath_var", LD_LIBRARY_PATH_LOCAL);
+#endif
+#ifdef SHELL_CMD
+ printc("SHELL", SHELL_CMD);
+#endif
+#ifdef OBJECT_EXT
+ printc("objext", OBJECT_EXT);
+#endif
+#ifdef OBJDIR
+ printc("objdir", OBJDIR);
+#endif
+#ifdef DYNAMIC_LIB_EXT
+ /* add a '.' prefix because libtool does that. */
+ printc("shrext_cmds", "echo ." DYNAMIC_LIB_EXT);
+ /* add a '.' prefix because libtool does that. */
+ printc("shrext", "." DYNAMIC_LIB_EXT);
+#endif
+#ifdef EXE_EXT
+ printc("exeext", EXE_EXT);
+#endif
+#ifdef STATIC_LIB_EXT
+ printc("libext", STATIC_LIB_EXT);
+#endif
+#ifdef LIBRARIAN
+ printc("AR", LIBRARIAN);
+#endif
+#ifdef LIBRARIAN_OPTS
+ printc("AR_FLAGS", LIBRARIAN_OPTS);
+#endif
+#ifdef LINKER_FLAG_PREFIX
+ printc("wl", LINKER_FLAG_PREFIX);
+#endif
+#ifdef RANLIB
+ printc("ranlib", RANLIB);
+#endif
+
+}
+/*
+ * Add a directory to the runtime library search path.
+ */
+static void add_runtime_dir_lib(char const *arg, command_t *cmd)
+{
+#ifdef RPATH
+ add_rpath(cmd->shared_opts.dependencies, arg);
+#else
+ (void) arg; /* -Wunused */
+ (void) cmd;
+#endif
+}
+
+static int parse_long_opt(char const *arg, command_t *cmd)
+{
+ char *equal_pos = strchr(arg, '=');
+ char var[50];
+ char value[500];
+
+ if (equal_pos) {
+ strncpy(var, arg, equal_pos - arg);
+ var[equal_pos - arg] = 0;
+ if (strlen(equal_pos + 1) >= sizeof(var)) {
+ return 0;
+ }
+ strcpy(value, equal_pos + 1);
+ } else {
+ strncpy(var, arg, sizeof(var) - 1);
+ var[sizeof(var) - 1] = '\0';
+
+ value[0] = '\0';
+ }
+
+ if (strcmp(var, "silent") == 0) {
+ cmd->options.silent = 1;
+ } else if (strcmp(var, "quiet") == 0) {
+ cmd->options.silent = 1;
+ } else if (strcmp(var, "debug") == 0) {
+ cmd->options.debug = 1;
+ } else if (strcmp(var, "mode") == 0) {
+ if (cmd->mode != MODE_UNKNOWN) {
+ ERROR("Cannot set --mode twice\n");
+ exit(1);
+ }
+
+ if (strcmp(value, "compile") == 0) {
+ cmd->mode = MODE_COMPILE;
+ cmd->output = OUT_OBJECT;
+
+ } else if (strcmp(value, "link") == 0) {
+ cmd->mode = MODE_LINK;
+ cmd->output = OUT_LIB;
+
+ } else if (strcmp(value, "install") == 0) {
+ cmd->mode = MODE_INSTALL;
+
+ } else if (strcmp(value, "execute") == 0) {
+ cmd->mode = MODE_EXECUTE;
+
+ } else {
+ ERROR("Unknown mode \"%s\"\n", value);
+ exit(1);
+ }
+
+ } else if (strcmp(var, "shared") == 0) {
+ if ((cmd->mode == MODE_LINK) && (cmd->output == OUT_GENERAL)) {
+ cmd->output = OUT_DYNAMIC_LIB_ONLY;
+ }
+ cmd->options.shared = SHARE_SHARED;
+
+ } else if (strcmp(var, "export-all") == 0) {
+ cmd->options.export_all = 1;
+
+ } else if (strcmp(var, "dry-run") == 0) {
+ NOTICE("Dry-run mode on!\n");
+ cmd->options.dry_run = 1;
+
+ } else if (strcmp(var, "version") == 0) {
+ NOTICE("Version " VERSION "\n");
+
+ } else if (strcmp(var, "help") == 0) {
+ usage(0);
+
+ } else if (strcmp(var, "config") == 0) {
+ print_config(value);
+
+ exit(0);
+ } else {
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Return 1 if we eat it. */
+static int parse_short_opt(char const *arg, command_t *cmd)
+{
+ if (strcmp(arg, "export-dynamic") == 0) {
+ cmd->options.export_dynamic = 1;
+ return 1;
+ }
+
+ if (strcmp(arg, "module") == 0) {
+ cmd->output = OUT_MODULE;
+ return 1;
+ }
+
+ if (strcmp(arg, "shared") == 0) {
+ if (cmd->mode == MODE_LINK) {
+ cmd->output = OUT_DYNAMIC_LIB_ONLY;
+ }
+ cmd->options.shared = SHARE_SHARED;
+ return 1;
+ }
+
+ if (strcmp(arg, "Zexe") == 0) {
+ return 1;
+ }
+
+ if (strcmp(arg, "avoid-version") == 0) {
+ return 1;
+ }
+
+ if (strcmp(arg, "prefer-pic") == 0) {
+ cmd->options.pic_mode = PIC_PREFER;
+ return 1;
+ }
+
+ if (strcmp(arg, "prefer-non-pic") == 0) {
+ cmd->options.pic_mode = PIC_AVOID;
+ return 1;
+ }
+
+ if (strcmp(arg, "static") == 0) {
+ if ((cmd->mode == MODE_LINK) && (cmd->output == OUT_LIB)) {
+ cmd->output = OUT_STATIC_LIB_ONLY;
+ }
+ cmd->options.shared = SHARE_STATIC;
+ return 1;
+ }
+
+ if (cmd->mode == MODE_LINK) {
+ if (strcmp(arg, "no-install") == 0) {
+ cmd->options.no_install = 1;
+ return 1;
+ }
+ if (arg[0] == 'L' || arg[0] == 'l') {
+ /* Hack... */
+ arg--;
+ push_count_chars(cmd->shared_opts.dependencies, arg);
+ return 1;
+ } else if (arg[0] == 'R' && arg[1]) {
+ /* -Rdir Add dir to runtime library search path. */
+ add_runtime_dir_lib(&arg[1], cmd);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+#ifdef TRUNCATE_DLL_NAME
+static char *truncate_dll_name(char *path)
+{
+ /* Cut DLL name down to 8 characters after removing any mod_ prefix */
+ char *tmppath = strdup(path);
+ char *newname = strrchr(tmppath, '/') + 1;
+ char *ext = strrchr(newname, '.');
+ int len;
+
+ if (ext == NULL) {
+ return tmppath;
+ }
+
+ len = ext - newname;
+
+ if (strncmp(newname, "mod_", 4) == 0) {
+ strcpy(newname, newname + 4);
+ len -= 4;
+ }
+
+ if (len > 8) {
+ strcpy(newname + 8, strchr(newname, '.'));
+ }
+
+ return tmppath;
+}
+#endif
+
+static long safe_strtol(char const *nptr, char const **endptr, int base)
+{
+ long rv;
+
+ errno = 0;
+
+ rv = strtol(nptr, (char**)endptr, 10);
+
+ if (errno == ERANGE) {
+ return 0;
+ }
+
+ return rv;
+}
+
+static void safe_mkdir(command_t *cmd, char const *path)
+{
+ int status;
+ mode_t old_umask;
+
+ old_umask = umask(0);
+ umask(old_umask);
+
+#ifdef MKDIR_NO_UMASK
+ status = mkdir(path);
+#else
+ status = mkdir(path, ~old_umask);
+#endif
+ if ((status < 0) && (errno != EEXIST)) {
+ NOTICE("Warning: mkdir of %s failed\n", path);
+ }
+}
+
+/** Returns a file's name without the path
+ *
+ * @param path to break apart.
+ * @return pointer in path.
+ */
+static char const *file_name(char const *path)
+{
+ char const *name;
+
+ name = strrchr(path, '/');
+ if (!name) {
+ name = strrchr(path, '\\'); /* eww windows? */
+ }
+ if (!name) {
+ name = path;
+ } else {
+ name++;
+ }
+
+ return name;
+}
+
+#ifdef GEN_EXPORTS
+
+/** Returns a file's name without path or extension
+ *
+ * @param path to check
+ * @return pointer in path.
+ */
+static char const *file_name_stripped(char const *path)
+{
+ char const *name;
+ char const *ext;
+
+ name = file_name(path);
+ ext = strrchr(name, '.');
+
+ if (ext) {
+ char *trimmed;
+
+ trimmed = lt_malloc(ext - name + 1);
+ strncpy(trimmed, name, ext - name);
+ trimmed[ext-name] = 0;
+
+ return trimmed;
+ }
+
+ return name;
+}
+#endif
+
+/* version_info is in the form of MAJOR:MINOR:PATCH */
+static char const *darwin_dynamic_link_function(char const *version_info)
+{
+ char *newarg;
+ long major, minor, patch;
+
+ major = 0;
+ minor = 0;
+ patch = 0;
+
+ if (version_info) {
+ major = safe_strtol(version_info, &version_info, 10);
+
+ if (version_info) {
+ if (version_info[0] == ':') {
+ version_info++;
+ }
+
+ minor = safe_strtol(version_info, &version_info, 10);
+
+ if (version_info) {
+ if (version_info[0] == ':') {
+ version_info++;
+ }
+
+ patch = safe_strtol(version_info, &version_info, 10);
+
+ }
+ }
+ }
+
+ /* Avoid -dylib_compatibility_version must be greater than zero errors. */
+ if (major == 0) {
+ major = 1;
+ }
+ newarg = (char*)lt_malloc(100);
+ snprintf(newarg, 99,
+ "-compatibility_version %ld -current_version %ld.%ld",
+ major, major, minor);
+
+ return newarg;
+}
+
+
+/*
+ * Add a '.libs/' to the buffer. The caller ensures that
+ * The buffer is large enough to handle 6 extra characters.
+ */
+static void add_dotlibs(char *buffer)
+{
+ char *name = strrchr(buffer, '/');
+
+ if (!name) {
+ if (!buffer[0]) {
+ strcpy(buffer, ".libs/");
+ return;
+ }
+ name = buffer;
+ } else {
+ name++;
+ }
+ memmove(name + 6, name, strlen(name));
+ memcpy(name, ".libs/", 6);
+}
+
+static char *gen_library_name(char const *name, enum lib_type genlib)
+{
+ char *newarg, *newext;
+
+ newarg = (char *)calloc(strlen(name) + 11, 1);
+
+ if (genlib == TYPE_MODULE_LIB && strncmp(name, "lib", 3) == 0) {
+ name += 3;
+ }
+
+ if (genlib == TYPE_MODULE_LIB) {
+ strcpy(newarg, file_name(name));
+ }
+ else {
+ strcpy(newarg, name);
+ }
+
+ newext = strrchr(newarg, '.');
+ if (!newext) {
+ ERROR("Library path does not have an extension\n");
+ free(newarg);
+
+ return NULL;
+ }
+ newext++;
+
+ switch (genlib) {
+ case TYPE_STATIC_LIB:
+ strcpy(newext, STATIC_LIB_EXT);
+ break;
+ case TYPE_DYNAMIC_LIB:
+ strcpy(newext, DYNAMIC_LIB_EXT);
+ break;
+ case TYPE_MODULE_LIB:
+ strcpy(newext, MODULE_LIB_EXT);
+ break;
+
+ default:
+ break;
+ }
+
+ add_dotlibs(newarg);
+
+ return newarg;
+}
+
+static char *gen_install_name(char const *name, enum lib_type genlib)
+{
+ char *newname;
+ int rv;
+ struct stat sb;
+
+ newname = gen_library_name(name, genlib);
+ if (!newname) return NULL;
+
+ /* Check if it exists. If not, return NULL. */
+ rv = stat(newname, &sb);
+
+ if (rv) {
+ free(newname);
+ return NULL;
+ }
+
+ return newname;
+}
+
+static char const *check_object_exists(command_t *cmd, char const *arg, int arglen)
+{
+ char *newarg, *ext;
+ struct stat sb;
+
+ newarg = (char *)lt_malloc(arglen + 10);
+ memcpy(newarg, arg, arglen);
+ newarg[arglen] = 0;
+ ext = newarg + arglen;
+
+ strcpy(ext, OBJECT_EXT);
+
+ DEBUG("Checking (obj): %s\n", newarg);
+ if (stat(newarg, &sb) == 0) {
+ return newarg;
+ }
+
+ free(newarg);
+
+ return NULL;
+}
+
+/* libdircheck values:
+ * 0 - no .libs suffix
+ * 1 - .libs suffix
+ */
+static char *check_library_exists(command_t *cmd, char const *arg, int pathlen,
+ int libdircheck, enum lib_type *libtype)
+{
+ char *newarg, *ext;
+ int pass, rv, newpathlen;
+
+ newarg = (char *)lt_malloc(strlen(arg) + 10);
+ strcpy(newarg, arg);
+ newarg[pathlen] = '\0';
+
+ newpathlen = pathlen;
+ if (libdircheck) {
+ add_dotlibs(newarg);
+ newpathlen += sizeof(".libs/") - 1;
+ }
+
+ strcpy(newarg + newpathlen, arg + pathlen);
+ ext = strrchr(newarg, '.');
+ if (!ext) {
+ ERROR("Error: Library path does not have an extension\n");
+ free(newarg);
+
+ return NULL;
+ }
+ ext++;
+
+ pass = 0;
+
+ do {
+ struct stat sb;
+
+ switch (pass) {
+ case 0:
+ if (cmd->options.pic_mode != PIC_AVOID &&
+ cmd->options.shared != SHARE_STATIC) {
+ strcpy(ext, DYNAMIC_LIB_EXT);
+ *libtype = TYPE_DYNAMIC_LIB;
+ break;
+ }
+ pass = 1;
+ /* Fall through */
+ case 1:
+ strcpy(ext, STATIC_LIB_EXT);
+ *libtype = TYPE_STATIC_LIB;
+ break;
+ case 2:
+ strcpy(ext, MODULE_LIB_EXT);
+ *libtype = TYPE_MODULE_LIB;
+ break;
+ case 3:
+ strcpy(ext, OBJECT_EXT);
+ *libtype = TYPE_OBJECT;
+ break;
+ default:
+ *libtype = TYPE_UKNOWN;
+ break;
+ }
+
+ DEBUG("Checking (lib): %s\n", newarg);
+ rv = stat(newarg, &sb);
+ }
+ while (rv != 0 && ++pass < 4);
+
+ if (rv == 0) {
+ return newarg;
+ }
+
+ free(newarg);
+
+ return NULL;
+}
+
+static char * load_install_path(char const *arg)
+{
+ FILE *f;
+ char *path;
+
+ f = fopen(arg,"r");
+ if (f == NULL) {
+ return NULL;
+ }
+
+ path = lt_malloc(PATH_MAX);
+
+ fgets(path, PATH_MAX, f);
+ fclose(f);
+
+ if (path[strlen(path)-1] == '\n') {
+ path[strlen(path)-1] = '\0';
+ }
+
+ /* Check that we have an absolute path.
+ * Otherwise the file could be a GNU libtool file.
+ */
+ if (path[0] != '/') {
+ free(path);
+
+ return NULL;
+ }
+ return path;
+}
+
+static char *load_noinstall_path(char const *arg, int pathlen)
+{
+ char *newarg, *expanded_path;
+ int newpathlen;
+
+ newarg = (char *)lt_malloc(strlen(arg) + 10);
+ strcpy(newarg, arg);
+ newarg[pathlen] = 0;
+
+ newpathlen = pathlen;
+ strcat(newarg, ".libs");
+ newpathlen += sizeof(".libs") - 1;
+ newarg[newpathlen] = 0;
+
+#ifdef HAS_REALPATH
+ expanded_path = lt_malloc(PATH_MAX);
+ expanded_path = realpath(newarg, expanded_path);
+ /* Uh, oh. There was an error. Fall back on our first guess. */
+ if (!expanded_path) {
+ expanded_path = newarg;
+ }
+#else
+ /* We might get ../ or something goofy. Oh, well. */
+ expanded_path = newarg;
+#endif
+
+ return expanded_path;
+}
+
+static void add_dynamic_link_opts(command_t *cmd, count_chars *args)
+{
+#ifdef DYNAMIC_LINK_OPTS
+ if (cmd->options.pic_mode != PIC_AVOID) {
+ DEBUG("Adding linker opt: %s\n", DYNAMIC_LINK_OPTS);
+
+ push_count_chars(args, DYNAMIC_LINK_OPTS);
+ if (cmd->undefined_flag) {
+ push_count_chars(args, "-undefined");
+#if defined(__APPLE__)
+ /* -undefined dynamic_lookup is used by the bundled Python in
+ * 10.4, but if we don't set MACOSX_DEPLOYMENT_TARGET to 10.3+,
+ * we'll get a linker error if we pass this flag.
+ */
+ if (strcasecmp(cmd->undefined_flag, "dynamic_lookup") == 0) {
+ insert_count_chars(cmd->program_opts, "MACOSX_DEPLOYMENT_TARGET=10.3", 0);
+ }
+#endif
+ push_count_chars(args, cmd->undefined_flag);
+ }
+ else {
+#ifdef DYNAMIC_LINK_UNDEFINED
+ DEBUG("Adding linker opt: %s\n", DYNAMIC_LINK_UNDEFINED);
+
+ push_count_chars(args, DYNAMIC_LINK_UNDEFINED);
+#endif
+ }
+ }
+#endif
+}
+
+/* Read the final install location and add it to runtime library search path. */
+#ifdef RPATH
+static void add_rpath(count_chars *cc, char const *path)
+{
+ int size = 0;
+ char *tmp;
+
+#ifdef LINKER_FLAG_PREFIX
+ size = strlen(LINKER_FLAG_PREFIX);
+#endif
+ size = size + strlen(path) + strlen(RPATH) + 2;
+ tmp = lt_malloc(size);
+
+#ifdef LINKER_FLAG_PREFIX
+ strcpy(tmp, LINKER_FLAG_PREFIX);
+ strcat(tmp, RPATH);
+#else
+ strcpy(tmp, RPATH);
+#endif
+#ifndef LINKER_FLAG_NO_EQUALS
+ strcat(tmp, "=");
+#endif
+ strcat(tmp, path);
+
+ push_count_chars(cc, tmp);
+}
+
+static void add_rpath_file(count_chars *cc, char const *arg)
+{
+ char const *path;
+
+ path = load_install_path(arg);
+ if (path) {
+ add_rpath(cc, path);
+ lt_const_free(path);
+ }
+}
+
+static void add_rpath_noinstall(count_chars *cc, char const *arg, int pathlen)
+{
+ char const *path;
+
+ path = load_noinstall_path(arg, pathlen);
+ if (path) {
+ add_rpath(cc, path);
+ lt_const_free(path);
+ }
+}
+#endif
+
+#ifdef DYNAMIC_LINK_NO_INSTALL
+static void add_dylink_noinstall(count_chars *cc, char const *arg, int pathlen,
+ int extlen)
+{
+ char const *install_path, *current_path, *name;
+ char *exp_argument;
+ int i_p_len, c_p_len, name_len, dyext_len, cur_len;
+
+ install_path = load_install_path(arg);
+ current_path = load_noinstall_path(arg, pathlen);
+
+ if (!install_path || !current_path) {
+ return;
+ }
+
+ push_count_chars(cc, DYNAMIC_LINK_NO_INSTALL);
+
+ i_p_len = strlen(install_path);
+ c_p_len = strlen(current_path);
+
+ name = arg+pathlen;
+ name_len = extlen-pathlen;
+ dyext_len = sizeof(DYNAMIC_LIB_EXT) - 1;
+
+ /* No, we need to replace the extension. */
+ exp_argument = (char *)lt_malloc(i_p_len + c_p_len + (name_len*2) +
+ (dyext_len*2) + 2);
+
+ cur_len = 0;
+ strcpy(exp_argument, install_path);
+ cur_len += i_p_len;
+ exp_argument[cur_len++] = '/';
+ strncpy(exp_argument+cur_len, name, extlen-pathlen);
+ cur_len += name_len;
+ strcpy(exp_argument+cur_len, DYNAMIC_LIB_EXT);
+ cur_len += dyext_len;
+ exp_argument[cur_len++] = ':';
+ strcpy(exp_argument+cur_len, current_path);
+ cur_len += c_p_len;
+ exp_argument[cur_len++] = '/';
+ strncpy(exp_argument+cur_len, name, extlen-pathlen);
+ cur_len += name_len;
+ strcpy(exp_argument+cur_len, DYNAMIC_LIB_EXT);
+ cur_len += dyext_len;
+
+ push_count_chars(cc, exp_argument);
+}
+#endif
+
+#ifdef ADD_MINUS_L
+/* use -L -llibname to allow to use installed libraries */
+static void add_minus_l(count_chars *cc, char const *arg)
+{
+ char *newarg;
+ char *name = strrchr(arg, '/');
+ char *file = strrchr(arg, '.');
+
+ if ((name != NULL) && (file != NULL) &&
+ (strstr(name, "lib") == (name + 1))) {
+ *name = '\0';
+ *file = '\0';
+ file = name;
+ file = file+4;
+ push_count_chars(cc, "-L");
+ push_count_chars(cc, arg);
+ /* we need one argument like -lapr-1 */
+ newarg = lt_malloc(strlen(file) + 3);
+ strcpy(newarg, "-l");
+ strcat(newarg, file);
+ push_count_chars(cc, newarg);
+ } else {
+ push_count_chars(cc, arg);
+ }
+}
+#endif
+
+#if 0
+static void add_linker_flag_prefix(count_chars *cc, char const *arg)
+{
+#ifndef LINKER_FLAG_PREFIX
+ push_count_chars(cc, arg);
+#else
+ char *newarg;
+ newarg = (char*)lt_malloc(strlen(arg) + sizeof(LINKER_FLAG_PREFIX) + 1);
+ strcpy(newarg, LINKER_FLAG_PREFIX);
+ strcat(newarg, arg);
+ push_count_chars(cc, newarg);
+#endif
+}
+#endif
+
+static int explode_static_lib(command_t *cmd, char const *lib)
+{
+ count_chars tmpdir_cc, libname_cc;
+ char const *tmpdir, *libname;
+ char savewd[PATH_MAX];
+ char const *name;
+ DIR *dir;
+ struct dirent *entry;
+ char const *lib_args[4];
+
+ /* Bah! */
+ if (cmd->options.dry_run) {
+ return 0;
+ }
+
+ name = file_name(lib);
+
+ init_count_chars(&tmpdir_cc);
+ push_count_chars(&tmpdir_cc, ".libs/");
+ push_count_chars(&tmpdir_cc, name);
+ push_count_chars(&tmpdir_cc, ".exploded/");
+ tmpdir = flatten_count_chars(&tmpdir_cc, 0);
+
+ NOTICE("Making: %s\n", tmpdir);
+
+ safe_mkdir(cmd, tmpdir);
+
+ push_count_chars(cmd->tmp_dirs, tmpdir);
+
+ getcwd(savewd, sizeof(savewd));
+
+ if (chdir(tmpdir) != 0) {
+ NOTICE("Warning: could not explode %s\n", lib);
+
+ return 1;
+ }
+
+ if (lib[0] == '/') {
+ libname = lib;
+ }
+ else {
+ init_count_chars(&libname_cc);
+ push_count_chars(&libname_cc, "../../");
+ push_count_chars(&libname_cc, lib);
+ libname = flatten_count_chars(&libname_cc, 0);
+ }
+
+ lib_args[0] = LIBRARIAN;
+ lib_args[1] = "x";
+ lib_args[2] = libname;
+ lib_args[3] = NULL;
+
+ external_spawn(cmd, LIBRARIAN, lib_args);
+
+ chdir(savewd);
+ dir = opendir(tmpdir);
+
+ while ((entry = readdir(dir)) != NULL) {
+#if defined(__APPLE__) && defined(RANLIB)
+ /* Apple inserts __.SYMDEF which isn't needed.
+ * Leopard (10.5+) can also add '__.SYMDEF SORTED' which isn't
+ * much fun either. Just skip them.
+ */
+ if (strstr(entry->d_name, "__.SYMDEF") != NULL) {
+ continue;
+ }
+#endif
+ if (entry->d_name[0] != '.') {
+ push_count_chars(&tmpdir_cc, entry->d_name);
+ name = flatten_count_chars(&tmpdir_cc, 0);
+
+ DEBUG("Adding object: %s\n", name);
+ push_count_chars(cmd->obj_files, name);
+ pop_count_chars(&tmpdir_cc);
+ }
+ }
+
+ closedir(dir);
+ return 0;
+}
+
+static int parse_input_file_name(char const *arg, command_t *cmd)
+{
+ char const *ext = strrchr(arg, '.');
+ char const *name;
+ int pathlen;
+ enum lib_type libtype;
+ char const *newarg;
+
+ /* Can't guess the extension */
+ if (!ext) {
+ return 0;
+ }
+
+ ext++;
+ name = file_name(arg);
+ pathlen = name - arg;
+
+ /*
+ * Were linking and have an archived object or object file
+ * push it onto the list of object files which'll get used
+ * to create the input files list for the linker.
+ *
+ * We assume that these are outside of the project were building,
+ * as there's no reason to create .a files as part of the build
+ * process.
+ */
+ if (!strcmp(ext, STATIC_LIB_EXT) && (cmd->mode == MODE_LINK)) {
+ struct stat sb;
+
+ if (!stat(arg, &sb)) {
+ DEBUG("Adding object: %s\n", arg);
+
+ push_count_chars(cmd->obj_files, arg);
+
+ return 1;
+ }
+ }
+
+ /*
+ * More object files, if were linking they get set as input
+ * files.
+ */
+ if (!strcmp(ext, "lo") || !strcmp(ext, OBJECT_EXT)) {
+ newarg = check_object_exists(cmd, arg, ext - arg);
+ if (!newarg) {
+ ERROR("Can not find suitable object file for %s\n", arg);
+ exit(1);
+ }
+
+ if (cmd->mode == MODE_LINK) {
+ DEBUG("Adding object: %s\n", newarg);
+
+ push_count_chars(cmd->obj_files, newarg);
+ } else {
+ push_count_chars(cmd->arglist, newarg);
+ }
+
+ return 1;
+ }
+
+ if (!strcmp(ext, "la")) {
+ switch (cmd->mode) {
+ case MODE_LINK:
+ /* Try the .libs dir first! */
+ newarg = check_library_exists(cmd, arg, pathlen, 1, &libtype);
+ if (!newarg) {
+ /* Try the normal dir next. */
+ newarg = check_library_exists(cmd, arg, pathlen, 0, &libtype);
+ if (!newarg) {
+ ERROR("Can not find suitable library for %s\n", arg);
+ exit(1);
+ }
+ }
+
+ /* It is not ok to just add the file: a library may added with:
+ 1 - -L path library_name. (For *.so in Linux).
+ 2 - library_name.
+ */
+#ifdef ADD_MINUS_L
+ if (libtype == TYPE_DYNAMIC_LIB) {
+ add_minus_l(cmd->shared_opts.dependencies, newarg);
+ } else if (cmd->output == OUT_LIB &&
+ libtype == TYPE_STATIC_LIB) {
+ explode_static_lib(cmd, newarg);
+ } else {
+ push_count_chars(cmd->shared_opts.dependencies, newarg);
+ }
+#else
+ if (cmd->output == OUT_LIB && libtype == TYPE_STATIC_LIB) {
+ explode_static_lib(cmd, newarg);
+ }
+ else {
+ push_count_chars(cmd->shared_opts.dependencies, newarg);
+ }
+#endif
+ if (libtype == TYPE_DYNAMIC_LIB) {
+ if (cmd->options.no_install) {
+#ifdef RPATH
+ add_rpath_noinstall(cmd->shared_opts.dependencies,
+ arg, pathlen);
+#endif
+ }
+ else {
+#ifdef RPATH
+ add_rpath_file(cmd->shared_opts.dependencies, arg);
+#endif
+ }
+ }
+ break;
+ case MODE_INSTALL:
+ /*
+ * If we've already recorded a library to
+ * install, we're most likely getting the .la
+ * file that we want to install as.
+ *
+ * The problem is that we need to add it as the
+ * directory, not the .la file itself.
+ * Otherwise, we'll do odd things.
+ */
+ if (cmd->output == OUT_LIB) {
+ char *tmp;
+
+ tmp = strdup(arg);
+ tmp[pathlen] = '\0';
+ push_count_chars(cmd->arglist, tmp);
+
+ } else {
+ cmd->output = OUT_LIB;
+ cmd->output_name = arg;
+ cmd->static_name.install = gen_install_name(arg, 0);
+ cmd->shared_name.install = gen_install_name(arg, 1);
+ cmd->module_name.install = gen_install_name(arg, 2);
+
+ if (!cmd->static_name.install &&
+ !cmd->shared_name.install &&
+ !cmd->module_name.install) {
+ ERROR("Files to install do not exist\n");
+ exit(1);
+ }
+
+ }
+ break;
+ default:
+ break;
+ }
+
+ return 1;
+ }
+
+ if (!strcmp(ext, "c")) {
+ /* If we don't already have an idea what our output name will be. */
+ if (!cmd->basename) {
+ char *tmp = lt_malloc(strlen(arg) + 4);
+ strcpy(tmp, arg);
+ strcpy(strrchr(tmp, '.') + 1, "lo");
+
+ cmd->basename = tmp;
+
+ cmd->fake_output_name = strrchr(cmd->basename, '/');
+ if (cmd->fake_output_name) {
+ cmd->fake_output_name++;
+ } else {
+ cmd->fake_output_name = cmd->basename;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int parse_output_file_name(char const *arg, command_t *cmd)
+{
+ char const *name;
+ char const *ext;
+ char *newarg = NULL;
+ size_t pathlen;
+
+ cmd->fake_output_name = arg;
+
+ name = file_name(arg);
+ ext = strrchr(name, '.');
+
+#ifdef EXE_EXT
+ if (!ext || strcmp(ext, EXE_EXT) == 0) {
+#else
+ if (!ext) {
+#endif
+ cmd->basename = arg;
+ cmd->output = OUT_PROGRAM;
+#if defined(_OSD_POSIX)
+ cmd->options.pic_mode = PIC_AVOID;
+#endif
+ newarg = (char *)lt_malloc(strlen(arg) + 5);
+ strcpy(newarg, arg);
+#ifdef EXE_EXT
+ if (!ext) {
+ strcat(newarg, EXE_EXT);
+ }
+#endif
+ cmd->output_name = newarg;
+ return 1;
+ }
+
+ ext++;
+ pathlen = name - arg;
+
+ if (strcmp(ext, "la") == 0) {
+ assert(cmd->mode == MODE_LINK);
+
+ cmd->basename = arg;
+ cmd->static_name.normal = gen_library_name(arg, TYPE_STATIC_LIB);
+ cmd->shared_name.normal = gen_library_name(arg, TYPE_DYNAMIC_LIB);
+ cmd->module_name.normal = gen_library_name(arg, TYPE_MODULE_LIB);
+ cmd->static_name.install = gen_install_name(arg, TYPE_STATIC_LIB);
+ cmd->shared_name.install = gen_install_name(arg, TYPE_DYNAMIC_LIB);
+ cmd->module_name.install = gen_install_name(arg, TYPE_MODULE_LIB);
+
+ if (!cmd->options.dry_run) {
+ char *newname;
+ char *newext;
+ newname = lt_malloc(strlen(cmd->static_name.normal) + 1);
+
+ strcpy(newname, cmd->static_name.normal);
+ newext = strrchr(newname, '/');
+ if (!newext) {
+ /* Check first to see if the dir already exists! */
+ safe_mkdir(cmd, ".libs");
+ } else {
+ *newext = '\0';
+ safe_mkdir(cmd, newname);
+ }
+ free(newname);
+ }
+
+#ifdef TRUNCATE_DLL_NAME
+ if (shared) {
+ arg = truncate_dll_name(arg);
+ }
+#endif
+
+ cmd->output_name = arg;
+ return 1;
+ }
+
+ if (strcmp(ext, STATIC_LIB_EXT) == 0) {
+ assert(cmd->mode == MODE_LINK);
+
+ cmd->basename = arg;
+ cmd->options.shared = SHARE_STATIC;
+ cmd->output = OUT_STATIC_LIB_ONLY;
+ cmd->static_name.normal = gen_library_name(arg, TYPE_STATIC_LIB);
+ cmd->static_name.install = gen_install_name(arg, TYPE_STATIC_LIB);
+
+ if (!cmd->options.dry_run) {
+ char *newname;
+ char *newext;
+ newname = lt_malloc(strlen(cmd->static_name.normal) + 1);
+
+ strcpy(newname, cmd->static_name.normal);
+ newext = strrchr(newname, '/');
+ if (!newext) {
+ /* Check first to see if the dir already exists! */
+ safe_mkdir(cmd, ".libs");
+ } else {
+ *newext = '\0';
+ safe_mkdir(cmd, newname);
+ }
+ free(newname);
+ }
+
+ cmd->output_name = arg;
+ return 1;
+ }
+
+ if (strcmp(ext, DYNAMIC_LIB_EXT) == 0) {
+ assert(cmd->mode == MODE_LINK);
+
+ cmd->basename = arg;
+ cmd->options.shared = SHARE_SHARED;
+ cmd->output = OUT_DYNAMIC_LIB_ONLY;
+ cmd->shared_name.normal = gen_library_name(arg, TYPE_DYNAMIC_LIB);
+ cmd->module_name.normal = gen_library_name(arg, TYPE_MODULE_LIB);
+ cmd->shared_name.install = gen_install_name(arg, TYPE_DYNAMIC_LIB);
+ cmd->module_name.install = gen_install_name(arg, TYPE_MODULE_LIB);
+
+ if (!cmd->options.dry_run) {
+ char *newname;
+ char *newext;
+ newname = lt_malloc(strlen(cmd->shared_name.normal) + 1);
+
+ strcpy(newname, cmd->shared_name.normal);
+ newext = strrchr(newname, '/');
+ if (!newext) {
+ /* Check first to see if the dir already exists! */
+ safe_mkdir(cmd, ".libs");
+ } else {
+ *newext = '\0';
+ safe_mkdir(cmd, newname);
+ }
+ free(newname);
+ }
+
+ cmd->output_name = arg;
+ return 1;
+ }
+
+ if (strcmp(ext, "lo") == 0) {
+ char *newext;
+ cmd->basename = arg;
+ cmd->output = OUT_OBJECT;
+ newarg = (char *)lt_malloc(strlen(arg) + 2);
+ strcpy(newarg, arg);
+ newext = strrchr(newarg, '.') + 1;
+ strcpy(newext, OBJECT_EXT);
+ cmd->output_name = newarg;
+ return 1;
+ }
+
+ if (strcmp(ext, DYNAMIC_LIB_EXT) == 0) {
+ ERROR("Please build libraries with .la target, not ."
+ DYNAMIC_LIB_EXT "\n");
+
+ exit(1);
+ }
+
+ if (strcmp(ext, STATIC_LIB_EXT) == 0) {
+ ERROR("Please build libraries with .la target, not ."
+ STATIC_LIB_EXT "\n");
+
+ exit(1);
+ }
+
+ return 0;
+}
+
+static char const *automode(char const *arg, command_t *cmd)
+{
+ if (cmd->mode != MODE_UNKNOWN) return arg;
+
+ if (!strcmp(arg, "CC") ||
+ !strcmp(arg, "CXX")) {
+ DEBUG("Now in compile mode, guessed from: %s\n", arg);
+ arg = CC;
+ cmd->mode = MODE_COMPILE;
+
+ } else if (!strcmp(arg, "LINK") ||
+ !strcmp(arg, "LINK.c") ||
+ !strcmp(arg, "LINK.cxx")) {
+ DEBUG("Now in linker mode, guessed from: %s\n", arg);
+ arg = LINK_C;
+ cmd->mode = MODE_LINK;
+ }
+
+ return arg;
+}
+
+
+#ifdef GEN_EXPORTS
+static void generate_def_file(command_t *cmd)
+{
+ char def_file[1024];
+ char implib_file[1024];
+ char *ext;
+ FILE *hDef;
+ char *export_args[1024];
+ int num_export_args = 0;
+ char *cmd;
+ int cmd_size = 0;
+ int a;
+
+ if (cmd->output_name) {
+ strcpy(def_file, cmd->output_name);
+ strcat(def_file, ".def");
+ hDef = fopen(def_file, "w");
+
+ if (hDef != NULL) {
+ fprintf(hDef, "LIBRARY '%s' INITINSTANCE\n", file_name_stripped(cmd->output_name));
+ fprintf(hDef, "DATA NONSHARED\n");
+ fprintf(hDef, "EXPORTS\n");
+ fclose(hDef);
+
+ for (a = 0; a < cmd->num_obj_files; a++) {
+ cmd_size += strlen(cmd->obj_files[a]) + 1;
+ }
+
+ cmd_size += strlen(GEN_EXPORTS) + strlen(def_file) + 3;
+ cmd = (char *)lt_malloc(cmd_size);
+ strcpy(cmd, GEN_EXPORTS);
+
+ for (a=0; a < cmd->num_obj_files; a++) {
+ strcat(cmd, " ");
+ strcat(cmd, cmd->obj_files[a] );
+ }
+
+ strcat(cmd, ">>");
+ strcat(cmd, def_file);
+ puts(cmd);
+ export_args[num_export_args++] = SHELL_CMD;
+ export_args[num_export_args++] = "-c";
+ export_args[num_export_args++] = cmd;
+ export_args[num_export_args++] = NULL;
+ external_spawn(cmd, export_args[0], (char const**)export_args);
+ cmd->arglist[cmd->num_args++] = strdup(def_file);
+
+ /* Now make an import library for the dll */
+ num_export_args = 0;
+ export_args[num_export_args++] = DEF2IMPLIB_CMD;
+ export_args[num_export_args++] = "-o";
+
+ strcpy(implib_file, ".libs/");
+ strcat(implib_file, cmd->basename);
+ ext = strrchr(implib_file, '.');
+
+ if (ext) {
+ *ext = '\0';
+ }
+
+ strcat(implib_file, ".");
+ strcat(implib_file, STATIC_LIB_EXT);
+
+ export_args[num_export_args++] = implib_file;
+ export_args[num_export_args++] = def_file;
+ export_args[num_export_args++] = NULL;
+ external_spawn(cmd, export_args[0], (char const**)export_args);
+
+ }
+ }
+}
+#endif
+
+#if 0
+static char const* expand_path(char const *relpath)
+{
+ char foo[PATH_MAX], *newpath;
+
+ getcwd(foo, PATH_MAX-1);
+ newpath = (char*)lt_malloc(strlen(foo)+strlen(relpath)+2);
+ strcpy(newpath, foo);
+ strcat(newpath, "/");
+ strcat(newpath, relpath);
+ return newpath;
+}
+#endif
+
+static void link_fixup(command_t *cmd)
+{
+ /* If we were passed an -rpath directive, we need to build
+ * shared objects too. Otherwise, we should only create static
+ * libraries.
+ */
+ if (!cmd->install_path && (cmd->output == OUT_DYNAMIC_LIB_ONLY ||
+ cmd->output == OUT_MODULE || cmd->output == OUT_LIB)) {
+ if (cmd->options.shared == SHARE_SHARED) {
+ cmd->install_path = LIBDIR;
+ }
+ }
+
+ if (cmd->output == OUT_DYNAMIC_LIB_ONLY ||
+ cmd->output == OUT_MODULE ||
+ cmd->output == OUT_LIB) {
+
+ push_count_chars(cmd->shared_opts.normal, "-o");
+ if (cmd->output == OUT_MODULE) {
+ push_count_chars(cmd->shared_opts.normal, cmd->module_name.normal);
+ } else {
+ push_count_chars(cmd->shared_opts.normal, cmd->shared_name.normal);
+#ifdef DYNAMIC_INSTALL_NAME
+ push_count_chars(cmd->shared_opts.normal, DYNAMIC_INSTALL_NAME);
+
+ if (!cmd->install_path) {
+ ERROR("Installation mode requires -rpath\n");
+ exit(1);
+ }
+
+ {
+ char *tmp = lt_malloc(PATH_MAX);
+ strcpy(tmp, cmd->install_path);
+
+ if (cmd->shared_name.install) {
+ strcat(tmp, strrchr(cmd->shared_name.install, '/'));
+ } else {
+ strcat(tmp, strrchr(cmd->shared_name.normal, '/'));
+ }
+
+ push_count_chars(cmd->shared_opts.normal, tmp);
+ }
+#endif
+ }
+
+ append_count_chars(cmd->shared_opts.normal, cmd->obj_files);
+ append_count_chars(cmd->shared_opts.normal, cmd->shared_opts.dependencies);
+
+ if (cmd->options.export_all) {
+#ifdef GEN_EXPORTS
+ generate_def_file(cmd);
+#endif
+ }
+ }
+
+ if (cmd->output == OUT_LIB || cmd->output == OUT_STATIC_LIB_ONLY) {
+ push_count_chars(cmd->static_opts.normal, "-o");
+ push_count_chars(cmd->static_opts.normal, cmd->output_name);
+ }
+
+ if (cmd->output == OUT_PROGRAM) {
+ if (cmd->output_name) {
+ push_count_chars(cmd->arglist, "-o");
+ push_count_chars(cmd->arglist, cmd->output_name);
+ append_count_chars(cmd->arglist, cmd->obj_files);
+ append_count_chars(cmd->arglist, cmd->shared_opts.dependencies);
+ add_dynamic_link_opts(cmd, cmd->arglist);
+ }
+ }
+}
+
+static void post_parse_fixup(command_t *cmd)
+{
+ switch (cmd->mode) {
+ case MODE_COMPILE:
+#ifdef PIC_FLAG
+ if (cmd->options.pic_mode != PIC_AVOID) {
+ push_count_chars(cmd->arglist, PIC_FLAG);
+ }
+#endif
+ if (cmd->output_name) {
+ push_count_chars(cmd->arglist, "-o");
+ push_count_chars(cmd->arglist, cmd->output_name);
+ }
+ break;
+ case MODE_LINK:
+ link_fixup(cmd);
+ break;
+ case MODE_INSTALL:
+ if (cmd->output == OUT_LIB) {
+ link_fixup(cmd);
+ }
+ default:
+ break;
+ }
+
+#ifdef USE_OMF
+ if (cmd->output == OUT_OBJECT ||
+ cmd->output == OUT_PROGRAM ||
+ cmd->output == OUT_LIB ||
+ cmd->output == OUT_DYNAMIC_LIB_ONLY) {
+ push_count_chars(cmd->arglist, "-Zomf");
+ }
+#endif
+
+ if (cmd->options.shared &&
+ (cmd->output == OUT_OBJECT ||
+ cmd->output == OUT_LIB ||
+ cmd->output == OUT_DYNAMIC_LIB_ONLY)) {
+#ifdef SHARE_SW
+ push_count_chars(cmd->arglist, SHARE_SW);
+#endif
+ }
+}
+
+static int run_mode(command_t *cmd)
+{
+ int rv = 0;
+ count_chars *cctemp;
+
+ cctemp = (count_chars*)lt_malloc(sizeof(count_chars));
+ init_count_chars(cctemp);
+
+ switch (cmd->mode) {
+ case MODE_COMPILE:
+ rv = run_command(cmd, cmd->arglist);
+ if (rv) goto finish;
+ break;
+ case MODE_INSTALL:
+ /* Well, we'll assume it's a file going to a directory... */
+ /* For brain-dead install-sh based scripts, we have to repeat
+ * the command N-times. install-sh should die.
+ */
+ if (!cmd->output_name) {
+ rv = run_command(cmd, cmd->arglist);
+ if (rv) goto finish;
+ }
+ if (cmd->output_name) {
+ append_count_chars(cctemp, cmd->arglist);
+ insert_count_chars(cctemp,
+ cmd->output_name,
+ cctemp->num - 1);
+ rv = run_command(cmd, cctemp);
+ if (rv) goto finish;
+ clear_count_chars(cctemp);
+ }
+ if (cmd->static_name.install) {
+ append_count_chars(cctemp, cmd->arglist);
+ insert_count_chars(cctemp,
+ cmd->static_name.install,
+ cctemp->num - 1);
+ rv = run_command(cmd, cctemp);
+ if (rv) goto finish;
+#if defined(__APPLE__) && defined(RANLIB)
+ /* From the Apple libtool(1) manpage on Tiger/10.4:
+ * ----
+ * With the way libraries used to be created, errors were possible
+ * if the library was modified with ar(1) and the table of
+ * contents was not updated by rerunning ranlib(1). Thus the
+ * link editor, ld, warns when the modification date of a library
+ * is more recent than the creation date of its table of
+ * contents. Unfortunately, this means that you get the warning
+ * even if you only copy the library.
+ * ----
+ *
+ * This means that when we install the static archive, we need to
+ * rerun ranlib afterwards.
+ */
+ char const *lib_args[3], *static_lib_name;
+
+ {
+ char *tmp;
+ size_t len1, len2;
+
+ len1 = strlen(cmd->arglist->vals[cmd->arglist->num - 1]);
+
+ static_lib_name = file_name(cmd->static_name.install);
+ len2 = strlen(static_lib_name);
+
+ tmp = lt_malloc(len1 + len2 + 2);
+
+ snprintf(tmp, len1 + len2 + 2, "%s/%s",
+ cmd->arglist->vals[cmd->arglist->num - 1],
+ static_lib_name);
+
+ lib_args[0] = RANLIB;
+ lib_args[1] = tmp;
+ lib_args[2] = NULL;
+
+ external_spawn(cmd, RANLIB, lib_args);
+
+ free(tmp);
+ }
+#endif
+ clear_count_chars(cctemp);
+ }
+ if (cmd->shared_name.install) {
+ append_count_chars(cctemp, cmd->arglist);
+ insert_count_chars(cctemp, cmd->shared_name.install,
+ cctemp->num - 1);
+ rv = run_command(cmd, cctemp);
+ if (rv) goto finish;
+ clear_count_chars(cctemp);
+ }
+ if (cmd->module_name.install) {
+ append_count_chars(cctemp, cmd->arglist);
+ insert_count_chars(cctemp, cmd->module_name.install,
+ cctemp->num - 1);
+ rv = run_command(cmd, cctemp);
+ if (rv) goto finish;
+ clear_count_chars(cctemp);
+ }
+ break;
+ case MODE_LINK:
+ if (cmd->output == OUT_STATIC_LIB_ONLY ||
+ cmd->output == OUT_LIB) {
+#ifdef RANLIB
+ char const *lib_args[3];
+#endif
+ /* Removes compiler! */
+ cmd->program = LIBRARIAN;
+ push_count_chars(cmd->program_opts, LIBRARIAN_OPTS);
+ push_count_chars(cmd->program_opts, cmd->static_name.normal);
+
+ rv = run_command(cmd, cmd->obj_files);
+ if (rv) goto finish;
+
+#ifdef RANLIB
+ lib_args[0] = RANLIB;
+ lib_args[1] = cmd->static_name.normal;
+ lib_args[2] = NULL;
+ external_spawn(cmd, RANLIB, lib_args);
+#endif
+ }
+
+ if (cmd->output == OUT_DYNAMIC_LIB_ONLY ||
+ cmd->output == OUT_MODULE ||
+ cmd->output == OUT_LIB) {
+ cmd->program = NULL;
+ clear_count_chars(cmd->program_opts);
+
+ append_count_chars(cmd->program_opts, cmd->arglist);
+ if (cmd->output == OUT_MODULE) {
+#ifdef MODULE_OPTS
+ push_count_chars(cmd->program_opts, MODULE_OPTS);
+#endif
+ } else {
+#ifdef SHARED_OPTS
+ push_count_chars(cmd->program_opts, SHARED_OPTS);
+#endif
+#ifdef dynamic_link_version_func
+ push_count_chars(cmd->program_opts,
+ dynamic_link_version_func(cmd->version_info));
+#endif
+ }
+ add_dynamic_link_opts(cmd, cmd->program_opts);
+
+ rv = run_command(cmd, cmd->shared_opts.normal);
+ if (rv) goto finish;
+ }
+ if (cmd->output == OUT_PROGRAM) {
+ rv = run_command(cmd, cmd->arglist);
+ if (rv) goto finish;
+ }
+ break;
+ case MODE_EXECUTE:
+ {
+ char *l, libpath[PATH_MAX];
+
+ if (!cmd->arglist->num) {
+ ERROR("No command to execute.\n");
+ rv = 1;
+
+ goto finish;
+ }
+
+ if (strlen(cmd->arglist->vals[0]) >= PATH_MAX) {
+ ERROR("Libpath too long no buffer space\n");
+ rv = 1;
+
+ goto finish;
+ }
+
+ strcpy(libpath, cmd->arglist->vals[0]);
+ add_dotlibs(libpath);
+ l = strrchr(libpath, '/');
+ if (!l) l = strrchr(libpath, '\\');
+ if (l) {
+ *l = '\0';
+ l = libpath;
+ } else {
+ l = ".libs/";
+ }
+
+ l = "./build/lib/.libs";
+ setenv(LD_LIBRARY_PATH_LOCAL, l, 1);
+#ifdef __APPLE__
+ setenv("DYLD_FALLBACK_LIBRARY_PATH", l, 1);
+#endif
+
+ if (!getenv("FR_LIBRARY_PATH")) {
+ setenv("FR_LIBRARY_PATH", "./build/lib/local/.libs", 1);
+ }
+
+ rv = run_command(cmd, cmd->arglist);
+ if (rv) goto finish;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ finish:
+
+ free(cctemp);
+ return rv;
+}
+
+static void cleanup_tmp_dir(char const *dirname)
+{
+ DIR *dir;
+ struct dirent *entry;
+ char fullname[1024];
+
+ dir = opendir(dirname);
+ if (!dir) {
+ return;
+ }
+
+ if ((strlen(dirname) + 1 + sizeof(entry->d_name)) >= sizeof(fullname)) {
+ ERROR("Dirname too long, out of buffer space\n");
+
+ (void) closedir(dir);
+ return;
+ }
+
+ while ((entry = readdir(dir)) != NULL) {
+ if (entry->d_name[0] != '.') {
+ strcpy(fullname, dirname);
+ strcat(fullname, "/");
+ strcat(fullname, entry->d_name);
+ (void) remove(fullname);
+ }
+ }
+
+ rmdir(dirname);
+
+ (void) closedir(dir);
+}
+
+static void cleanup_tmp_dirs(command_t *cmd)
+{
+ int d;
+
+ for (d = 0; d < cmd->tmp_dirs->num; d++) {
+ cleanup_tmp_dir(cmd->tmp_dirs->vals[d]);
+ }
+}
+
+static int ensure_fake_uptodate(command_t *cmd)
+{
+ /* FIXME: could do the stat/touch here, but nah... */
+ char const *touch_args[3];
+
+ if (cmd->mode == MODE_INSTALL) {
+ return 0;
+ }
+ if (!cmd->fake_output_name) {
+ return 0;
+ }
+
+ touch_args[0] = "touch";
+ touch_args[1] = cmd->fake_output_name;
+ touch_args[2] = NULL;
+ return external_spawn(cmd, "touch", touch_args);
+}
+
+/* Store the install path in the *.la file */
+static int add_for_runtime(command_t *cmd)
+{
+ if (cmd->mode == MODE_INSTALL) {
+ return 0;
+ }
+ if (cmd->output == OUT_DYNAMIC_LIB_ONLY ||
+ cmd->output == OUT_LIB) {
+ FILE *f=fopen(cmd->fake_output_name,"w");
+ if (f == NULL) {
+ return -1;
+ }
+ fprintf(f,"%s\n", cmd->install_path);
+ fclose(f);
+ return(0);
+ } else {
+ return(ensure_fake_uptodate(cmd));
+ }
+}
+
+static void parse_args(int argc, char *argv[], command_t *cmd)
+{
+ int a;
+ char const *arg, *base;
+ int arg_used;
+
+ /*
+ * We now take a major step past libtool.
+ *
+ * IF there's no "--mode=...", AND we recognise
+ * the binary as a "special" name, THEN replace it
+ * with the correct one, and set the correct mode.
+ *
+ * For example if were called 'CC' then we know we should
+ * probably be compiling stuff.
+ */
+ base = file_name(argv[0]);
+ arg = automode(base, cmd);
+ if (arg != base) {
+ push_count_chars(cmd->arglist, arg);
+
+ assert(cmd->mode != MODE_UNKNOWN);
+ }
+
+ /*
+ * We first pass over the command-line arguments looking for
+ * "--mode", etc. If so, then use the libtool compatibility
+ * method for building the software. Otherwise, auto-detect it
+ * via "-o" and the extensions.
+ */
+ base = NULL;
+ if (cmd->mode == MODE_UNKNOWN) for (a = 1; a < argc; a++) {
+ arg = argv[a];
+
+ if (strncmp(arg, "--mode=", 7) == 0) {
+ base = NULL;
+ break;
+ }
+
+ /*
+ * Stop if we get another magic method
+ */
+ if ((a == 1) &&
+ ((strncmp(arg, "LINK", 4) == 0) ||
+ (strcmp(arg, "CC") == 0) ||
+ (strcmp(arg, "CXX") == 0))) {
+ base = NULL;
+ break;
+ }
+
+ if (strncmp(arg, "-o", 2) == 0) {
+ base = argv[++a];
+ }
+ }
+
+ /*
+ * There were no magic args or an explicit --mode= but we did
+ * find an output file, so guess what mode were meant to be in
+ * from its extension.
+ */
+ if (base) {
+ arg = strrchr(base, '.');
+ if (!arg) {
+ cmd->mode = MODE_LINK;
+ push_count_chars(cmd->arglist, LINK_C);
+ }
+#ifdef EXE_EXT
+ else if (strcmp(arg, EXE_EXT) == 0) {
+ cmd->mode = MODE_LINK;
+ push_count_chars(cmd->arglist, LINK_C);
+ }
+#endif
+ else if (strcmp(arg + 1, DYNAMIC_LIB_EXT) == 0) {
+ cmd->mode = MODE_LINK;
+ push_count_chars(cmd->arglist, LINK_C);
+ }
+ else if (strcmp(arg + 1, STATIC_LIB_EXT) == 0) {
+ cmd->mode = MODE_LINK;
+ push_count_chars(cmd->arglist, LINK_C);
+ }
+ else if (strcmp(arg + 1, "la") == 0) {
+ cmd->mode = MODE_LINK;
+ push_count_chars(cmd->arglist, LINK_C);
+ }
+ else if ((strcmp(arg + 1, "lo") == 0) ||
+ (strcmp(arg + 1, "o") == 0)) {
+ cmd->mode = MODE_COMPILE;
+ push_count_chars(cmd->arglist, CC);
+ }
+ }
+
+ for (a = 1; a < argc; a++) {
+ arg = argv[a];
+ arg_used = 1;
+
+ if (cmd->mode == MODE_EXECUTE) {
+ push_count_chars(cmd->arglist, arg);
+ continue;
+ }
+
+ if (arg[0] == '-') {
+ /*
+ * Double dashed (long) single dash (short)
+ */
+ arg_used = (arg[1] == '-') ?
+ parse_long_opt(arg + 2, cmd) :
+ parse_short_opt(arg + 1, cmd);
+
+ if (arg_used) continue;
+
+ /*
+ * Ignore all options after the '--execute'
+ */
+ if (cmd->mode == MODE_EXECUTE) continue;
+
+ /*
+ * We haven't done anything with it yet, but
+ * there are still some arg/value pairs.
+ *
+ * Try some of the more complicated short opts...
+ */
+ if (a + 1 < argc) {
+ /*
+ * We found an output file!
+ */
+ if ((arg[1] == 'o') && (arg[2] == '\0')) {
+ arg = argv[++a];
+ arg_used = parse_output_file_name(arg,
+ cmd);
+ /*
+ * -MT literal dependency
+ */
+ } else if (!strcmp(arg + 1, "MT")) {
+ DEBUG("Adding: %s\n", arg);
+
+ push_count_chars(cmd->arglist, arg);
+ arg = argv[++a];
+
+ NOTICE(" %s\n", arg);
+
+ push_count_chars(cmd->arglist, arg);
+ arg_used = 1;
+ /*
+ * Runtime library search path
+ */
+ } else if (!strcmp(arg + 1, "rpath")) {
+ /* Aha, we should try to link both! */
+ cmd->install_path = argv[++a];
+ arg_used = 1;
+
+ } else if (!strcmp(arg + 1, "release")) {
+ /* Store for later deciphering */
+ cmd->version_info = argv[++a];
+ arg_used = 1;
+
+ } else if (!strcmp(arg + 1, "version-info")) {
+ /* Store for later deciphering */
+ cmd->version_info = argv[++a];
+ arg_used = 1;
+
+ } else if (!strcmp(arg + 1,
+ "export-symbols-regex")) {
+ /* Skip the argument. */
+ ++a;
+ arg_used = 1;
+
+ } else if (!strcmp(arg + 1, "undefined")) {
+ cmd->undefined_flag = argv[++a];
+ arg_used = 1;
+ /*
+ * Add dir to runtime library search path.
+ */
+ } else if ((arg[1] == 'R') && !arg[2]) {
+
+ add_runtime_dir_lib(argv[++a], cmd);
+ arg_used = 1;
+ }
+ }
+ /*
+ * Ok.. the argument doesn't begin with a dash
+ * maybe it's an input file.
+ *
+ * Check its extension to see if it's a known input
+ * file and verify it exists.
+ */
+ } else {
+ arg_used = parse_input_file_name(arg, cmd);
+ }
+
+ /*
+ * If we still don't have a run mode, look for a magic
+ * program name CC, LINK, or whatever. Then replace that
+ * with the name of the real program we want to run.
+ */
+ if (!arg_used) {
+ if ((cmd->arglist->num == 0) &&
+ (cmd->mode == MODE_UNKNOWN)) {
+ arg = automode(arg, cmd);
+ }
+
+ DEBUG("Adding: %s\n", arg);
+
+ push_count_chars(cmd->arglist, arg);
+ }
+ }
+
+}
+
+int main(int argc, char *argv[])
+{
+ int rc;
+ command_t cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+
+ cmd.options.pic_mode = PIC_UNKNOWN;
+ cmd.mode = MODE_UNKNOWN;
+ cmd.output = OUT_GENERAL;
+
+ /*
+ * Initialise the various argument lists
+ */
+ cmd.program_opts = alloc_countchars();
+ cmd.arglist = alloc_countchars();
+ cmd.tmp_dirs = alloc_countchars();
+ cmd.obj_files = alloc_countchars();
+ cmd.dep_rpaths = alloc_countchars();
+ cmd.rpaths = alloc_countchars();
+ cmd.static_opts.normal = alloc_countchars();
+ cmd.shared_opts.normal = alloc_countchars();
+ cmd.shared_opts.dependencies = alloc_countchars();
+
+ /*
+ * Fill up the various argument lists
+ */
+ parse_args(argc, argv, &cmd);
+ post_parse_fixup(&cmd);
+
+ /*
+ * We couldn't figure out which mode to operate in
+ */
+ if (cmd.mode == MODE_UNKNOWN) {
+ usage(1);
+ }
+
+ rc = run_mode(&cmd);
+ if (!rc) {
+ add_for_runtime(&cmd);
+ }
+
+ cleanup_tmp_dirs(&cmd);
+
+ return rc;
+}
diff --git a/scripts/ldap/radiusd2ldif.pl b/scripts/ldap/radiusd2ldif.pl
new file mode 100755
index 0000000..4dbd04f
--- /dev/null
+++ b/scripts/ldap/radiusd2ldif.pl
@@ -0,0 +1,307 @@
+#!/usr/bin/perl
+
+# radius2ldif.pl
+#
+# To test this program, do the following
+#Take a radius users' file, for example with:
+#
+#myuser Password = "apassword"
+# User-Service = Framed-User,
+# Framed-Protocol = PPP,
+# Framed-Address = 255.255.255.255,
+# Framed-Netmask = 255.255.255.255,
+# Ascend-Metric = 2,
+# Framed-Routing = None,
+# Framed-Compression = 0,
+# Ascend-Idle-Limit = 0,
+# Ascend-Maximum-Time = 36000
+#
+#and do:
+#
+#cat users | ./radius2ldif
+#
+#Output is:
+#dn: cn=myuser, ou=Hardware, ou=EDUCAMADRID, ou=People, o=icm.es
+#objectclass: top
+#objectclass: person
+#objectclass: radiusprofile
+#cn: myuser
+#sn: myuser
+#userpassword: apassword
+#radiusServiceType: Framed-User
+#radiusFramedProtocol: PPP
+#radiusFramedIPAddress: 255.255.255.255
+#radiusFramedIPNetmask: 255.255.255.255
+#radiusFramedRouting: None
+#radiusFramedCompression: 0
+#
+#dn: ou=RadiusUser, ou=Groups, o=icm.es
+#description: RadiusUser
+#objectclass: top
+#objectclass: groupOfUniqueNames
+#cn: RadiusUser
+#uniquemember: dn: cn=myuser, ou=Hardware, ou=EDUCAMADRID, ou=People, o=icm.es
+#
+# (c) 2000 Javier Fern'andez-Sanguino Pen~a <jfs@computer.org>
+# -------------------------------------------------------------------------
+# 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
+# -----------------------------------------------------------------------
+
+
+# TODO:
+# currently does not encrypt passwords (takes them from outside file)
+
+# Command line options
+# -d : debugging output
+# -p : give only password
+# -m : set entry to modify ldap attributes
+# -f : read encrypted passwords from file
+use Getopt::Std;
+getopts('dpmf:');
+$debug = $opt_d;
+
+%passwords;
+# This might or might not be necessary depending if your LDAP server
+# when importing from ldif introduces crypted passwords in the LDAP db
+# (not necessary for Netscape's Directory Server)
+read_passwds ($opt_f) if $opt_f;
+
+# USER CONFIGURATION
+# ------------------
+$usermatch = ".*"; # only add users matching this
+# WARNING: in order to add *all* users set this to ".*" NOT ""
+
+# LDAP configuration
+$domain = "o=icm.es";
+$basedn = ", ou=Hardware, ou=EDUCAMADRID, ou=People, $domain";
+$predn = "dn: cn=";
+$uniquemembers = 1;
+$groupname = "RadiusUser"; # group to add in the LDAP, if null will not add
+$group = "\n\ndn: ou=$groupname, ou=Groups, $domain";
+# Only useful for adding the group (not yet implemented)
+$addgroup = $group."\ndescription: $groupname\nobjectclass: top";
+if ( $uniquemembers ) {
+$addgroup = $addgroup."\nobjectclass: groupOfUniqueNames";
+} else {
+$addgroup = $addgroup."\nobjectclass: groupOfNames";
+}
+$addgroup = $addgroup."\ncn: $groupname";
+# The following group must be created first
+# (ldif entry), the script will *not* create it
+#cn=$group,ou=Groups,o=icm.es
+#description=whatever
+#objectclass=top
+#objectclass=groupOfUniqueNames
+# (or objectclass=groupOfNames)
+#cn=$group
+# Required: person (for userpasswords) and radiusprofile (<draft-aboba-radius-02.txt> 5 February 1998)
+@objectClass = ( "top", "person" , "radiusprofile" );
+
+
+# Mapping of entries (use lower case so no check needs to be make)
+# From freeradius: rlm_ldap.c
+# { "radiusServiceType", "Service-Type" },
+# { "radiusFramedProtocol", "Framed-Protocol" },
+# { "radiusFramedIPAddress", "Framed-IP-Address" },
+# { "radiusFramedIPNetmask", "Framed-IP-Netmask" },
+# { "radiusFramedRoute", "Framed-Route" },
+# { "radiusFramedRouting", "Framed-Routing" },
+# { "radiusFilterId", "Filter-Id" },
+# { "radiusFramedMTU", "Framed-MTU" },
+# { "radiusFramedCompression", "Framed-Compression" },
+# { "radiusLoginIPHost", "Login-IP-Host" },
+# { "radiusLoginService", "Login-Service" },
+# { "radiusLoginTCPPort", "Login-TCP-Port" },
+# { "radiusCallbackNumber", "Callback-Number" },
+# { "radiusCallbackId", "Callback-Id" },
+# { "radiusFramedRoute", "Framed-Route" },
+# { "radiusFramedIPXNetwork", "Framed-IPX-Network" },
+# { "radiusClass", "Class" },
+# { "radiusSessionTimeout", "Session-Timeout" },
+# { "radiusIdleTimeout", "Idle-Timeout" },
+# { "radiusTerminationAction", "Termination-Action" },
+# { "radiusCalledStationId", "Called-Station-Id" },
+# { "radiusCallingStationId", "Calling-Station-Id" },
+# { "radiusLoginLATService", "Login-LAT-Service" },
+# { "radiusLoginLATNode", "Login-LAT-Node" },
+# { "radiusLoginLATGroup", "Login-LAT-Group" },
+# { "radiusFramedAppleTalkLink", "Framed-AppleTalk-Link" },
+# { "radiusFramedAppleTalkNetwork", "Framed-AppleTalk-Network" },
+# { "radiusFramedAppleTalkZone", "Framed-AppleTalk-Zone" },
+# { "radiusPortLimit", "Port-Limit" },
+# { "radiusLoginLATPort", "Login-LAT-Port" },
+# You can change to the mappings below like this
+# cat radius2ldif.pl | grep ^# | \
+# perl -ne 'if ( /\{ \"(.*?)\", \"(.*?)\" \}/ ) \
+# { $attr=lc $2; print "\$mapping{\"$attr\"} = \"$1\";\n" ; } '
+
+
+# Warning: sometimes password must be encrypted before sent to the LDAP
+# Which Perl libraries are available? Only way I find is through
+# Netscape's NDS getpwenc.
+# However NDS does the cyphering even if sending plain passwords
+# (do all LDAP's do this?)
+# TODO: test with OpenLDAP
+$mapping{'password'} = "userpassword";
+$mapping{'service-type'} = "radiusServiceType";
+$mapping{'framed-protocol'} = "radiusFramedProtocol";
+$mapping{'framed-ip-address'} = "radiusFramedIPAddress";
+$mapping{'framed-ip-netmask'} = "radiusFramedIPNetmask";
+$mapping{'framed-route'} = "radiusFramedRoute";
+$mapping{'framed-routing'} = "radiusFramedRouting";
+$mapping{'filter-id'} = "radiusFilterId";
+$mapping{'framed-mtu'} = "radiusFramedMTU";
+$mapping{'framed-compression'} = "radiusFramedCompression";
+$mapping{'login-ip-host'} = "radiusLoginIPHost";
+$mapping{'login-service'} = "radiusLoginService";
+$mapping{'login-tcp-port'} = "radiusLoginTCPPort";
+$mapping{'callback-number'} = "radiusCallbackNumber";
+$mapping{'callback-id'} = "radiusCallbackId";
+$mapping{'framed-ipx-network'} = "radiusFramedIPXNetwork";
+$mapping{'class'} = "radiusClass";
+$mapping{'session-timeout'} = "radiusSessionTimeout";
+$mapping{'idle-timeout'} = "radiusIdleTimeout";
+$mapping{'termination-action'} = "radiusTerminationAction";
+$mapping{'called-station-id'} = "radiusCalledStationId";
+$mapping{'calling-station-id'} = "radiusCallingStationId";
+$mapping{'login-lat-service'} = "radiusLoginLATService";
+$mapping{'login-lat-node'} = "radiusLoginLATNode";
+$mapping{'login-lat-group'} = "radiusLoginLATGroup";
+$mapping{'framed-appletalk-link'} = "radiusFramedAppleTalkLink";
+$mapping{'framed-appletalk-network'} = "radiusFramedAppleTalkNetwork";
+$mapping{'framed-appletalk-zone'} = "radiusFramedAppleTalkZone";
+$mapping{'port-limit'} = "radiusPortLimit";
+$mapping{'login-lat-port'} = "radiusLoginLATPort";
+
+# Must be added to rlm_ldap.c (change this to suite your needs)
+# (really not all since they are in the /etc/raddb/dictionary.compat)
+$mapping{'framed-address'} = "radiusFramedIPAddress";
+$mapping{'framed-ip-route'} = "radiusFramedRoute";
+$mapping{'framed-netmask'} = "radiusFramedIPNetmask";
+$mapping{'user-service'} = "radiusServiceType";
+# Since this might not change they could be placed in the DEFAULT
+# user insted of the LDAP
+#$mapping{'ascend-metric'} = "radiusAscendMetric";
+#$mapping{'ascend-idle-limit'} = "radiusAscendIdleLimit";
+# But this really ought to be there :
+$mapping{'callback_number'} = "radiusCallbackNumber";
+
+
+# Footer of ldif entries
+$footer = "\n\n";
+$startentry = 0;
+
+while ($line=<STDIN>) {
+ chomp $line;
+ if ( $line =~ /^[\s\t]*$/ && $startentry) {
+ $startentry = 0 ;
+ print $footer;
+ }
+ # Start line is hardcoded must be uid followed by password
+ # this could be changed to use any other parameter however
+ if ( $line =~ /^(\w+)\s*\t*(?:User-)?Password=(\w+)/ ) {
+ $uid = $1;
+ $password= $2;
+ $password = $passwords{$password} if $opt_f;
+ if ( $uid =~ /$usermatch/ ) {
+ $startentry = 1;
+ $dn=$predn.$uid.$basedn; # Start of LDIF entry
+ $header = "$dn\n";
+ push @userlist, $dn;
+ if ( $opt_m ) {
+ $header= $header."changetype: modify\n";
+ } else {
+ for (my $i=0; $i < $#objectClass+1; $i++) {
+ $header = $header."objectclass: ".$objectClass[$i]."\n";
+ }
+ }
+ print $header if !$opt_m;
+ print_entry ("cn",$uid);
+ print_entry ("sn",$uid);
+ # The following might be necessary (depending on the groups)
+ # of the object
+ #print "replace: uid\n" if $opt_m;
+ #print "uid: $uid\n";
+ #print "replace: givenname\n" if $opt_m;
+ #print "givenname: $uid\n";
+ print_entry ($mapping{'password'},$password);
+ }
+ }
+ # Do this only for entries detected
+ if ( $startentry && ! $opt_p ) {
+ #Take anything that starts with a tab or spaces
+ # and ends (sometimes) with a comma
+ if ( $line =~ /^[\t\s]+(.*?)\s+=\s+(.*?),*$/ ) {
+ $parameter = lc $1;
+ $value = $2;
+ print "DEBUG: Got :$parameter=$value\n" if $debug;
+ if ( defined $mapping{$parameter} && $mapping{$parameter} ne "" ) {
+ print_entry ($mapping{$parameter},$value);
+ } # of if defined mapping
+ else {
+ print "DEBUG: Parameter $parameter not known\n" if $debug;
+ }
+ } # of if line
+ } # of if startentry
+
+} # of while
+
+
+# The list of users in the group
+if ( $group ) {
+ if ( ! $opt_m ) {
+ print "$addgroup\n";
+ }
+ else {
+ print "\n\n$group\n";
+ print "changetype: modify\n" ;
+ }
+ foreach $user ( @userlist ) {
+ $member = "member: ";
+ $member = "uniquemember: " if $uniquemembers;
+ print "$member$user\n";
+ }
+}
+
+exit 0;
+
+sub read_passwds {
+# Reads passwords from a file in order to get the crypted
+# version, the file must be of the following format:
+# password cryptedversion
+ my ($file)=@_;
+ open (PASSWD,"< $file") or die ("Could not open $file: $!\n");
+
+ while ($line = <PASSWD>) {
+ chomp $line;
+ if ( $line =~ /^(\w+)[\t\s]+(.*?)$/ ) {
+ $passwords{$1}=$2;
+ }
+ }
+ close PASSWD;
+
+ return 0;
+}
+
+sub print_entry {
+# Prints and ldif entry given name and value
+# if this is a modification it will print header and footer
+ my ($name, $value) = @_;
+ print $header."replace: $name\n" if $opt_m;
+ print $name.": ".$value."\n";
+ print $footer if $opt_m;
+ return 0;
+}
+
diff --git a/scripts/ldap/schema_to_samba.py b/scripts/ldap/schema_to_samba.py
new file mode 100644
index 0000000..637ae52
--- /dev/null
+++ b/scripts/ldap/schema_to_samba.py
@@ -0,0 +1,132 @@
+# This is a quick hack to convert an openldap schema file to a form which
+# can be loaded into Samba4/AD.
+#
+# Inspired by:
+# http://david-latham.blogspot.co.uk/2012/12/extending-ad-schema-on-samba4-part-2.html
+# https://github.com/linuxplayground/yubikey-ldap/tree/master/samba4-schema
+#
+# (c) 2017 Brian Candler <b.candler@pobox.com>
+# -------------------------------------------------------------------------
+# 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
+# -----------------------------------------------------------------------
+
+from __future__ import print_function
+import sys
+import re
+from collections import OrderedDict
+
+BASEDN = 'dc=samba4,dc=internal'
+
+# RFC 2252 to https://technet.microsoft.com/en-us/library/cc961740.aspx
+SYNTAX_MAP = {
+ '1.3.6.1.4.1.1466.115.121.1.7': ('2.5.5.8', 1), # boolean
+ '1.3.6.1.4.1.1466.115.121.1.12': ('2.5.5.1', 127), # DN
+ '1.3.6.1.4.1.1466.115.121.1.15': ('2.5.5.3', 27), # DirectoryString
+ '1.3.6.1.4.1.1466.115.121.1.26': ('2.5.5.5', 22), # IA5String
+ '1.3.6.1.4.1.1466.115.121.1.27': ('2.5.5.9', 10), # Integer
+}
+obj = None
+for line in sys.stdin:
+ if re.match(r'^\s*(#|$)', line): continue
+ m = re.match(r'^attributetype\s+\(\s+(\S+)', line)
+ if m:
+ obj = OrderedDict([
+ ('objectClass', ['top', 'attributeSchema']),
+ ('attributeID', m.group(1)),
+ ('isSingleValued', 'FALSE'),
+ ])
+ continue
+ m = re.match(r'^objectclass\s+\(\s+(\S+)', line)
+ if m:
+ obj = OrderedDict([
+ ('objectClass', ['top', 'classSchema']),
+ ('governsID', m.group(1)),
+ ])
+ continue
+ m = re.match(r'^\s*NAME\s+[\'"](.+)[\'"]', line)
+ if m:
+ obj.update([
+ ('cn', m.group(1)),
+ ('name', m.group(1)),
+ ('lDAPDisplayName', m.group(1)),
+ ])
+ continue
+ m = re.match(r'^\s*DESC\s+[\'"](.+)[\'"]', line)
+ if m:
+ obj.update([
+ ('description', m.group(1)),
+ ])
+ continue
+ m = re.match(r'^\s*(EQUALITY|SUBSTR)\s+(\S+)', line)
+ if m:
+ # Not supported by AD?
+ # https://technet.microsoft.com/en-us/library/cc961575.aspx
+ continue
+ m = re.match(r'^\s*SYNTAX\s+(\S+)', line)
+ if m:
+ obj.update([
+ ('attributeSyntax', SYNTAX_MAP[m.group(1)][0]),
+ ('oMSyntax', SYNTAX_MAP[m.group(1)][1]),
+ ])
+ continue
+ if re.match(r'^\s*SINGLE-VALUE', line):
+ obj.update([
+ ('isSingleValued', 'TRUE'),
+ ])
+ continue
+ if re.match(r'^\s*AUXILIARY', line):
+ # https://msdn.microsoft.com/en-us/library/ms679014(v=vs.85).aspx
+ # https://technet.microsoft.com/en-us/library/2008.05.schema.aspx
+ obj.update([
+ ('objectClassCategory', '3'),
+ ])
+ continue
+ if re.match(r'^\s*STRUCTURAL', line):
+ obj.update([
+ ('objectClassCategory', '1'),
+ ])
+ continue
+ m = re.match(r'^\s*SUP\s+(\S+)', line)
+ if m:
+ obj.update([
+ ('subClassOf', m.group(1)),
+ ])
+ continue
+ m = re.match(r'^\s*(MAY|MUST)\s+\((.*)\)\s*$', line)
+ if m:
+ attrs = m.group(2).split('$')
+ obj.update([
+ ('%sContain' % m.group(1).lower(), [v.strip() for v in attrs]),
+ ])
+ continue
+ m = re.match(r'^\s*(MAY|MUST)\s+(\w+)\s*$', line)
+ if m:
+ obj.update([
+ ('%sContain' % m.group(1).lower(), m.group(2)),
+ ])
+ continue
+ if re.match(r'^\s*\)', line) and obj:
+ print("dn: CN=%s,CN=Schema,CN=Configuration,%s" % (obj['cn'], BASEDN))
+ print("changetype: add")
+ for k in obj:
+ if type(obj[k]) == list:
+ for v in obj[k]:
+ print("%s: %s" % (k, v))
+ else:
+ print("%s: %s" % (k, obj[k]))
+ print()
+ obj = None
+ continue
+ print("??? %s" % line, file=sys.stderr)
diff --git a/scripts/libtool.mk b/scripts/libtool.mk
new file mode 100644
index 0000000..381127e
--- /dev/null
+++ b/scripts/libtool.mk
@@ -0,0 +1,243 @@
+# Copyright 2008, 2009, 2010 Dan Moulding, Alan T. DeKok
+#
+# 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 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+#
+# You can watch what it's doing by:
+#
+# $ VERBOSE=1 make ... args ...
+#
+ifeq "${VERBOSE}" ""
+ Q=@
+else
+ Q=
+endif
+
+# Add these rules only when LIBTOOL is being used.
+ifneq "${LIBTOOL}" ""
+
+ # clang on OSX sometimes doesn't know where things are. <sigh>
+ ifeq "$(findstring darwin,$(HOSTINFO))" "darwin"
+ JLIBTOOL_DEFS += -L/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib
+ endif
+
+# JLIBTOOL - check if we're using the local (fast) jlibtool, rather
+# than the GNU (slow) libtool shell script. If so, add rules
+# to build it.
+
+ifeq "${LIBTOOL}" "JLIBTOOL"
+ JLIBTOOL := ${BUILD_DIR}/make/jlibtool
+
+ # Add a rule to build jlibtool BEFORE any other targets. This
+ # means that we can use it to build the later targets.
+ all install: ${JLIBTOOL}
+
+ # Note that we need to use a compilation rule that does NOT
+ # include referencing ${LIBTOOL}, as we don't have a jlibtool
+ # binary!
+ ${JLIBTOOL}: ${top_makedir}/jlibtool.c
+ $(Q)mkdir -p $(dir $@)
+ $(Q)echo CC jlibtool.c
+ $(Q)${CC} $< -o $@ ${JLIBTOOL_DEFS}
+
+ clean: jlibtool_clean
+
+ .PHONY: jlibtool_clean
+ jlibtool_clean:
+ $(Q)rm -f ${JLIBTOOL}
+
+ # Tell GNU Make to use this value, rather than anything specified
+ # on the command line.
+ override LIBTOOL := ${JLIBTOOL}
+endif # else we're not using jlibtool
+
+# When using libtool, it produces a '.libs' directory. Ensure that it
+# is removed on "make clean", too.
+#
+clean: .libs_clean
+
+.PHONY: .libs_clean
+.libs_clean:
+ $(Q)rm -rf ${BUILD_DIR}/.libs/
+
+# Re-define compilers and linkers
+#
+OBJ_EXT = lo
+COMPILE.c = ${LIBTOOL} --silent --mode=compile ${CC}
+COMPILE.cxx = ${LIBTOOL} --mode=compile ${CXX}
+LINK.c = ${LIBTOOL} --silent --mode=link ${CC}
+LINK.cxx = ${LIBTOOL} --mode=link ${CXX}
+PROGRAM_INSTALL = ${LIBTOOL} --silent --mode=install ${INSTALL}
+
+
+# LIBTOOL_ENDINGS - Given a library ending in ".a" or ".so", replace that
+# extension with ".la".
+#
+define LIBTOOL_ENDINGS
+$(patsubst %.a,%.la,$(patsubst %.so,%.la,${1}))
+endef
+
+# ADD_TARGET_RULE.la - Build a ".la" target.
+#
+# USE WITH EVAL
+#
+define ADD_TARGET_RULE.la
+ # So "make ${1}" works
+ .PHONY: ${1}
+ ${1}: $${${1}_BUILD}/${1}
+
+ # Create libtool library ${1}
+ $${${1}_BUILD}/${1}: $${${1}_OBJS} $${${1}_PRLIBS}
+ $(Q)$(strip mkdir -p $(dir $${${1}_BUILD}/${1}))
+ @$(ECHO) LINK $${${1}_BUILD}/${1}
+ $(Q)$${${1}_LINKER} -o $${${1}_BUILD}/${1} $${RPATH_FLAGS} $${LDFLAGS} \
+ $${${1}_LDFLAGS} $${${1}_OBJS} $${LDLIBS} $${${1}_LDLIBS} \
+ $${${1}_PRLIBS}
+ $(Q)$${${1}_POSTMAKE}
+
+ ifneq "${ANALYZE.c}" ""
+ scan.${1}: $${${1}_PLISTS}
+ endif
+endef
+
+# ADD_LOCAL_RULE.exe - Parametric "function" that adds a rule to build
+# a local version of the target.
+#
+# USE WITH EVAL
+#
+define ADD_LOCAL_RULE.exe
+ ${1}: $${${1}_BUILD}/$${LOCAL}${1}
+
+ # used to fix up RPATH for ${1} on install.
+ $${${1}_BUILD}/$${${1}_LOCAL}: $${${1}_OBJS} $${${1}_PRBIN} $${${1}_LOCAL_PRLIBS}
+ $(Q)$(strip mkdir -p $${${1}_BUILD}/${LOCAL}/)
+ $(Q)$${${1}_LINKER} -o $${${1}_BUILD}/$${LOCAL}${1} $${LOCAL_FLAGS} $${LDFLAGS} \
+ $${${1}_LDFLAGS} $${${1}_OBJS} $${${1}_LOCAL_PRLIBS} \
+ $${LDLIBS} $${${1}_LDLIBS}
+ $(Q)$${${1}_POSTMAKE}
+endef
+
+# ADD_LOCAL_RULE.la - Parametric "function" that adds a rule to build
+# a local version of the target.
+#
+# USE WITH EVAL
+#
+define ADD_LOCAL_RULE.la
+ ${1}: $${${1}_BUILD}/$${LOCAL}${1}
+
+ # used to fix up RPATH for ${1} on install.
+ $${${1}_BUILD}/$${${1}_LOCAL}: $${${1}_OBJS} $${${1}_LOCAL_PRLIBS}
+ $(Q)$(strip mkdir -p $${${1}_BUILD}/${LOCAL}/)
+ $(Q)$${${1}_LINKER} -o $${${1}_BUILD}/$${LOCAL}${1} $${LOCAL_FLAGS} $${LDFLAGS} \
+ $${${1}_LDFLAGS} $${${1}_OBJS} $${LDLIBS} $${${1}_LDLIBS} \
+ $${${1}_LOCAL_PRLIBS}
+ $(Q)$${${1}_POSTMAKE}
+
+endef
+
+# By default, if libdir is defined, we build shared libraries.
+# However, we can disable shared libraries if explicitly told to.
+ifneq "${libdir}" ""
+ ifneq "${bm_shared_libs}" "no"
+ bm_shared_libs := yes
+ endif
+endif
+
+# Default to building static libraries, too.
+ifneq "${bm_static_libs}" "no"
+ bm_static_libs := yes
+endif
+
+# Check if we build shared libraries.
+ifeq "${bm_shared_libs}" "yes"
+ LOCAL := local/
+
+ # RPATH : flags use to build executables that are installed,
+ # with no dependency on the source.
+ # RELINL : flags use to build executables that can be run
+ # from the build directory / source tree.
+ RPATH_FLAGS := -rpath ${libdir}
+ LOCAL_FLAGS := -rpath $(subst //,/,$(abspath ${BUILD_DIR})/lib/${LOCAL}/.libs)
+
+ LOCAL_FLAGS_MIN := -rpath ${libdir}
+
+ ifneq "${bm_static_libs}" "yes"
+ RPATH_FLAGS += --shared
+ LOCAL_FLAGS += --shared
+ endif
+else
+ ifneq "${bm_static_libs}" "yes"
+ $(error Building without static libraries requires you to set 'INSTALL' or 'libdir')
+ endif
+
+ RPATH_FLAGS := -static
+endif
+
+# UPDATE_TARGET_ENDINGS - Function to turn target into a libtool target
+# e.g. "libfoo.a" -> libfoo.la"
+#
+# If the target is an executable, then its extension doesn't change
+# when we use libtool, and we don't do any re-writing.
+#
+# USE WITH EVAL
+#
+define ADD_LIBTOOL_SUFFIX
+ ifneq "$$(call LIBTOOL_ENDINGS,$${TGT})" "$${TGT}"
+ TGT_NOLIBTOOL := $${TGT}
+ TGT := $$(call LIBTOOL_ENDINGS,$${TGT})
+ $${TGT}_NOLIBTOOL := $${TGT_NOLIBTOOL}
+ endif
+
+ ifneq "$${LOCAL_FLAGS}" ""
+ $${TGT}_LOCAL := ${LOCAL}$${TGT}
+ endif
+
+ # re-write all of the dependencies to have the libtool endings.
+ TGT_PREREQS := $$(call LIBTOOL_ENDINGS,$${TGT_PREREQS})
+endef
+
+# ADD_LIBTOOL_TARGET - Function to ensure that the object files depend
+# on our jlibtool target. This ensures that jlibtool is built before
+# it's used to build the object files.
+#
+# USE WITH EVAL
+#
+define ADD_LIBTOOL_TARGET
+ ifneq "${JLIBTOOL}" ""
+ $${$${TGT}_OBJS}: $${JLIBTOOL}
+ endif
+
+ ifneq "$${$${TGT}_NOLIBTOOL}" ""
+ $$(notdir $${$${TGT}_NOLIBTOOL}): $${TGT}
+ endif
+
+ # If we need to relink, add the relink targets now.
+ ifneq "$${$${TGT}_LOCAL}" ""
+ # add rules to relink the target
+
+ $${TGT}_LOCAL_PRLIBS := $$(subst $${BUILD_DIR}/lib/,$${BUILD_DIR}/lib/${LOCAL},$${$${TGT}_PRLIBS})
+
+ $$(eval $$(call ADD_LOCAL_RULE$${$${TGT}_SUFFIX},$${TGT}))
+
+ $$(eval $$(call ADD_CLEAN_RULE,$${$${TGT}_LOCAL}_libtool))
+
+ ifneq "$${$${TGT}_NOLIBTOOL}" ""
+ $$(eval $$(call ADD_CLEAN_RULE,$${$${TGT}_NOLIBTOOL}_libtool))
+ endif
+ endif
+
+endef
+
+
+endif
diff --git a/scripts/logrotate/freeradius b/scripts/logrotate/freeradius
new file mode 100644
index 0000000..eecf631
--- /dev/null
+++ b/scripts/logrotate/freeradius
@@ -0,0 +1,59 @@
+#
+# Sample logrotate file for FreeRADIUS
+#
+# You can use this to rotate the /var/log/radius/* files, simply copy it to /etc/logrotate.d/radiusd
+#
+
+#
+# The main server log
+#
+/var/log/radius/radius.log {
+ # common options
+ daily
+ rotate 14
+ missingok
+ compress
+ delaycompress
+ notifempty
+
+ copytruncate
+ su radiusd radiusd
+}
+
+# (in order)
+# Session monitoring utilities
+# SQL log files
+/var/log/freeradius/checkrad.log /var/log/freeradius/radwatch.log
+/var/log/freeradius/sqllog.sql
+{
+ # common options
+ daily
+ rotate 14
+ missingok
+ compress
+ delaycompress
+ notifempty
+
+ nocreate
+ su radiusd radiusd
+}
+
+# There are different detail-rotating strategies you can use. One is
+# to write to a single detail file per IP and use the rotate config
+# below. Another is to write to a daily detail file per IP with:
+# detailfile = ${radacctdir}/%{Client-IP-Address}/%Y%m%d-detail
+# (or similar) in radiusd.conf, without rotation. If you go with the
+# second technique, you will need another cron job that removes old
+# detail files. You do not need to comment out the below for method #2.
+/var/log/radius/radacct/*/detail {
+ # common options
+ daily
+ rotate 14
+ missingok
+ compress
+ delaycompress
+ notifempty
+
+ nocreate
+ su radiusd radiusd
+}
diff --git a/scripts/min-includes.pl b/scripts/min-includes.pl
new file mode 100755
index 0000000..37044ed
--- /dev/null
+++ b/scripts/min-includes.pl
@@ -0,0 +1,238 @@
+#!/usr/bin/env perl
+######################################################################
+#
+# This script find duplicates of #include files, ignoring #ifdef's, etc.
+# from C source files, and (at your command) removes the duplicates.
+#
+# It is meant to be run ONLY by FreeRADUS developers, and has nothing
+# whatsoever to do with RADIUS, FreeRADIUS, or configuring a RADIUS server.
+#
+######################################################################
+#
+# Run as: ./min-includes.pl `find . -name "*.c" -print`
+# prints out duplicate includes from files.
+#
+# ./min-includes.pl +n `find . -name "*.c" -print`
+# removes the duplicate includes from each file.
+# Remember to check that it still builds!
+#
+# It has to be run from the TOP of the FreeRADIUS build tree,
+# i.e. where the top-level "configure" script is located.
+#
+######################################################################
+#
+# FIXME: We don't handle include files taken from the current
+# directory...
+#
+# FIXME: we should take -I <path> from the command line.
+#
+######################################################################
+#
+# Copyright (C) 2006 Alan DeKok <aland@freeradius.org>
+#
+# $Id$
+#
+######################################################################
+
+my %processed;
+
+$any_dups = 0;
+$debug = 0;
+
+#
+# Find the #include's for one file.
+#
+sub process($) {
+ my $file = shift;
+
+ return if ($processed{$file});
+
+ $processed{$file}++;
+
+ open FILE, "<$file" or die "Failed to open $file: $!\n";
+
+ $line = 0;
+ while (<FILE>) {
+ $line++;
+
+ next if (!/^\s*\#\s*include\s+/);
+
+ if (/^\s*\#\s*include\s+"(.+?)"/) {
+ $refs{$file}{$1} = $line;
+
+ # FIXME: local header files?
+ # src/foo/bar.c: #include "foo.h"
+ # src/foo/foo.h do stuff..
+
+ $include{$1}++;
+ } elsif (/^\s*\#\s*include\s+<(.+?)>/) {
+ $refs{$file}{$1} = $line;
+ $include{$1}++;
+ }
+ }
+
+ close FILE;
+}
+
+#
+# Where include files are located.
+#
+# FIXME:
+#
+@directories = ("src/lib", "src");
+$do_it = 0;
+
+#
+# Horrid.
+#
+if ($ARGV[0] eq "+n") {
+ shift;
+ $do_it = 1;
+}
+
+#
+# Bootstrap the basic C files.
+#
+foreach $file (@ARGV) {
+ process($file);
+}
+
+
+#
+# Process the include files referenced from the C files, to find out
+# what they include Note that we create a temporary array, rather
+# than walking over %include, because the process() function adds
+# entries to the %include hash.
+#
+@work = sort keys %include;
+foreach $inc (@work) {
+
+ foreach $dir (@directories) {
+ $path = $dir . "/" . $inc;
+
+ # normalize path
+ $path =~ s:/.*?/\.\.::;
+ $path =~ s:/.*?/\.\.::;
+
+ next if (! -e $path);
+ process($path);
+ $forward{$inc} = $path;
+ $reverse{$path} = $inc;
+
+ # ignore system include files
+ next if ((scalar keys %{$refs{$path}}) == 0);
+
+ # Remember that X includes Y, and push Y onto the list
+ # of files to scan.
+ foreach $inc2 (sort keys %{$refs{$path}}) {
+ $maps{$inc}{$inc2} = 0;
+ push @work, $inc2;
+ }
+ }
+}
+
+#
+# Process all of the forward refs, so that we have a complete
+# list of who's referencing who.
+#
+# This doesn't find the shortest path from A to B, but it does
+# find one path.
+#
+foreach $inc (sort keys %maps) {
+ foreach $inc2 (sort keys %{$maps{$inc}}) {
+ foreach $inc3 (sort keys %{$maps{$inc2}}) {
+ # map is already there...
+ next if (defined $maps{$inc}{$inc3});
+
+ $maps{$inc}{$inc3} = $maps{$inc2}{$inc3} + 1;
+ }
+ }
+}
+
+#
+# Walk through the files again, looking for includes that are
+# unnecessary. Note that we process header files, too.
+#
+foreach $file (sort keys %refs) {
+
+ # print out some debugging information.
+ if ($debug > 0) {
+ if (defined $reverse{$file}) {
+ print $file, "\t(", $reverse{$file}, ")\n";
+ } else {
+ print $file, "\n";
+ }
+ }
+
+ # walk of the list of include's in this file
+ foreach $ref (sort keys %{$refs{$file}}) {
+
+ # walk over the include files we include, or included by
+ # files that we include.
+ foreach $inc2 (sort keys %{$maps{$ref}}) {
+ #
+ # If we include X, and X includes Y, and we include
+ # Y ourselves *after* X, it's a definite dupe.
+ #
+ # Note that this is a *guaranteed* duplicate.
+ #
+ # Sometimes order matters, so we can't always delete X if
+ # we include Y after X, and Y includes X
+ #
+ if (defined $refs{$file}{$inc2} &&
+ ($refs{$file}{$inc2} > $refs{$file}{$ref})) {
+ $duplicate{$file}{$inc2} = $ref;
+
+ # mark the line to be deleted.
+ $delete_line{$file}{$refs{$file}{$inc2}}++;
+
+ $any_dups++;
+ }
+ }
+ print "\t", $ref, "\n" if ($debug > 0);
+ }
+}
+
+if ($debug > 0) {
+ print "------------------------------------\n";
+}
+
+#
+# Maybe just print out the dups so that a person can validate them.
+#
+if (!$do_it) {
+ foreach $file (sort keys %duplicate) {
+ print $file, "\n";
+
+ foreach $inc (sort keys %{$duplicate{$file}}) {
+ print "\t[", $refs{$file}{$inc}, "] ", $inc, " (", $duplicate{$file}{$inc}, " at ", $refs{$file}{$duplicate{$file}{$inc}}, ")\n";
+ }
+ }
+} else {
+ foreach $file (sort keys %duplicate) {
+ open FILE, "<$file" or die "Failed to open $file: $!\n";
+ open OUTPUT, ">$file.tmp" or die "Failed to create $file.tmp: $!\n";
+
+ $line = 0;
+ while (<FILE>) {
+ $line++;
+
+ # supposed to delete this line, don't print it to the output.
+ next if (defined $delete_line{$file}{$line});
+
+ print OUTPUT;
+ }
+
+ rename "$file.tmp", $file;
+ }
+
+}
+
+# If we succeeded in re-writing the files, it's OK.
+exit 0 if ($do_it);
+
+# If there are no duplicates, then we're OK.
+exit 0 if (!$any_dups);
+
+# Else there are duplicates, complain.
+exit 1
diff --git a/scripts/monit/freeradius.monitrc b/scripts/monit/freeradius.monitrc
new file mode 100644
index 0000000..65f96cf
--- /dev/null
+++ b/scripts/monit/freeradius.monitrc
@@ -0,0 +1,18 @@
+#
+# Script for use with Monit
+#
+# http://mmonit.com/monit/
+#
+
+#
+# Totalmem limit should be lowered to 200.0 if none of the
+# interpreted language modules or rlm_cache are being used.
+#
+check process radiusd with pidfile /var/run/radiusd/radiusd.pid
+ start program = "/etc/init.d/radiusd start"
+ stop program = "/etc/init.d/radiusd stop"
+ if failed host 127.0.0.1 port 1812 type udp protocol radius secret testing123 then alert
+ if failed host 127.0.0.1 port 1813 type udp protocol radius secret testing123 then alert
+ if cpu > 95% for 2 cycles then alert
+ if totalmem > 1024.0 MB for 5 cycles then restart
+ if 5 restarts within 5 cycles then timeout
diff --git a/scripts/munin/freeradius_acct b/scripts/munin/freeradius_acct
new file mode 100755
index 0000000..a61627c
--- /dev/null
+++ b/scripts/munin/freeradius_acct
@@ -0,0 +1,88 @@
+#!/bin/sh
+#
+# Plugin to count the daily amount of freeradius authentication packets.
+#
+# 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) 2008 Alan DeKok <aland@deployingradius.com>
+#
+# Magic markers - optional - used by installation scripts and
+# munin-config:
+#
+#%# family=manual
+#%# capabilities=autoconf
+
+RADMIN=radmin
+SOCKETFILE=/var/run/radiusd/radiusd.sock
+
+if [ "$1" = "autoconf" ]; then
+ #
+ # FIXME: Check if FreeRADIUS is running.
+ #
+ echo yes
+ exit 0
+fi
+
+if [ "$1" = "config" ]; then
+ echo 'graph_title FreeRADIUS Accounting Requests'
+ echo 'graph_args --base 1000 -l 0 '
+ echo 'graph_period second'
+ echo 'graph_vlabel requests / ${graph_period}'
+ echo 'graph_category Other'
+
+ echo 'requests.label Accounting-Requests'
+ echo 'requests.info total received request packets'
+ echo 'requests.type DERIVE'
+ echo 'requests.min 0'
+
+ echo 'responses.label Accounting-Responses'
+ echo 'responses.info total sent response packets'
+ echo 'responses.type DERIVE'
+ echo 'responses.min 0'
+
+ echo 'dup.label Duplicate requests'
+ echo 'dup.info total duplicate request packets'
+ echo 'dup.type DERIVE'
+ echo 'dup.min 0'
+
+ echo 'invalid.label Invalid requests'
+ echo 'invalid.info total invalid request packets'
+ echo 'invalid.type DERIVE'
+ echo 'invalid.min 0'
+
+ echo 'malformed.label Malformed requests'
+ echo 'malformed.info total malformed request packets'
+ echo 'malformed.type DERIVE'
+ echo 'malformed.min 0'
+
+ echo 'bad_signature.label Requests with bad signature'
+ echo 'bad_signature.info total request packets with a bad signature'
+ echo 'bad_signature.type DERIVE'
+ echo 'bad_signature.min 0'
+
+ echo 'dropped.label Dropped requests'
+ echo 'dropped.info total request packets dropped for other reasons'
+ echo 'dropped.type DERIVE'
+ echo 'dropped.min 0'
+
+ echo 'unknown_types.label Unknown type'
+ echo 'unknown_types.info total request packets of unknown type'
+ echo 'unknown_types.type DERIVE'
+ echo 'unknown_types.min 0'
+
+ exit 0
+fi
+
+$RADMIN -f $SOCKETFILE -e "stats client acct" | awk '{print $1".value " $2}'
diff --git a/scripts/munin/freeradius_auth b/scripts/munin/freeradius_auth
new file mode 100755
index 0000000..b602402
--- /dev/null
+++ b/scripts/munin/freeradius_auth
@@ -0,0 +1,103 @@
+#!/bin/sh
+#
+# Plugin to count the daily amount of freeradius authentication packets.
+#
+# 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) 2008 Alan DeKok <aland@deployingradius.com>
+#
+# Magic markers - optional - used by installation scripts and
+# munin-config:
+#
+#%# family=manual
+#%# capabilities=autoconf
+
+RADMIN=radmin
+SOCKETFILE=/var/run/radiusd/radiusd.sock
+
+if [ "$1" = "autoconf" ]; then
+ #
+ # FIXME: Check if FreeRADIUS is running.
+ #
+ echo yes
+ exit 0
+fi
+
+if [ "$1" = "config" ]; then
+ echo 'graph_title FreeRADIUS Authentication Requests'
+ echo 'graph_args --base 1000 -l 0 '
+ echo 'graph_period second'
+ echo 'graph_vlabel requests / ${graph_period}'
+ echo 'graph_category Other'
+
+ echo 'requests.label Access-Requests'
+ echo 'requests.info total received request packets'
+ echo 'requests.type DERIVE'
+ echo 'requests.min 0'
+
+ echo 'responses.label responses (all types)'
+ echo 'responses.info total sent response packets'
+ echo 'responses.type DERIVE'
+ echo 'responses.min 0'
+
+ echo 'accepts.label Access-Accepts'
+ echo 'accepts.info total sent Access-Accept packets'
+ echo 'accepts.type DERIVE'
+ echo 'accepts.min 0'
+
+ echo 'rejects.label Access-Rejects'
+ echo 'rejects.info total sent Access-Reject packets'
+ echo 'rejects.type DERIVE'
+ echo 'rejects.min 0'
+
+ echo 'challenges.label Access-Challenges'
+ echo 'challenges.info total sent Access-Challenge packets'
+ echo 'challenges.type DERIVE'
+ echo 'challenges.min 0'
+
+ echo 'dup.label Duplicate requests'
+ echo 'dup.info total duplicate request packets'
+ echo 'dup.type DERIVE'
+ echo 'dup.min 0'
+
+ echo 'invalid.label Invalid requests'
+ echo 'invalid.info total invalid request packets'
+ echo 'invalid.type DERIVE'
+ echo 'invalid.min 0'
+
+ echo 'malformed.label Malformed requests'
+ echo 'malformed.info total malformed request packets'
+ echo 'malformed.type DERIVE'
+ echo 'malformed.min 0'
+
+ echo 'bad_signature.label Requests with bad signature'
+ echo 'bad_signature.info total request packets with a bad signature'
+ echo 'bad_signature.type DERIVE'
+ echo 'bad_signature.min 0'
+
+ echo 'dropped.label Dropped requests'
+ echo 'dropped.info total request packets dropped for other reasons'
+ echo 'dropped.type DERIVE'
+ echo 'dropped.min 0'
+
+ echo 'unknown_types.label Unknown type'
+ echo 'unknown_types.info total request packets of unknown type'
+ echo 'unknown_types.type DERIVE'
+ echo 'unknown_types.min 0'
+
+ exit 0
+fi
+
+$RADMIN -f $SOCKETFILE -e "stats client auth" | awk '{print $1".value " $2}'
diff --git a/scripts/munin/freeradius_proxy_acct b/scripts/munin/freeradius_proxy_acct
new file mode 100755
index 0000000..7a8b85b
--- /dev/null
+++ b/scripts/munin/freeradius_proxy_acct
@@ -0,0 +1,88 @@
+#!/bin/sh
+#
+# Plugin to count the daily amount of freeradius authentication packets.
+#
+# 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) 2008 Alan DeKok <aland@deployingradius.com>
+#
+# Magic markers - optional - used by installation scripts and
+# munin-config:
+#
+#%# family=manual
+#%# capabilities=autoconf
+
+RADMIN=radmin
+SOCKETFILE=/var/run/radiusd/radiusd.sock
+
+if [ "$1" = "autoconf" ]; then
+ #
+ # FIXME: Check if FreeRADIUS is running.
+ #
+ echo yes
+ exit 0
+fi
+
+if [ "$1" = "config" ]; then
+ echo 'graph_title FreeRADIUS Proxied Accounting Requests'
+ echo 'graph_args --base 1000 -l 0 '
+ echo 'graph_period second'
+ echo 'graph_vlabel requests / ${graph_period}'
+ echo 'graph_category Other'
+
+ echo 'requests.label Accounting-Requests'
+ echo 'requests.info total sent request packets'
+ echo 'requests.type DERIVE'
+ echo 'requests.min 0'
+
+ echo 'responses.label Accounting-Responses'
+ echo 'responses.info total received response packets'
+ echo 'responses.type DERIVE'
+ echo 'responses.min 0'
+
+ echo 'dup.label Duplicate requests'
+ echo 'dup.info total duplicate request packets'
+ echo 'dup.type DERIVE'
+ echo 'dup.min 0'
+
+ echo 'invalid.label Invalid requests'
+ echo 'invalid.info total invalid request packets'
+ echo 'invalid.type DERIVE'
+ echo 'invalid.min 0'
+
+ echo 'malformed.label Malformed requests'
+ echo 'malformed.info total malformed request packets'
+ echo 'malformed.type DERIVE'
+ echo 'malformed.min 0'
+
+ echo 'bad_signature.label Requests with bad signature'
+ echo 'bad_signature.info total request packets with a bad signature'
+ echo 'bad_signature.type DERIVE'
+ echo 'bad_signature.min 0'
+
+ echo 'dropped.label Dropped requests'
+ echo 'dropped.info total request packets dropped for other reasons'
+ echo 'dropped.type DERIVE'
+ echo 'dropped.min 0'
+
+ echo 'unknown_types.label Unknown type'
+ echo 'unknown_types.info total request packets of unknown type'
+ echo 'unknown_types.type DERIVE'
+ echo 'unknown_types.min 0'
+
+ exit 0
+fi
+
+$RADMIN -f $SOCKETFILE -e "stats client acct" | awk '{print $1".value " $2}'
diff --git a/scripts/munin/freeradius_proxy_auth b/scripts/munin/freeradius_proxy_auth
new file mode 100755
index 0000000..dbc8617
--- /dev/null
+++ b/scripts/munin/freeradius_proxy_auth
@@ -0,0 +1,103 @@
+#!/bin/sh
+#
+# Plugin to count the daily amount of freeradius authentication packets.
+#
+# 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) 2008 Alan DeKok <aland@deployingradius.com>
+#
+# Magic markers - optional - used by installation scripts and
+# munin-config:
+#
+#%# family=manual
+#%# capabilities=autoconf
+
+RADMIN=radmin
+SOCKETFILE=/var/run/radiusd/radiusd.sock
+
+if [ "$1" = "autoconf" ]; then
+ #
+ # FIXME: Check if FreeRADIUS is running.
+ #
+ echo yes
+ exit 0
+fi
+
+if [ "$1" = "config" ]; then
+ echo 'graph_title FreeRADIUS Proxied Authentication Requests'
+ echo 'graph_args --base 1000 -l 0 '
+ echo 'graph_period second'
+ echo 'graph_vlabel requests / ${graph_period}'
+ echo 'graph_category Other'
+
+ echo 'requests.label Access-Requests'
+ echo 'requests.info total sent request packets'
+ echo 'requests.type DERIVE'
+ echo 'requests.min 0'
+
+ echo 'responses.label responses (all types)'
+ echo 'responses.info total received response packets'
+ echo 'responses.type DERIVE'
+ echo 'responses.min 0'
+
+ echo 'accepts.label Access-Accepts'
+ echo 'accepts.info total received Access-Accept packets'
+ echo 'accepts.type DERIVE'
+ echo 'accepts.min 0'
+
+ echo 'rejects.label Access-Rejects'
+ echo 'rejects.info total received Access-Reject packets'
+ echo 'rejects.type DERIVE'
+ echo 'rejects.min 0'
+
+ echo 'challenges.label Access-Challenges'
+ echo 'challenges.info total received Access-Challenge packets'
+ echo 'challenges.type DERIVE'
+ echo 'challenges.min 0'
+
+ echo 'dup.label Duplicate requests'
+ echo 'dup.info total duplicate request packets'
+ echo 'dup.type DERIVE'
+ echo 'dup.min 0'
+
+ echo 'invalid.label Invalid requests'
+ echo 'invalid.info total invalid request packets'
+ echo 'invalid.type DERIVE'
+ echo 'invalid.min 0'
+
+ echo 'malformed.label Malformed requests'
+ echo 'malformed.info total malformed request packets'
+ echo 'malformed.type DERIVE'
+ echo 'malformed.min 0'
+
+ echo 'bad_signature.label Requests with bad signature'
+ echo 'bad_signature.info total request packets with a bad signature'
+ echo 'bad_signature.type DERIVE'
+ echo 'bad_signature.min 0'
+
+ echo 'dropped.label Dropped requests'
+ echo 'dropped.info total request packets dropped for other reasons'
+ echo 'dropped.type DERIVE'
+ echo 'dropped.min 0'
+
+ echo 'unknown_types.label Unknown type'
+ echo 'unknown_types.info total request packets of unknown type'
+ echo 'unknown_types.type DERIVE'
+ echo 'unknown_types.min 0'
+
+ exit 0
+fi
+
+$RADMIN -f $SOCKETFILE -e "stats home_server auth" | awk '{print $1".value " $2}'
diff --git a/scripts/munin/radsniff b/scripts/munin/radsniff
new file mode 100755
index 0000000..47f4400
--- /dev/null
+++ b/scripts/munin/radsniff
@@ -0,0 +1,246 @@
+#!/bin/sh
+: << =cut
+
+=head1 NAME
+
+radsniff - A plugin to consume statistics generated by radsniff via collectd RRD files
+
+=head1 APPLICABLE SYSTEMS
+
+radsniff v4 or later
+
+=head1 CONFIGURATION
+
+This plugin uses the following configuration variables:
+
+ [radsniff]
+ env.host - The host collectd thinks the radsniff data
+ originated from (defaults to current host).
+ env.rrd_path - Path to the directory containing rrd files.
+ env.type - Either radius_rtx, radius_latency or radius_count
+ env.pkt_type - The type of packet to graph.
+ env.instance - radsniff instance name (passed to radsniff with -N).
+
+=head1 AUTHOR
+
+Copyright (C) 2014 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+
+=head1 LICENSE
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+
+=head1 MAGIC MARKERS
+
+ #%# family=manual
+
+=cut
+
+if [ -z "$type" ]; then
+ echo "env.type must be set" >&2
+ exit -1
+fi
+
+if [ -z "$pkt_type" ]; then
+ echo "env.pkt_type must be set" >&2
+ exit -1
+fi
+
+if [ "$1" = "config" ]; then
+ pretty_pkt_type=`echo "$pkt_type" | sed -e 's/_/ /g' | sed 's/^./\U&\E/'`
+
+ case "$type" in
+ radius_rtx)
+ echo "graph_title ${pretty_pkt_type} rtx"
+ echo 'graph_args --base 1000 -l 0 '
+ echo 'graph_period second'
+ echo 'graph_vlabel Exchanged / ${graph_period}'
+ echo 'graph_category RADIUS'
+
+ echo 'none.label no loss'
+ echo 'none.info Responses received after first request'
+ echo 'none.type GAUGE'
+ echo 'none.min 0'
+
+ echo 'one.label 1'
+ echo 'one.info Responses received after one retransmission'
+ echo 'one.type GAUGE'
+ echo 'one.min 0'
+
+ echo 'two.label 2'
+ echo 'two.info Responses received after two retransmissions'
+ echo 'two.type GAUGE'
+ echo 'two.min 0'
+
+ echo 'three.label 3'
+ echo 'three.info Responses received after three retransmissions'
+ echo 'three.type GAUGE'
+ echo 'three.min 0'
+
+ echo 'four.label 4'
+ echo 'four.info Responses received after four retransmissions'
+ echo 'four.type GAUGE'
+ echo 'four.min 0'
+
+ echo 'more.label more'
+ echo 'more.info Responses received after more than four retransmissions'
+ echo 'more.type GAUGE'
+ echo 'more.min 0'
+
+ echo 'lost.label lost'
+ echo 'lost.info Requests to which no response was seen'
+ echo 'lost.type GAUGE'
+ echo 'lost.min 0'
+ ;;
+
+ radius_latency)
+ echo "graph_title ${pretty_pkt_type} latency"
+ echo 'graph_args --base 1000 -l 0 '
+ echo 'graph_vlabel Latency (ms)'
+ echo 'graph_category RADIUS'
+
+ echo 'smoothed.label smoothed avg'
+ echo 'smoothed.info Smoothed average'
+ echo 'smoothed.type GAUGE'
+ echo 'smoothed.min 0'
+
+ echo 'avg.label avg'
+ echo 'avg.info Average latency over the stats interval'
+ echo 'avg.type GAUGE'
+ echo 'avg.min 0'
+
+ echo 'high.label high'
+ echo 'high.info Highest latency over the stats interval'
+ echo 'high.type GAUGE'
+ echo 'high.min 0'
+
+ echo 'low.label low'
+ echo 'low.info Lowest latency over the stats interval'
+ echo 'low.type GAUGE'
+ echo 'low.min 0'
+ ;;
+
+ radius_count)
+ echo "graph_title $pretty_pkt_type counters"
+ echo 'graph_args --base 1000 -l 0 '
+ echo 'graph_period second'
+ echo 'graph_vlabel Packets / ${graph_period}'
+ echo 'graph_category RADIUS'
+
+ echo 'received.label received'
+ echo 'received.info Packets of this type received'
+ echo 'received.type GAUGE'
+ echo 'received.min 0'
+
+ echo 'linked.label linked'
+ echo 'linked.info Packets linked to another request or response'
+ echo 'linked.type GAUGE'
+ echo 'linked.min 0'
+
+ echo 'unlinked.label unlinked'
+ echo 'unlinked.info Packets not linked to another request or response'
+ echo 'unlinked.type GAUGE'
+ echo 'unlinked.min 0'
+
+ echo 'reused.label reused'
+ echo 'reused.info Request which (prematurely) re-used the same ID as a previous request'
+ echo 'reused.type GAUGE'
+ echo 'reused.min 0'
+ ;;
+ *)
+ echo "env.type ($type) is invalid must be radius_rtx, radius_latency, or radius_count" >&2
+ exit -1
+ esac
+ exit 0
+fi
+
+HOST=${host:-`hostname -f`}
+INSTANCE=${instance:-'radsniff'}
+RRD_PATH=${rrd_path:-"/var/lib/collectd/rrd/${HOST}/${INSTANCE}-exchanged"}
+RRD_PATH="${RRD_PATH}/${type}-${pkt_type}.rrd"
+RRD_RES=${rrd_res:-300}
+
+if [ ! -e "$RRD_PATH" ]; then
+ echo "rrd file '$RRD_PATH' does not exist" >&2
+ exit -1
+fi
+
+fetch_data()
+{
+ # RRD tool doesn't always select the correct period (seems
+ # to round up and give us -nan results) in the interest of
+ # gap free graphing, we attempt to get the last two periods
+ # worth of data, and then use the newest non -nan one.
+ # It's not perfect and should be fixed at some point...
+ rrd_last=`rrdtool fetch "$RRD_PATH" $1 -r $RRD_RES -e $(expr $(date +%s) / $RRD_RES \* $RRD_RES) -s end-$(expr $RRD_RES \* 2)`; ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "$rrd_last" >&2
+ exit $ret
+ fi
+ echo "$rrd_last" | head -1
+ echo "$rrd_last" | grep '^[0-9]*:' | grep -v -E '^[0-9]*:( -nan)*$' | tail -1
+}
+
+fetch_data_column()
+{
+ echo "$(fetch_data $1)" | tail -1 | cut -d ' ' -f $(expr $2 + 2)
+}
+
+case "$type" in
+ radius_rtx)
+ col=2
+ rrd_data=$(fetch_data 'AVERAGE')
+ for var in `echo "$rrd_data" | head -1`; do
+ case "$var" in
+ 1) printf "one.value ";;
+ 2) printf "two.value ";;
+ 3) printf "three.value ";;
+ 4) printf "four.value ";;
+ *) printf "$var.value ";;
+ esac
+ echo "$rrd_data" | tail -1 | cut -d ' ' -f $col
+ col=`expr $col + 1`
+ done
+ ;;
+
+ radius_count)
+ col=2
+ rrd_data=$(fetch_data 'AVERAGE')
+ for var in `echo "$rrd_data" | head -1`; do
+ printf "$var.value "
+ echo "$rrd_data" | tail -1 | cut -d ' ' -f $col
+ col=`expr $col + 1`
+ done
+ ;;
+
+ radius_latency)
+ printf "smoothed.value "
+ fetch_data_column 'AVERAGE' 0
+
+ printf "avg.value "
+ fetch_data_column 'AVERAGE' 1
+
+ # Averages here are unacceptable because we use this to detect
+ # abnormally long delays in responses, and if we average all the highs
+ # over a five minute period, transient spikes in latency may be lost.
+ printf "high.value "
+ fetch_data_column 'MAX' 2
+
+ # Again we need the lowest value of the set here, as an abnormally
+ # quick response may indicate something is wrong.
+ printf "low.value "
+ fetch_data_column 'MIN' 3
+ ;;
+esac
+exit 0
diff --git a/scripts/osx/README b/scripts/osx/README
new file mode 100644
index 0000000..ee621d6
--- /dev/null
+++ b/scripts/osx/README
@@ -0,0 +1,2 @@
+cp ./org.freeradius.radius.plist /System/Library/LaunchDaemons
+launchctl load -w /System/Library/LaunchDaemons/org.freeradius.radiusd.plist
diff --git a/scripts/osx/org.freeradius.radiusd.plist b/scripts/osx/org.freeradius.radiusd.plist
new file mode 100644
index 0000000..5f593a5
--- /dev/null
+++ b/scripts/osx/org.freeradius.radiusd.plist
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>Disabled</key>
+ <true/>
+ <key>EnableTransactions</key>
+ <true/>
+ <key>KeepAlive</key>
+ <true/>
+ <key>RunAtLoad</key>
+ <true/>
+ <key>Label</key>
+ <string>org.freeradius.radiusd</string>
+ <key>ProgramArguments</key>
+ <array>
+ <string>/usr/sbin/radiusd</string>
+ <string>-f</string>
+ </array>
+</dict>
+</plist>
diff --git a/scripts/raddebug b/scripts/raddebug
new file mode 100755
index 0000000..c1d6a2a
--- /dev/null
+++ b/scripts/raddebug
@@ -0,0 +1,140 @@
+#!/bin/sh
+######################################################################
+#
+# 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 Network RADIUS SARL <info@networkradius.com>
+#
+######################################################################
+#
+# This script assumes that "radmin" is in PATH, and that the user
+# running this script has permission to connect to the radmin socket,
+# and to read/write files in the "logdir" directory. If none of this is
+# true, then it won't work.
+#
+# Usage: raddebug [-c condition] [-i client-ip-address] [-I client-ipv6-address] [-f socket_file] [-t timeout] [-u username]
+#
+#
+
+usage() {
+ printf "Usage: %s: [-c condition] [-d directory] [-n name] [-D dictdir] [-i client-ip-address] [-I client-ipv6-address] [-f socket_file] [-t timeout] [-u user]\n" $(basename $0) >&2
+ exit 2
+}
+
+extra=
+condition=1
+timeout=60
+while getopts 'd:n:D:c:i:I:f:t:u:' OPTION
+do
+ case $OPTION in
+ c) condition="$OPTARG"
+ ;;
+ d) extra="$extra -d $OPTARG"
+ ;;
+ n) extra="$extra -n $OPTARG"
+ ;;
+ D) extra="$extra -D $OPTARG"
+ ;;
+ i) x="(Packet-Src-IP-Address == $OPTARG)"
+ if [ "$condition" = "" ]; then
+ condition="$x"
+ else
+ condition="$condition && $x"
+ fi
+ ;;
+ I) x="(Packet-Src-IPv6-Address == $OPTARG)"
+ if [ "$condition" = "" ]; then
+ condition="$x"
+ else
+ condition="$condition && $x"
+ fi
+ ;;
+ f) extra="$extra -f $OPTARG"
+ ;;
+ t) timeout="$OPTARG"
+ [ "$timeout" = "0" ] && timeout=1000000
+ ;;
+ u) x="(User-Name == '$OPTARG')"
+ if [ "$condition" = "" ]; then
+ condition="$x"
+ else
+ condition="$condition && $x"
+ fi
+ ;;
+ ?) usage
+ ;;
+ esac
+done
+shift $(($OPTIND - 1))
+
+radmin="radmin $extra"
+
+#
+# Start off by turning off debugging.
+# If there's a problem, die.
+#
+$radmin -e "debug condition"
+if [ "$?" != "0" ]; then
+ exit 1
+fi
+
+#
+# Debug to a file, and then tell us where the file is.
+#
+outfile=`$radmin -e "debug file radmin.debug.$$" -e "show debug file"`
+group=`$radmin -e "debug file radmin.debug.$$" -e "show config security.group"`
+
+#
+# If there was an error setting the debug output, re-set the
+# debug condition, echo the error, and exit.
+#
+echo $outfile | grep 'ERROR' >/dev/null 2>&1
+if [ "$?" = "0" ]; then
+ $radmin -e "debug condition"
+ echo $outfile
+ exit 1
+fi
+
+#
+# Truncate the file, and ensure it's writable by radiusd
+#
+cp /dev/null $outfile
+[ "$group" != "" ] && chgrp $group $outfile
+chmod g+w $outfile
+
+TAILPID=$$
+
+#
+# Set the trap to clean up on exit and any interrupts.
+#
+trap '$radmin -e "debug condition" -e "debug file"; rm -f $outfile;kill -TERM $TAILPID;exit 0' 1 2 15
+
+#
+# Set the debug condition
+#
+$radmin -e "debug condition \"$condition\"" | grep -I 'error'
+if [ $? -eq 0 ]; then
+ exit 1
+fi
+
+#
+# Print the output, and wait for "timeout". Then, stop printing.
+#
+tail -f $outfile &
+TAILPID=$!
+sleep $timeout
+kill -TERM $TAILPID
+$radmin -e "debug condition" -e "debug file"
+rm -f $outfile
diff --git a/scripts/radiusd.sh b/scripts/radiusd.sh
new file mode 100644
index 0000000..e791dff
--- /dev/null
+++ b/scripts/radiusd.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+#
+# The purpose of this script is to forcibly load the *correct* version
+# of OpenSSL for FreeRADIUS, when you have more than one version of OpenSSL
+# installed on your system.
+#
+# You'll have to edit the directories to the correct location
+# for your local system.
+#
+# $Id$
+#
+
+LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/ssl/lib:/usr/local/radius/lib
+LD_PRELOAD=/usr/local/ssl/lib/libcrypto.so
+
+export LD_LIBRARY_PATH LD_PRELOAD
+exec /usr/local/radius/sbin/radiusd $@
diff --git a/scripts/radtee b/scripts/radtee
new file mode 100755
index 0000000..78b4bcb
--- /dev/null
+++ b/scripts/radtee
@@ -0,0 +1,563 @@
+#!/usr/bin/env python2
+from __future__ import with_statement
+
+# RADIUS comparison tee v1.0
+# Sniffs local RADIUS traffic, replays incoming requests to a test
+# server, and compares the sniffed responses with the responses
+# generated by the test server.
+#
+# Copyright (c) 2009, Frontier Communications
+# Copyright (c) 2010, John Morrissey <jwm@horde.net>
+#
+# 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.
+
+# Requires
+# ========
+# - python 2.4 or newer
+# - impacket
+# - pcapy
+# - pyrad, ideally 1.2 or newer
+
+# Output
+# ======
+# - .: 50 successful, matching responses processed.
+# - C=x.x.x.x: Ignored packet sniffed from unknown client.
+# - D: Dropped sniffed packet due to processing bottleneck. Consider
+# increasing THREADS.
+# - I: Invalid/unparseable packet sniffed.
+# - Mreq: Response was sniffed without sniffing a corresponding request.
+# - Mresp: Request was sniffed without sniffing a corresponding response.
+# - T: Request to test server timed out.
+
+import fcntl
+from getopt import gnu_getopt, GetoptError
+import os
+import Queue
+import re
+import signal
+import socket
+import struct
+import sys
+import thread
+from threading import Thread
+from time import sleep, time
+
+from impacket.ImpactDecoder import EthDecoder
+import pcapy
+from pyrad.client import Client
+from pyrad.dictionary import Dictionary
+from pyrad import packet
+
+
+TEST_DEST = 'server.example.com'
+TEST_SECRET = 'examplesecret'
+
+# Dictionary to use when decoding RADIUS packets. pyrad earlier than
+# v1.2 can't parse $INCLUDE directives, so you must combine FreeRADIUS'
+# dictionary manually, with something like this:
+#
+# import re
+# import sys
+#
+# def combine(file):
+# for line in open(file):
+# matches = re.search(r'^\$INCLUDE\s+(.*)$', line)
+# if not matches:
+# sys.stdout.write(line)
+# continue
+#
+# combine(matches.group(1))
+#
+# combine('/etc/freeradius/dictionary')
+DICTIONARY = '/etc/freeradius/dictionary'
+
+# Number of worker threads to run.
+THREADS = 32
+
+# Mapping of RADIUS request source addresses to shared secrets,
+# so we can decode incoming RADIUS requests.
+#
+# For example:
+# '127.0.0.1': 'test',
+CLIENTS = {
+}
+
+# Ignore any sniffed requests from these IP addresses.
+IGNORE_CLIENTS = [
+]
+
+# Expected mismatches to ignore and consider the packet matching.
+# Only the differences are compared to these items, so only the
+# differing attrs need be listed in the attrs array.
+#
+# Examples:
+# - Ignore mismatched AccessRejects whose sole difference is a
+# Reply-Message attribute with the values given.
+# {
+# 'sniffed': {
+# 'code': packet.AccessReject,
+# 'attrs': [
+# 'Reply-Message=Request Denied',
+# ],
+# },
+# 'test': {
+# 'code': packet.AccessReject,
+# 'attrs': [
+# 'Reply-Message=Account is disabled.',
+# ],
+# }
+# },
+#
+# - Ignore mismatched AccessRejects with Reply-Message=Request Denied
+# and arbitrary Cisco dns-servers in the sniffed packet, and
+# no Reply-Message and Cisco-AVPair attrs in the response from the
+# test RADIUS server.
+# {
+# 'sniffed': {
+# 'code': packet.AccessReject,
+# 'attrs': [
+# 'Reply-Message=Request Denied',
+# 'regex:^Cisco-AVPair=ip:dns-servers=.*$',
+# ],
+# },
+# 'test': {
+# 'code': packet.AccessReject,
+# 'attrs': [
+# ],
+# }
+# },
+#
+# - Only apply this stanza to sniffed requests with
+# 'User-Name= user@example.com' (note the leading whitespace).
+# {
+# 'check': [
+# 'User-Name= user@example.com',
+# ],
+# 'sniffed': {
+# 'code': packet.AccessReject,
+# 'attrs': [
+# 'Reply-Message=Request Denied',
+# ],
+# },
+# 'test': {
+# 'code': packet.AccessAccept,
+# 'attrs': [
+# 'Service-Type=Framed-User',
+# 'Framed-Protocol=PPP',
+# 'Framed-IP-Address=255.255.255.255',
+# 'Framed-MTU=1500',
+# 'Framed-Compression=Van-Jacobson-TCP-IP',
+# ],
+# }
+# },
+IGNORE = [
+]
+
+
+QUEUE = Queue.Queue(maxsize=25000)
+DICT = Dictionary(DICTIONARY)
+
+def code2str(code):
+ if code == packet.AccessRequest:
+ return "Access-Request"
+ elif code == packet.AccessAccept:
+ return "Access-Accept"
+ elif code == packet.AccessReject:
+ return "Access-Reject"
+ elif code == packet.AccountingRequest:
+ return "Accounting-Request"
+ elif code == packet.AccountingResponse:
+ return "Accounting-Response"
+ elif code == packet.AccessChallenge:
+ return "Access-Challenge"
+ elif code == packet.StatusServer:
+ return "Status-Server"
+ elif code == packet.StatusClient:
+ return "Status-Client"
+ elif code == packet.DisconnectRequest:
+ return "Disconnect-Request"
+ elif code == packet.DisconnectACK:
+ return "Disconnect-ACK"
+ elif code == packet.DisconnectNAK:
+ return "Disconnect-NAK"
+ elif code == packet.CoARequest:
+ return "CoA-Request"
+ elif code == packet.CoAACK:
+ return "CoA-ACK"
+ elif code == packet.CoANAK:
+ return "CoA-NAK"
+
+def handlePacket(header, data):
+ """Place captured packets in the queue to be picked up
+ by worker threads."""
+
+ global QUEUE
+
+ try:
+ QUEUE.put_nowait(data)
+ except Queue.Full:
+ sys.stdout.write('D')
+ sys.stdout.flush()
+
+def ignore_applies(pkt, ignore):
+ """Determine whether an ignore stanza (based on its check
+ items) applies to a packet."""
+
+ # All check items must match for this ignore stanza to apply.
+ stanza_applies = True
+ for pair in ignore.get('check', []):
+ attr, value = pair.split('=')
+
+ if attr not in pkt:
+ return False
+ if value.startswith('regex:'):
+ if not re.search(value.replace('regex:', '', 1), value):
+ return False
+ elif pkt[attr] != value:
+ return False
+
+ return True
+
+def ignores_match(pkt, mismatched, ignore):
+ """Determine whether mismatched AV pairs remain after accounting
+ for ignored differences."""
+
+ non_regex_ignore = [
+ q
+ for q
+ in ignore['attrs']
+ if not q.startswith('regex:')
+ ]
+ regex_ignore = [
+ q
+ for q
+ in ignore['attrs']
+ if q.startswith('regex:')
+ ]
+
+ unmatched_av = mismatched[:]
+ unmatched_rules = ignore['attrs'][:]
+ for av in mismatched:
+ if av in non_regex_ignore:
+ unmatched_av.remove(av)
+ unmatched_rules.remove(av)
+ continue
+ for regex in regex_ignore:
+ if re.search(regex.replace('regex:', '', 1), av):
+ unmatched_av.remove(av)
+ if regex in unmatched_rules:
+ unmatched_rules.remove(regex)
+ break
+
+ if unmatched_av or unmatched_rules:
+ return False
+ return True
+
+def matches(req, sniffed_pkt, test_pkt):
+ """Determine whether a response from the test server matches
+ the response sniffed from the wire, accounting for ignored
+ differences."""
+
+ global IGNORE
+
+ mis_attrs_sniffed = []
+ for k in sniffed_pkt.keys():
+ if sorted(sniffed_pkt[k]) == sorted(test_pkt.get(k, [])):
+ continue
+ mis_attrs_sniffed.append('%s=%s' % (
+ k, ', '.join([str(v) for v in sorted(sniffed_pkt[k])])))
+
+ mis_attrs_test = []
+ for k in test_pkt.keys():
+ if sorted(test_pkt[k]) == sorted(sniffed_pkt.get(k, [])):
+ continue
+ mis_attrs_test.append('%s=%s' % (
+ k, ', '.join([str(v) for v in sorted(test_pkt[k])])))
+
+ # The packets match without having to consider any ignores.
+ if sniffed_pkt.code == test_pkt.code and \
+ not mis_attrs_sniffed and not mis_attrs_test:
+ return True
+
+ for ignore in IGNORE:
+ if not ignore_applies(req, ignore):
+ continue
+
+ if ignore['sniffed']['code'] != sniffed_pkt.code or \
+ ignore['test']['code'] != test_pkt.code:
+ continue
+
+ if ignores_match(sniffed_pkt, mis_attrs_sniffed, i['sniffed']):
+ return True
+ if ignores_match(test_pkt, mis_attrs_test, i['test']):
+ return True
+
+ return False
+
+def log_mismatch(nas, req, passwd, expected, got):
+ """Emit notification that the test server has returned a response
+ that differs from the sniffed response."""
+
+ print 'Mismatch: %s' % nas
+
+ print 'Request: %s' % code2str(req.code)
+ for key in req.keys():
+ if key == 'User-Password':
+ print '\t%s: %s' % (key, passwd)
+ continue
+ print '\t%s: %s' % (
+ key, ', '.join([str(v) for v in req[key]]))
+
+ print 'Expected: %s' % code2str(expected.code)
+ for key in expected.keys():
+ print '\t%s: %s' % (
+ key, ', '.join([str(v) for v in expected[key]]))
+
+ print 'Got: %s' % code2str(got.code)
+ for key in got.keys():
+ print '\t%s: %s' % (
+ key, ', '.join([str(v) for v in got[key]]))
+
+ print
+
+REQUESTS = {}
+REQUESTS_LOCK = thread.allocate_lock()
+NUM_SUCCESSFUL = 0
+def check_for_match(key, req_resp):
+ """Send a copy of the original request to the test server and
+ determine whether the response matches the response sniffed from
+ the wire."""
+
+ global DICT, NUM_SUCCESSFUL, TEST_DEST, TEST_SECRET
+ global REQUESTS, REQUESTS_LOCK
+
+ client = Client(server=TEST_DEST,
+ secret=TEST_SECRET, dict=DICT)
+ fwd_req = client.CreateAuthPacket(code=packet.AccessRequest)
+ fwd_req.authenticator = req_resp['req']['pkt'].authenticator
+
+ keys = req_resp['req']['pkt'].keys()
+ for k in keys:
+ for value in req_resp['req']['pkt'][k]:
+ fwd_req.AddAttribute(k, value)
+ if 'User-Password' in keys:
+ fwd_req['User-Password'] = fwd_req.PwCrypt(req_resp['req']['passwd'])
+ if 'NAS-IP-Address' in fwd_req:
+ del fwd_req['NAS-IP-Address']
+ fwd_req.AddAttribute('NAS-IP-Address', req_resp['req']['ip'])
+
+ try:
+ test_reply = client.SendPacket(fwd_req)
+ except:
+ # Request to test server timed out.
+ sys.stdout.write('T')
+ sys.stdout.flush()
+ with REQUESTS_LOCK:
+ del REQUESTS[key]
+ return
+
+ if not matches(req_resp['req']['pkt'],
+ req_resp['response']['pkt'], test_reply):
+
+ print
+ log_mismatch(req_resp['req']['ip'],
+ req_resp['req']['pkt'],
+ req_resp['req']['passwd'],
+ req_resp['response']['pkt'], test_reply)
+
+ with REQUESTS_LOCK:
+ # Occasionally, this key isn't present. Maybe retransmissions
+ # due to a short timeout on the remote RADIUS client's end
+ # and a subsequent race?
+ if key in REQUESTS:
+ del REQUESTS[key]
+
+ NUM_SUCCESSFUL += 1
+ if NUM_SUCCESSFUL % 50 == 0:
+ sys.stdout.write('.')
+ sys.stdout.flush()
+
+class RadiusComparer(Thread):
+ def run(self):
+ global DICT, IGNORE_CLIENTS, QUEUE, REQUESTS, REQUESTS_LOCK
+
+ while True:
+ data = QUEUE.get()
+ if not data:
+ return
+
+ frame = EthDecoder().decode(data)
+ ip = frame.child()
+ udp = ip.child()
+ rad_raw = udp.child().get_buffer_as_string()
+
+ try:
+ pkt = packet.Packet(dict=DICT, packet=rad_raw)
+ except packet.PacketError:
+ sys.stdout.write('I')
+ sys.stdout.flush()
+ continue
+
+ if ip.get_ip_src() in IGNORE_CLIENTS:
+ continue
+
+ if pkt.code == packet.AccessRequest:
+ auth = packet.AuthPacket(data[42:])
+ auth.authenticator = pkt.authenticator
+ auth.secret = clients.CLIENTS.get(ip.get_ip_src(), None)
+ if not auth.secret:
+ # No configuration for this client.
+ sys.stdout.write('C=%s' % ip.get_ip_src())
+ sys.stdout.flush()
+ continue
+ passwd = None
+ if 'User-Password' in pkt.keys():
+ passwd = auth.PwDecrypt(pkt['User-Password'][0])
+
+ key = '%s:%d:%d' % (ip.get_ip_src(),
+ udp.get_uh_sport(), pkt.id)
+ do_compare = None
+ with REQUESTS_LOCK:
+ if key not in REQUESTS:
+ REQUESTS[key] = {}
+ REQUESTS[key]['req'] = {
+ 'ip': ip.get_ip_src(),
+ 'port': udp.get_uh_sport(),
+ 'pkt': pkt,
+ 'passwd': passwd,
+ }
+ REQUESTS[key]['tstamp'] = time()
+ if 'response' in REQUESTS[key]:
+ do_compare = REQUESTS[key]
+
+ if do_compare:
+ check_for_match(key, do_compare)
+ elif pkt.code in [packet.AccessAccept, packet.AccessReject]:
+ key = '%s:%d:%d' % (ip.get_ip_dst(),
+ udp.get_uh_dport(), pkt.id)
+ do_compare = None
+ with REQUESTS_LOCK:
+ if key not in REQUESTS:
+ REQUESTS[key] = {}
+ REQUESTS[key]['response'] = {
+ 'ip': ip.get_ip_src(),
+ 'port': udp.get_uh_sport(),
+ 'pkt': pkt,
+ }
+ REQUESTS[key]['tstamp'] = time()
+ if 'req' in REQUESTS[key]:
+ do_compare = REQUESTS[key]
+
+ if do_compare:
+ check_for_match(key, do_compare)
+ else:
+ print >>sys.stderr, \
+ 'Unsupported packet type received: %d' % pkt.code
+
+class RequestsPruner(Thread):
+ """Prune stale request state periodically."""
+
+ def run(self):
+ global REQUESTS, REQUESTS_LOCK
+
+ while True:
+ sleep(30)
+
+ now = time()
+ with REQUESTS_LOCK:
+ keys = REQUESTS.keys()
+ for key in keys:
+ if REQUESTS[key]['tstamp'] + 60 >= now:
+ continue
+
+ if 'req' not in REQUESTS[key]:
+ sys.stdout.write('Mreq')
+ sys.stdout.flush()
+ if 'response' not in REQUESTS[key]:
+ sys.stdout.write('Mresp')
+ sys.stdout.flush()
+
+ del REQUESTS[key]
+
+def usage():
+ print 'Usage: %s INTERFACE' % os.path.basename(sys.argv[0])
+ print ''
+ print ' -h, --help display this help and exit'
+
+if __name__ == '__main__':
+ global PID_FILE
+
+ progname = os.path.basename(sys.argv[0])
+
+ try:
+ options, iface = gnu_getopt(sys.argv[1:], 'h', ['help'])
+ except GetoptError, e:
+ print '%s: %s' % (progname, str(e))
+ usage()
+ sys.exit(1)
+
+ for option in options:
+ if option[0] == '-h' or option[0] == '--help':
+ usage()
+ sys.exit(0)
+
+ if len(iface) != 1:
+ usage()
+ sys.exit(1)
+ iface = iface[0]
+
+ if os.geteuid() != 0:
+ print >>sys.stderr, '%s: must be run as root.' % progname
+ sys.exit(1)
+
+ for i in range(0, THREADS):
+ RadiusComparer().start()
+ RequestsPruner().start()
+
+ s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+
+ # This is Linux-specific, and there's no tenable way to make
+ # it portable.
+ #
+ # Unfortunately, we need the interface's IP address to filter out
+ # only RADIUS traffic destined for this host (avoiding traffic sent
+ # *by* this host, such as proxied requests or our own traffic) to
+ # avoid replaying requests not directed to the local radiusd.
+ #
+ # Furthermore, this only obtains the interface's *first* IP address,
+ # so we won't notice traffic sent to additional IP addresses on
+ # the given interface.
+ #
+ # This is Good Enough For Me given the effort I care to invest.
+ # Of course, patches enhancing this are welcome.
+ if os.uname()[0] == 'Linux':
+ local_ipaddr = socket.inet_ntoa(fcntl.ioctl(
+ s.fileno(),
+ 0x8915, # SIOCGIFADDR
+ struct.pack('256s', iface[:15])
+ )[20:24])
+ else:
+ raise Exception('Only the Linux operating system is currently supported.')
+
+ p = pcapy.open_live(iface, 1600, 0, 100)
+ p.setfilter('''
+ (dst host %s and udp and dst port 1812) or
+ (src host %s and udp and src port 1812)''' % \
+ (local_ipaddr, local_ipaddr))
+ while True:
+ try:
+ p.dispatch(1, handlePacket)
+ except KeyboardInterrupt:
+ sys.exit(0)
diff --git a/scripts/raduat b/scripts/raduat
new file mode 100755
index 0000000..9778b2a
--- /dev/null
+++ b/scripts/raduat
@@ -0,0 +1,366 @@
+#!/bin/bash
+
+# Simple test wrapper around radclient to allow automated UATs
+#
+# Author Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+# Copyright 2014-2015 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+# Copyright 2015 The FreeRADIUS Project
+
+# A POSIX variable
+OPTIND=1 # Reset in case getopts has been used previously in the shell.
+
+# Environmental variables
+: ${TESTDIR=$(dirname $0)"/tests"}
+: ${RADCLIENT='radclient'}
+: ${FILTER_SUFFIX='_expected'}
+: ${DICTPATH=$(dirname $0)/share}
+PATH="$(dirname $0)/bin:${PATH}"
+
+# Initialize our own variables
+verbose=0
+cluster=
+role=
+type=
+parallel=40
+retries=3
+timeout=2
+target='127.0.0.1'
+secret='testing123'
+
+# Some very basic logging functions
+function ERROR
+{
+ echo "$@" 1>&2;
+}
+
+function INFO
+{
+ echo "$@"
+}
+
+function DEBUG
+{
+ if [ $verbose -gt 0 ]; then
+ echo "$@"
+ fi
+}
+
+function show_help
+{
+ echo $(basename $0)" [options] [-- <test_glob0> <test_glob1> <test_globN>]"
+ echo " -h Display this help message."
+ echo " -H <host>[:port] Send test packets to specified host and port (defaults to 127.0.0.1)"
+ echo " -v Verbose mode."
+ echo " -p <number> Run tests in parallel (defaults to 20)."
+ echo " -s <secret> Shared secret."
+ if [ ! -z "$role_types" ]; then
+ echo " -c <cluster> Specify cluster type one of ($cluster_types)."
+ echo " -r <type> Specify server role one of ($role_types)."
+ echo
+ echo "Note: Test path globs are relative to ${TESTDIR}/<cluster>/<type>/"
+ fi
+
+ echo
+ echo "For role based test file layout create test files under ${TESTDIR}/<cluster>/<type>"
+ echo "Where <cluster> and <type> are substrings found in the FQDN of <host>."
+ echo "For simplified test layout create test files under ${TESTDIR}"
+ echo
+ echo "The directory containing the tests should contains pairs of request files and filter files."
+ echo "The request file name must contain 'test<num><num><num>."
+ echo "The filter name must match the test name but with a '${FILTER_SUFFIX}' suffix."
+ echo "For example:"
+ echo " ${TESTDIR}/test000_my_first_test"
+ echo " ${TESTDIR}/test000_my_first_test${FILTER_SUFFIX}"
+ echo
+ echo "The directory containing the tests may have multiple subdirectories to group the tests."
+}
+
+RADCLIENT=$(command -v "$RADCLIENT")
+if [ ! -x "$RADCLIENT" ]; then
+ ERROR "Can't find radclient binary, modify your \$PATH or set RADCLIENT"
+ exit 64
+fi
+
+if [ ! -d "$TESTDIR" ]; then
+ ERROR "Test dir $TESTDIR does not exist, create it or specify it with TESTDIR=<dir>"
+ show_help
+ exit 64
+fi
+
+# Definitions (build these dynamically by looking at the files under tests)
+cluster_dirs=$(find "$TESTDIR/" -mindepth 1 -maxdepth 1 -type d)
+cluster_types=$(echo $cluster_dirs | sed 's/\s/ /g')
+
+role_types=
+for i in $cluster_dirs; do
+ for j in $(find "$TESTDIR/$(basename $i)/" -mindepth 1 -maxdepth 1 -type d); do
+ role=$(basename "$j")
+ if [ "$role_types" == '' ]; then
+ role_types="$role"
+ else
+ role_types+="\n$role"
+ fi
+ done
+done
+
+if [ -z "$role_types" ]; then
+ DEBUG "Using simple test file layout"
+else
+ DEBUG "Using role based test file layout"
+ role_types=$(echo -e "$role_types" | sort | uniq) # Remove duplicates
+ role_types=$(echo $role_types | sed 's/\s/ /g') # Change \n back to spaces
+fi
+
+while getopts "h?H:vc:r:s:p:" opt; do
+ case "$opt" in
+ h|\?)
+ show_help
+ exit 0
+ ;;
+
+ v)
+ verbose=1
+ ;;
+
+ c)
+ found=0
+ for i in $cluster_types; do
+ if [ "$i" == "$OPTARG" ]; then
+ found=1
+ fi
+ done
+ if [ $found -ne 1 ]; then
+ ERROR "'$OPTARG' is not a valid cluster type"
+ show_help
+ exit 64
+ fi
+ cluster="$OPTARG"
+ ;;
+
+ r)
+ found=0
+ for i in $role_types; do
+ if [ "$i" == "$OPTARG" ]; then
+ found=1
+ fi
+ done
+ if [ $found -ne 1 ]; then
+ ERROR "'$OPTARG' is not a valid role type"
+ show_help
+ exit 64
+ fi
+ role="$OPTARG"
+ ;;
+
+ s)
+ secret="$OPTARG"
+ ;;
+
+ p)
+ if ! echo "$OPTARG" | grep -E '^[0-9]+$' > /dev/null; then
+ ERROR "Non integer argument '$OPTARG' specified for -p"
+ show_help
+ exit 64
+ fi
+ parallel=$OPTARG
+ ;;
+
+ H)
+ target="$OPTARG"
+ ;;
+
+ esac
+done
+
+shift $((OPTIND-1))
+
+[ "$1" = "--" ] && shift
+test_files=$@
+
+#
+# Match keywords from the hostname to clusters or roles
+#
+if [ ! -z "$role_types" ]; then
+ this_host=$(hostname -f)
+ for tok in $(echo "$this_host" | sed 's/\./ /g'); do
+ for key in ${cluster_types}; do
+ if echo "$tok" | grep "$key" > /dev/null && [ "$cluster" = '' ]; then cluster="$key"; fi
+ done
+ for key in ${role_types}; do
+ if echo "$tok" | grep "$key" > /dev/null && [ "$role" = '' ]; then role="$key"; fi
+ done
+ done
+
+ if [ "$cluster" == '' ]; then
+ ERROR "Couldn't determine the cluster $this_host belongs to";
+ show_help
+ exit 64;
+ fi
+
+ if [ "$role" == '' ]; then
+ ERROR "Couldn't determine the role $this_host performs";
+ show_help
+ exit 64;
+ fi
+
+ test_path="${TESTDIR}/${cluster}/${role}"
+#
+# Otherwise just use the tests in the test dir
+#
+else
+ test_path="${TESTDIR}"
+fi
+
+if [ "$test_files" != '' ]; then
+ tmp=
+ for glob in $test_files; do
+ # Filter out response files (makes wildcards easier), and expand the globs
+ for file in $(find "${test_path}" -depth -path "*${glob}" -and -not -path "*${FILTER_SUFFIX}" -and '(' -type f -or -type l ')'); do
+ tmp+="${file} "
+ done
+ done
+ test_files="${tmp}"
+else
+ # Lexicographical, depth-first
+ test_files=$(find "$test_path" -depth -path '*test[0-9][0-9][0-9]*' -and -not -path "*${FILTER_SUFFIX}" -and '(' -type f -or -type l ')')
+ if [ "$test_files" == '' ]; then
+ ERROR "No test files found in $test_path"
+ exit 64;
+ fi
+ INFO "Executing"$(echo "$test_files" | wc -l)" test(s) from ${test_path}"
+fi
+
+#
+# Check if we got any test files
+#
+if [ "$test_files" == '' ]; then
+ ERROR "No test files to process"
+ exit 1
+fi
+
+#
+# Output which files were going to be using for testing
+#
+if [ $verbose -eq 0 ]; then
+ INFO "Executing specified tests"
+ INFO "Use -v to see full list"
+else
+ INFO "Executing specified tests:"
+ for i in $test_files; do
+ DEBUG "$i"
+ done
+fi
+
+#
+# Figure out which tests we can munge into a single file which we can
+# use to parallelise testing
+#
+base=$(basename $0)
+packets=$(mktemp -t "${base}XXX") || exit 1
+filters=$(mktemp -t "${base}XXX") || exit 1
+
+args=
+file_args=
+serial_file_args=
+for i in $test_files; do
+ if [ ! -f "$i" -a ! -L "$i" ]; then
+ INFO "Skipping $i: not file"
+ continue
+ fi
+
+ if [ ! -r "$i" ]; then
+ INFO "Skipping $i: not readable (check permissions)"
+ continue
+ fi
+
+ expected="${i}${FILTER_SUFFIX}"
+ if [ ! -f "$expected" -a ! -L "$expected" ]; then
+ DEBUG "$i cannot be parallelised: Can't find 'expected' file"
+ file_args+=" -f \"$i\""
+ continue
+ fi
+
+ if [ ! -r "$expected" ]; then
+ INFO "$i cannot be parallelised: 'expected' file not readable"
+ file_args+=" -f \"${i}:${expected}\""
+ continue
+ fi
+
+ if head -n 1 "$i" | grep -i -E '^#\s*serial' > /dev/null; then
+ DEBUG "$i marked as serial only"
+ serial_file_args+=" -f \"${i}:${expected}\""
+ continue
+ fi
+
+ # Else add it to the master test file
+ printf '%s\n' "$(cat "$i")" >> "$packets"
+
+ # Add the name of the file so it appears in radclient debug output
+ # and can later be specified with -v -- <test> to drill down.
+ echo "Radclient-Test-Name := \""$(echo "$i" | sed -e "s@${test_path}/\?@@")"\"" >> "$packets"
+ echo >> "$packets"
+ printf '%s\n' "$(cat "${i}_expected")" >> "$filters"
+ echo >> "$filters"
+done
+
+if [ `cat "$packets" | wc -l` -gt 0 ]; then
+ file_args+=" -f \"${packets}:${filters}\""
+fi
+
+if [ ! -z "$file_args" ]; then
+ args="$file_args"
+
+ if [ $verbose -ne 0 ]; then
+ args+=" -x"
+ fi
+
+ args+=" -s"
+ args+=" -t \"$timeout\""
+ args+=" -r \"$retries\""
+ args+=" -p \"$parallel\""
+ args+=" -D \"$DICTPATH\""
+ args+=" \"$target\""
+ args+=" auto"
+ args+=" \"$secret\""
+
+ DEBUG "Executing: $RADCLIENT $args"
+ eval $RADCLIENT $args; ret=$?
+ INFO "(Parallelised tests)"
+ INFO ""
+
+ rm -f "$packets" 2>&1 > /dev/null
+ rm -f "$filters" 2>&1 > /dev/null
+
+ if [ $ret -ne 0 ]; then
+ ERROR "One or more tests failed (radclient exited with $ret)"
+ exit $ret
+ fi
+fi
+
+if [ ! -z "$serial_file_args" ]; then
+ args="$serial_file_args"
+
+ if [ $verbose -ne 0 ]; then
+ args+=" -x"
+ fi
+
+ args+=" -s"
+ args+=" -t \"$timeout\""
+ args+=" -r \"$retries\""
+ args+=" -p 1"
+ args+=" -D \"$DICTPATH\""
+ args+=" \"$target\""
+ args+=" auto"
+ args+=" \"$secret\""
+
+ DEBUG "Executing: $RADCLIENT $args"
+ eval $RADCLIENT $args; ret=$?
+ INFO "(Serialised tests)"
+
+ if [ $ret -ne 0 ]; then
+ ERROR "One or more tests failed (radclient exited with $ret)"
+ exit $ret
+ fi
+fi
+
+exit 0
diff --git a/scripts/rc.radiusd.in b/scripts/rc.radiusd.in
new file mode 100755
index 0000000..4cc04ab
--- /dev/null
+++ b/scripts/rc.radiusd.in
@@ -0,0 +1,100 @@
+#!/bin/sh
+#
+# radiusd Start the radius daemon.
+#
+# 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) 2001-2008 The FreeRADIUS Project http://www.freeradius.org
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+sbindir=@sbindir@
+localstatedir=@localstatedir@
+logdir=@logdir@
+rundir=${localstatedir}/run/radiusd
+sysconfdir=@sysconfdir@
+
+#
+# If you have issues with OpenSSL, uncomment these next lines.
+#
+# Something similar may work for MySQL, and you may also
+# have to LD_PRELOAD libz.so
+#
+#LD_LIBRARY_PATH=@OPENSSL_LIBS@
+#LD_RUN_PATH=@OPENSSL_LIBS@:
+#LD_PRELOAD=@OPENSSL_LIBS@libcrypto.so
+export LD_LIBRARY_PATH LD_RUN_PATH LD_PRELOAD
+
+RADIUSD=$sbindir/radiusd
+RADDBDIR=@raddbdir@
+DESC="FreeRADIUS"
+
+#
+# See 'man radiusd' for details on command-line options.
+#
+ARGS=""
+
+test -f $RADIUSD || exit 0
+test -f $RADDBDIR/radiusd.conf || exit 0
+
+#if [ ! -d $rundir ] ; then
+# mkdir $rundir
+# chown radmin:radius $rundir
+# chmod 775 $rundir
+#fi
+#
+#if [ ! -d $logdir ] ; then
+# mkdir $logdir
+# chown radmin:radius $logdir
+# chmod 770 $logdir
+# chmod g+s $logdir
+#fi
+#
+#if [ ! -f $logdir/radius.log ]; then
+# touch $logdir/radius.log
+#fi
+#
+#chown radmin:radius $logdir/radius.log
+#chmod 660 $logdir/radius.log
+
+case "$1" in
+ start)
+ echo -n "Starting $DESC:"
+ $RADIUSD $ARGS
+ echo "radiusd"
+ ;;
+ stop)
+ [ -z "$2" ] && echo -n "Stopping $DESC: "
+ [ -f $rundir/radiusd.pid ] && kill -TERM `cat $rundir/radiusd.pid`
+ [ -z "$2" ] && echo "radiusd."
+ ;;
+ reload|force-reload)
+ echo "Reloading $DESC configuration files."
+ [ -f $rundir/radiusd.pid ] && kill -HUP `cat $rundir/radiusd.pid`
+ ;;
+ restart)
+ sh $0 stop quiet
+ sleep 3
+ sh $0 start
+ ;;
+ check)
+ $RADIUSD -C $ARGS
+ ;;
+ *)
+ echo "Usage: /etc/init.d/$RADIUS {start|stop|reload|restart|check}"
+ exit 1
+esac
+
+exit 0
diff --git a/scripts/snmp-proxy/README b/scripts/snmp-proxy/README
new file mode 100644
index 0000000..d9741e7
--- /dev/null
+++ b/scripts/snmp-proxy/README
@@ -0,0 +1,32 @@
+ The files in this directory replace the old FreeRADIUS SNMP
+implementantion with a new one.
+
+net-radius-freeradius-dictionary.diff
+ Patch to enable the Perl Net::RADIUS module to read the
+ FreeRADIUS dictionary file format.
+
+dictionary.hacked
+ Dictionary used by Perl Net::RADIUS if it is NOT patched.
+ Do NOT use this dictionary with the FreeRADIUS server!
+
+freeradius-snmp.pl
+ Perl module that implements the connection between SNMP
+ and FreeRADIUS.
+
+ See raddb/sites-available/status for information on using
+ Status-Server packets to obtain internal server statistics.
+
+make sure snmpd is agentx master (snmpd.conf):
+
+ master agentx
+
+run the script (no demonizing support yet):
+
+ $ ./freeradius-snmp.pl
+
+then you can walk the tree (default oid):
+
+ $ snmpbulkwalk -On -v2c -cpublic localhost .1.3.6.1.2.1.67
+
+This code is ALPHA. Please test, and return any fixes back to the
+mailing list, or to bugs.freeradius.org.
diff --git a/scripts/snmp-proxy/dictionary.hacked b/scripts/snmp-proxy/dictionary.hacked
new file mode 100644
index 0000000..66b2159
--- /dev/null
+++ b/scripts/snmp-proxy/dictionary.hacked
@@ -0,0 +1,132 @@
+#
+# This is a dictionary that should be used by the Perl module Net::RADIUS,
+# if it has NOT been updated to parse the FreeRADIUS format dictionaries.
+#
+# It SHOULD NOT be used in the FreeRADIUS server or client!
+#
+ATTRIBUTE Message-Authenticator 80 octets
+
+
+VENDOR FreeRADIUS 11344
+
+ATTRIBUTE FreeRADIUS-Proxied-To 1 ipaddr
+
+
+#
+# This attribute is really a bitmask.
+#
+ATTRIBUTE FreeRADIUS-Statistics-Type 127 integer FreeRADIUS
+
+VALUE FreeRADIUS-Statistics-Type None 0 FreeRADIUS
+VALUE FreeRADIUS-Statistics-Type Authentication 1
+VALUE FreeRADIUS-Statistics-Type Accounting 2
+VALUE FreeRADIUS-Statistics-Type Proxy-Authentication 4
+VALUE FreeRADIUS-Statistics-Type Proxy-Accounting 8
+VALUE FreeRADIUS-Statistics-Type Internal 0x10
+VALUE FreeRADIUS-Statistics-Type Client 0x20
+VALUE FreeRADIUS-Statistics-Type Server 0x40
+VALUE FreeRADIUS-Statistics-Type Home-Server 0x80
+
+VALUE FreeRADIUS-Statistics-Type Auth-Acct 0x03
+VALUE FreeRADIUS-Statistics-Type Proxy-Auth-Acct 0x0c
+
+VALUE FreeRADIUS-Statistics-Type All 0x1f
+
+#
+# Global authentication statistics for packets received by the server.
+#
+ATTRIBUTE FreeRADIUS-Total-Access-Requests 128 integer FreeRADIUS
+ATTRIBUTE FreeRADIUS-Total-Access-Accepts 129 integer FreeRADIUS
+ATTRIBUTE FreeRADIUS-Total-Access-Rejects 130 integer FreeRADIUS
+ATTRIBUTE FreeRADIUS-Total-Access-Challenges 131 integer FreeRADIUS
+ATTRIBUTE FreeRADIUS-Total-Auth-Responses 132 integer FreeRADIUS
+ATTRIBUTE FreeRADIUS-Total-Auth-Duplicate-Requests 133 integer FreeRADIUS
+ATTRIBUTE FreeRADIUS-Total-Auth-Malformed-Requests 134 integer FreeRADIUS
+ATTRIBUTE FreeRADIUS-Total-Auth-Invalid-Requests 135 integer FreeRADIUS
+ATTRIBUTE FreeRADIUS-Total-Auth-Dropped-Requests 136 integer FreeRADIUS
+ATTRIBUTE FreeRADIUS-Total-Auth-Unknown-Types 137 integer FreeRADIUS
+
+#
+# Global statistics for auth packets sent by the server to all home servers
+#
+ATTRIBUTE FreeRADIUS-Total-Proxy-Access-Requests 138 integer FreeRADIUS
+ATTRIBUTE FreeRADIUS-Total-Proxy-Access-Accepts 139 integer FreeRADIUS
+ATTRIBUTE FreeRADIUS-Total-Proxy-Access-Rejects 140 integer FreeRADIUS
+ATTRIBUTE FreeRADIUS-Total-Proxy-Access-Challenges 141 integer FreeRADIUS
+ATTRIBUTE FreeRADIUS-Total-Proxy-Auth-Responses 142 integer FreeRADIUS
+ATTRIBUTE FreeRADIUS-Total-Proxy-Auth-Duplicate-Requests 143 integer FreeRADIUS
+ATTRIBUTE FreeRADIUS-Total-Proxy-Auth-Malformed-Requests 144 integer FreeRADIUS
+ATTRIBUTE FreeRADIUS-Total-Proxy-Auth-Invalid-Requests 145 integer FreeRADIUS
+ATTRIBUTE FreeRADIUS-Total-Proxy-Auth-Dropped-Requests 146 integer FreeRADIUS
+ATTRIBUTE FreeRADIUS-Total-Proxy-Auth-Unknown-Types 147 integer FreeRADIUS
+
+#
+# Global accounting statistics for packets received by the server.
+#
+ATTRIBUTE FreeRADIUS-Total-Accounting-Requests 148 integer FreeRADIUS
+ATTRIBUTE FreeRADIUS-Total-Accounting-Responses 149 integer FreeRADIUS
+ATTRIBUTE FreeRADIUS-Total-Acct-Duplicate-Requests 150 integer FreeRADIUS
+ATTRIBUTE FreeRADIUS-Total-Acct-Malformed-Requests 151 integer FreeRADIUS
+ATTRIBUTE FreeRADIUS-Total-Acct-Invalid-Requests 152 integer FreeRADIUS
+ATTRIBUTE FreeRADIUS-Total-Acct-Dropped-Requests 153 integer FreeRADIUS
+ATTRIBUTE FreeRADIUS-Total-Acct-Unknown-Types 154 integer FreeRADIUS
+
+#
+# Global statistics for acct packets sent by the server to all home servers
+#
+ATTRIBUTE FreeRADIUS-Total-Proxy-Accounting-Requests 155 integer FreeRADIUS
+ATTRIBUTE FreeRADIUS-Total-Proxy-Accounting-Responses 156 integer FreeRADIUS
+ATTRIBUTE FreeRADIUS-Total-Proxy-Acct-Duplicate-Requests 157 integer FreeRADIUS
+ATTRIBUTE FreeRADIUS-Total-Proxy-Acct-Malformed-Requests 158 integer FreeRADIUS
+ATTRIBUTE FreeRADIUS-Total-Proxy-Acct-Invalid-Requests 159 integer FreeRADIUS
+ATTRIBUTE FreeRADIUS-Total-Proxy-Acct-Dropped-Requests 160 integer FreeRADIUS
+ATTRIBUTE FreeRADIUS-Total-Proxy-Acct-Unknown-Types 161 integer FreeRADIUS
+
+#
+# Internal queues. Different packet types are put into different queues.
+#
+ATTRIBUTE FreeRADIUS-Queue-Len-Internal 162 integer FreeRADIUS
+ATTRIBUTE FreeRADIUS-Queue-Len-Proxy 163 integer FreeRADIUS
+ATTRIBUTE FreeRADIUS-Queue-Len-Auth 164 integer FreeRADIUS
+ATTRIBUTE FreeRADIUS-Queue-Len-Acct 165 integer FreeRADIUS
+ATTRIBUTE FreeRADIUS-Queue-Len-Detail 166 integer FreeRADIUS
+
+ATTRIBUTE FreeRADIUS-Stats-Client-IP-Address 167 ipaddr FreeRADIUS
+ATTRIBUTE FreeRADIUS-Stats-Client-Number 168 integer FreeRADIUS
+ATTRIBUTE FreeRADIUS-Stats-Client-Netmask 169 integer FreeRADIUS
+
+ATTRIBUTE FreeRADIUS-Stats-Server-IP-Address 170 ipaddr FreeRADIUS
+ATTRIBUTE FreeRADIUS-Stats-Server-Port 171 integer FreeRADIUS
+
+ATTRIBUTE FreeRADIUS-Stats-Server-Outstanding-Requests 172 integer FreeRADIUS
+ATTRIBUTE FreeRADIUS-Stats-Server-State 173 integer FreeRADIUS
+
+VALUE FreeRADIUS-Stats-Server-State Alive 0
+VALUE FreeRADIUS-Stats-Server-State Zombie 1
+VALUE FreeRADIUS-Stats-Server-State Dead 2
+
+#
+# When a home server is marked "dead" or "alive"
+#
+ATTRIBUTE FreeRADIUS-Stats-Server-Time-Of-Death 174 date FreeRADIUS
+ATTRIBUTE FreeRADIUS-Stats-Server-Time-Of-Life 175 date FreeRADIUS
+
+#
+# When this server was started. If start == hup, it hasn't been
+# hup'd yet. This is friendlier than having hup == 0 on start.
+#
+ATTRIBUTE FreeRADIUS-Stats-Start-Time 176 date FreeRADIUS
+ATTRIBUTE FreeRADIUS-Stats-HUP-Time 177 date FreeRADIUS
+
+#
+# Exponential moving average of home server response time
+# Window-1 is the average is calculated over "window" packets.
+# Window-10 is the average is calculated over "10 * window" packets.
+#
+# Both Window-1 and Window-10 are times in microseconds
+# (1/1000000 of a second).
+#
+ATTRIBUTE FreeRADIUS-Server-EMA-Window 178 integer FreeRADIUS
+ATTRIBUTE FreeRADIUS-Server-EMA-USEC-Window-1 179 integer FreeRADIUS
+ATTRIBUTE FreeRADIUS-Server-EMA-USEC-Window-10 180 integer FreeRADIUS
+
diff --git a/scripts/snmp-proxy/freeradius-snmp.pl b/scripts/snmp-proxy/freeradius-snmp.pl
new file mode 100644
index 0000000..f30fc7d
--- /dev/null
+++ b/scripts/snmp-proxy/freeradius-snmp.pl
@@ -0,0 +1,585 @@
+#!/usr/bin/perl
+#
+# Copyright (C) 2008 Sky Network Services.
+# Copyright (C) 2022 Network RADIUS.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the same terms as Perl itself.
+#
+use strict;
+use warnings;
+
+use threads;
+use threads::shared;
+
+use Net::Radius::Packet;
+use Net::Radius::Dictionary;
+use NetSNMP::agent qw/:all/;
+use NetSNMP::ASN qw/:all/;
+use Socket qw(inet_ntop);
+use IO::Socket::INET;
+use Digest::HMAC_MD5;
+use Log::Log4perl qw/:easy/;
+#use Data::Dumper;
+#$Data::Dumper::Indent = 1;
+#$Data::Dumper::Sortkeys = 1;
+#$| = 1;
+
+my $cfg = {
+ snmp => {
+ agent => {
+ Name => 'freeradius-snmp',
+ AgentX => 1,
+ },
+ oid_root => '1.3.6.1.2.1.67',
+ oid_sub => {
+ 1 => [qw/auth proxyauth/],
+ 2 => [qw/acct proxyacct/],
+ },
+ },
+
+ radius => {
+ host => 'localhost',
+ port => 18120,
+ secret => 'adminsecret',
+# dictionary => '../radiusd/share/dictionary',
+ dictionary => 'dictionary.hacked',
+ refresh_rate => 20,
+ },
+
+ log => {
+ level => $WARN, # $DEBUG, $ERROR, etc.
+ layout => '%d{ISO8601} <%p> (%L) %m%n',
+ file => 'STDERR'
+ },
+
+ clients => 1, # Or 0 to disable
+};
+
+Log::Log4perl->easy_init($cfg->{log});
+
+INFO 'starting';
+my $running :shared;
+my %snmp_data :shared;
+my @snmp_data_k :shared;
+my %snmp_next :shared;
+
+INFO 'initializing snmp';
+my $agent = new NetSNMP::agent(%{$cfg->{snmp}->{agent}});
+
+radius_stats_init();
+$running = 1;
+
+$SIG{INT} = sub {
+ INFO 'stopping';
+ $running = 0;
+};
+
+#
+# Background updater thread
+#
+INFO 'launching radius client thread';
+threads->create(\&radius_updater);
+
+#
+# We export only the radiusAuthServ and radiusAccServ subtree
+#
+$agent->register(
+ $cfg->{snmp}->{agent}->{Name},
+ $cfg->{snmp}->{oid_root}.'.'.$_, \&snmp_handler) or die
+ foreach keys %{$cfg->{snmp}->{oid_sub}};
+
+INFO 'entering client main loop';
+$agent->agent_check_and_process(1) while $running;
+
+$agent->shutdown();
+
+$_->join() for threads->list();
+
+
+#
+# Initialize common radius client stuff
+#
+sub radius_stats_init {
+ our ( $d, $s, $rid );
+
+ $d = new Net::Radius::Dictionary;
+ $d->readfile($cfg->{radius}->{dictionary});
+ srand ($$ ^ time);
+ $rid = int rand 255;
+
+ $s = new IO::Socket::INET(
+ PeerHost => $cfg->{radius}->{host},
+ PeerPort => $cfg->{radius}->{port},
+ Proto => 'udp',
+ Timeout => 5) or die;
+
+}
+
+#
+# Build server status packet, send it, fetch and parse the result
+#
+sub radius_stats_get {
+ my ($type, %args) = @_;
+
+ our ($d, $s, $rid);
+
+ my $p_req = new Net::Radius::Packet $d;
+ $p_req->set_code('Status-Server');
+ $p_req->set_vsattr('FreeRADIUS', 'FreeRADIUS-Statistics-Type', $type);
+ $p_req->set_vsattr('FreeRADIUS', $_, $args{$_}) foreach keys %args;
+
+ #
+ # Update id
+ #
+ $p_req->set_identifier($rid++);
+ $p_req->set_authenticator(pack 'C*', map { int rand 255 } 0..15);
+
+ #
+ # Recalc authenticator
+ #
+ $p_req->set_attr('Message-Authenticator', "\0"x16, 1);
+ $p_req->set_attr('Message-Authenticator', Digest::HMAC_MD5::hmac_md5($p_req->pack, $cfg->{radius}->{secret}), 1);
+
+ #
+ # Send brand new and shiny request
+ #
+ $s->send($p_req->pack) or die;
+
+ my $p_data;
+ if (defined $s->recv($p_data, 2048)) {
+ my $p_res = new Net::Radius::Packet $d, $p_data;
+
+ my %response = map {
+ $_ => $p_res->vsattr($d->vendor_num('FreeRADIUS'), $_)->[0]
+ } $p_res->vsattributes($d->vendor_num('FreeRADIUS'));
+ return \%response;
+
+ }
+ else {
+ warn "no answer, $!\n";
+ return undef;
+ }
+
+}
+
+#
+# Wrappers for specific types of stats
+#
+sub radius_stats_get_global { return radius_stats_get(0x1f); }
+sub radius_stats_get_client { return radius_stats_get(0x3f, 'FreeRADIUS-Stats-Client-Number' => $_[0]); }
+
+#
+# Main loop of thread fetching status from freeradius server
+#
+sub radius_updater {
+
+ while ($running) {
+ INFO 'fetching new data';
+ my $main_stat = radius_stats_get_global();
+
+ if (defined $main_stat) {
+ my @clients_stat = ();
+
+ if ($cfg->{clients}) {
+ my $client_id = 0;
+
+ while (1) {
+ my $client_stat = radius_stats_get_client($client_id);
+ last unless exists $client_stat->{'FreeRADIUS-Stats-Client-IP-Address'} || exists $client_stat->{'FreeRADIUS-Stats-Client-IPv6-Address'};
+ push @clients_stat, $client_stat;
+ $client_id += 1;
+ }
+ }
+
+ INFO 'got data, updating stats';
+ radius_snmp_stats($main_stat, \@clients_stat);
+
+ }
+ else {
+ WARN 'problem with fetching data';
+ }
+
+ INFO 'stats updated, sleeping';
+ my $now = time;
+ my $next_stats_time = $now + $cfg->{radius}->{refresh_rate};
+ do {
+ sleep 1;
+ $now = time;
+ } while ($now < $next_stats_time && $running);
+
+ }
+
+}
+
+#
+# Helper to get a dotted string from NetSNMP::OID
+#
+sub oid_s { return join '.', $_[0]->to_array; }
+
+#
+# Handler for snmp requests from master agent
+#
+sub snmp_handler {
+ DEBUG 'got new request';
+ my ($handler, $registration_info, $request_info, $requests) = @_;
+
+ lock %snmp_data;
+ lock @snmp_data_k;
+ lock %snmp_next;
+
+ for (my $request = $requests; $request; $request = $request->next()) {
+ INFO 'request type '.$request_info->getMode.' for oid: '.oid_s($request->getOID);
+
+ if ($request_info->getMode == MODE_GET) {
+ my $oid_s = oid_s($request->getOID);
+ if (exists $snmp_data{$oid_s}) {
+ $request->setValue($snmp_data{$oid_s}->[0], ''.$snmp_data{$oid_s}->[1]);
+ }
+
+ }
+ elsif ($request_info->getMode == MODE_GETNEXT) {
+
+ #
+ # Do a fast lookup if we can...
+ #
+ my $oid = $snmp_next{oid_s($request->getOID)};
+
+ #
+ # ... otherwise take the slow route
+ #
+ unless (defined $oid) {
+ foreach ( @snmp_data_k ) {
+ #the keys is sorted in ascending order, so we are looking for
+ #first value bigger than one in request
+ if ($request->getOID < NetSNMP::OID->new($_)) {
+ $oid = $_;
+ last;
+ }
+ }
+ }
+
+ next unless $oid;
+
+ $request->setValue($snmp_data{$oid}->[0], ''.$snmp_data{$oid}->[1]);
+ $request->setOID($oid);
+
+ }
+ else {
+ $request->setError($request_info, SNMP_ERR_READONLY); # No write support
+ }
+ }
+ DEBUG 'finished processing the request';
+}
+
+#
+# Init part of subtree for handling radius AUTH statistics
+#
+sub radius_snmp_stats_init_auth {
+ my ($snmp_data_n, $oid, $clients) = @_;
+
+ @{$snmp_data_n->{$oid.'.1.1.1.1'} = &share([])} = (ASN_OCTET_STR, ''); # radiusAuthServIdent
+ @{$snmp_data_n->{$oid.'.1.1.1.2'} = &share([])} = (ASN_TIMETICKS, 0); # radiusAuthServUpTime
+ @{$snmp_data_n->{$oid.'.1.1.1.3'} = &share([])} = (ASN_TIMETICKS, 0); # radiusAuthServResetTime
+ @{$snmp_data_n->{$oid.'.1.1.1.4'} = &share([])} = (ASN_INTEGER, 0); # radiusAuthServConfigReset
+ @{$snmp_data_n->{$oid.'.1.1.1.5'} = &share([])} = (ASN_COUNTER, 0); # radiusAuthServTotalAccessRequests
+ @{$snmp_data_n->{$oid.'.1.1.1.6'} = &share([])} = (ASN_COUNTER, 0); # radiusAuthServTotalInvalidRequests
+ @{$snmp_data_n->{$oid.'.1.1.1.7'} = &share([])} = (ASN_COUNTER, 0); # radiusAuthServTotalDupAccessRequests
+ @{$snmp_data_n->{$oid.'.1.1.1.8'} = &share([])} = (ASN_COUNTER, 0); # radiusAuthServTotalAccessAccepts
+ @{$snmp_data_n->{$oid.'.1.1.1.9'} = &share([])} = (ASN_COUNTER, 0); # radiusAuthServTotalAccessRejects
+ @{$snmp_data_n->{$oid.'.1.1.1.10'} = &share([])} = (ASN_COUNTER, 0); # radiusAuthServTotalAccessChallenges
+ @{$snmp_data_n->{$oid.'.1.1.1.11'} = &share([])} = (ASN_COUNTER, 0); # radiusAuthServTotalMalformedAccessRequests
+ @{$snmp_data_n->{$oid.'.1.1.1.12'} = &share([])} = (ASN_COUNTER, 0); # radiusAuthServTotalBadAuthenticators
+ @{$snmp_data_n->{$oid.'.1.1.1.13'} = &share([])} = (ASN_COUNTER, 0); # radiusAuthServTotalPacketsDropped
+ @{$snmp_data_n->{$oid.'.1.1.1.14'} = &share([])} = (ASN_COUNTER, 0); # radiusAuthServTotalUnknownTypes
+
+ #
+ # radiusAuthClientExtTable
+ #
+ for (1 .. scalar @$clients) {
+
+ my $addrtype;
+ my $addr;
+ if (exists $clients->[$_-1]->{'FreeRADIUS-Stats-Client-IP-Address'}) {
+ $addrtype = 1;
+ $addr = $clients->[$_-1]->{'FreeRADIUS-Stats-Client-IP-Address'};
+ }
+ elsif (exists $clients->[$_-1]->{'FreeRADIUS-Stats-Client-IPv6-Address'}) {
+ $addrtype = 2;
+ $addr = inet_ntop(AF_INET6, $clients->[$_-1]->{'FreeRADIUS-Stats-Client-IPv6-Address'});
+ }
+ else {
+ next;
+ }
+
+ @{$snmp_data_n->{$oid.'.1.1.1.16.1.1.'.$_} = &share([])} = (ASN_INTEGER, $_); # radiusAuthClientExtIndex
+ @{$snmp_data_n->{$oid.'.1.1.1.16.1.2.'.$_} = &share([])} = (ASN_INTEGER, $addrtype); # radiusAuthClientInetAddressType
+ @{$snmp_data_n->{$oid.'.1.1.1.16.1.3.'.$_} = &share([])} = (ASN_OCTET_STR, $addr); # radiusAuthClientInetAddress
+ @{$snmp_data_n->{$oid.'.1.1.1.16.1.4.'.$_} = &share([])} = (ASN_OCTET_STR, $clients->[$_-1]->{'FreeRADIUS-Stats-Client-Number'}); # radiusAuthClientExtID
+ @{$snmp_data_n->{$oid.'.1.1.1.16.1.5.'.$_} = &share([])} = (ASN_COUNTER, 0); # radiusAuthServExtAccessRequests
+ @{$snmp_data_n->{$oid.'.1.1.1.16.1.6.'.$_} = &share([])} = (ASN_COUNTER, 0); # radiusAuthServExtDupAccessRequests
+ @{$snmp_data_n->{$oid.'.1.1.1.16.1.7.'.$_} = &share([])} = (ASN_COUNTER, 0); # radiusAuthServExtAccessAccepts
+ @{$snmp_data_n->{$oid.'.1.1.1.16.1.8.'.$_} = &share([])} = (ASN_COUNTER, 0); # radiusAuthServExtAccessRejects
+ @{$snmp_data_n->{$oid.'.1.1.1.16.1.9.'.$_} = &share([])} = (ASN_COUNTER, 0); # radiusAuthServExtAccessChallenges
+ @{$snmp_data_n->{$oid.'.1.1.1.16.1.10.'.$_} = &share([])} = (ASN_COUNTER, 0); # radiusAuthServExtMalformedAccessRequests
+ @{$snmp_data_n->{$oid.'.1.1.1.16.1.11.'.$_} = &share([])} = (ASN_COUNTER, 0); # radiusAuthServExtBadAuthenticators
+ @{$snmp_data_n->{$oid.'.1.1.1.16.1.12.'.$_} = &share([])} = (ASN_COUNTER, 0); # radiusAuthServExtPacketsDropped
+ @{$snmp_data_n->{$oid.'.1.1.1.16.1.13.'.$_} = &share([])} = (ASN_COUNTER, 0); # radiusAuthServExtUnknownTypes
+ @{$snmp_data_n->{$oid.'.1.1.1.16.1.14.'.$_} = &share([])} = (ASN_TIMETICKS, 0); # radiusAuthServerCounterDiscontinuity
+
+ }
+}
+
+#
+# Init part of subtree for handling radius ACCT statistics
+#
+sub radius_snmp_stats_init_acct {
+ my ( $snmp_data_n, $oid, $clients ) = @_;
+
+ @{$snmp_data_n->{$oid.'.1.1.1.1'} = &share([])} = (ASN_OCTET_STR, ''); # radiusAccServIdent
+ @{$snmp_data_n->{$oid.'.1.1.1.2'} = &share([])} = (ASN_TIMETICKS, 0); # radiusAccServUpTime
+ @{$snmp_data_n->{$oid.'.1.1.1.3'} = &share([])} = (ASN_TIMETICKS, 0); # radiusAccServResetTime
+ @{$snmp_data_n->{$oid.'.1.1.1.4'} = &share([])} = (ASN_INTEGER, 0); # radiusAccServConfigReset
+ @{$snmp_data_n->{$oid.'.1.1.1.5'} = &share([])} = (ASN_COUNTER, 0); # radiusAccServTotalRequests
+ @{$snmp_data_n->{$oid.'.1.1.1.6'} = &share([])} = (ASN_COUNTER, 0); # radiusAccServTotalInvalidRequests
+ @{$snmp_data_n->{$oid.'.1.1.1.7'} = &share([])} = (ASN_COUNTER, 0); # radiusAccServTotalDupRequests
+ @{$snmp_data_n->{$oid.'.1.1.1.8'} = &share([])} = (ASN_COUNTER, 0); # radiusAccServTotalResponses
+ @{$snmp_data_n->{$oid.'.1.1.1.9'} = &share([])} = (ASN_COUNTER, 0); # radiusAccServTotalMalformedRequests
+ @{$snmp_data_n->{$oid.'.1.1.1.10'} = &share([])} = (ASN_COUNTER, 0); # radiusAccServTotalBadAuthenticators
+ @{$snmp_data_n->{$oid.'.1.1.1.11'} = &share([])} = (ASN_COUNTER, 0); # radiusAccServTotalPacketsDropped
+ @{$snmp_data_n->{$oid.'.1.1.1.12'} = &share([])} = (ASN_COUNTER, 0); # radiusAccServTotalNoRecords
+ @{$snmp_data_n->{$oid.'.1.1.1.13'} = &share([])} = (ASN_COUNTER, 0); # radiusAccServTotalUnknownTypes
+
+ #
+ # radiusAccClientExtTable
+ #
+ for (1 .. scalar @$clients) {
+
+ my $addrtype;
+ my $addr;
+ if (exists $clients->[$_-1]->{'FreeRADIUS-Stats-Client-IP-Address'}) {
+ $addrtype = 1;
+ $addr = $clients->[$_-1]->{'FreeRADIUS-Stats-Client-IP-Address'};
+ }
+ elsif (exists $clients->[$_-1]->{'FreeRADIUS-Stats-Client-IPv6-Address'}) {
+ $addrtype = 2;
+ $addr = inet_ntop(AF_INET6, $clients->[$_-1]->{'FreeRADIUS-Stats-Client-IPv6-Address'});
+ }
+ else {
+ next;
+ }
+
+ @{$snmp_data_n->{$oid.'.1.1.1.15.1.1.'.$_} = &share([])} = (ASN_INTEGER, $_); # radiusAccClientExtIndex
+ @{$snmp_data_n->{$oid.'.1.1.1.15.1.2.'.$_} = &share([])} = (ASN_INTEGER, $addrtype); # radiusAccClientInetAddressType
+ @{$snmp_data_n->{$oid.'.1.1.1.15.1.3.'.$_} = &share([])} = (ASN_OCTET_STR, $addr); # radiusAccClientInetAddress
+ @{$snmp_data_n->{$oid.'.1.1.1.15.1.4.'.$_} = &share([])} = (ASN_OCTET_STR, $clients->[$_-1]->{'FreeRADIUS-Stats-Client-Number'}); # radiusAccClientExtID
+ @{$snmp_data_n->{$oid.'.1.1.1.15.1.5.'.$_} = &share([])} = (ASN_COUNTER, 0); # radiusAccServExtPacketsDropped
+ @{$snmp_data_n->{$oid.'.1.1.1.15.1.6.'.$_} = &share([])} = (ASN_COUNTER, 0); # radiusAccServExtRequests
+ @{$snmp_data_n->{$oid.'.1.1.1.15.1.7.'.$_} = &share([])} = (ASN_COUNTER, 0); # radiusAccServExtDupRequests
+ @{$snmp_data_n->{$oid.'.1.1.1.15.1.8.'.$_} = &share([])} = (ASN_COUNTER, 0); # radiusAccServResponses
+ @{$snmp_data_n->{$oid.'.1.1.1.15.1.9.'.$_} = &share([])} = (ASN_COUNTER, 0); # radiusAccServExtBadAuthenticators
+ @{$snmp_data_n->{$oid.'.1.1.1.15.1.10.'.$_} = &share([])} = (ASN_COUNTER, 0); # radiusAccServExtMalformedRequests
+ @{$snmp_data_n->{$oid.'.1.1.1.15.1.11.'.$_} = &share([])} = (ASN_COUNTER, 0); # radiusAccServExtNoRecords
+ @{$snmp_data_n->{$oid.'.1.1.1.15.1.12.'.$_} = &share([])} = (ASN_COUNTER, 0); # radiusAccServExtUnknownTypes
+ @{$snmp_data_n->{$oid.'.1.1.1.15.1.13.'.$_} = &share([])} = (ASN_TIMETICKS, 0); # radiusAccServerCounterDiscontinuity
+
+ }
+}
+
+#
+# Fill part of subtree with data from radius AUTH statistics
+#
+sub radius_snmp_stats_fill_auth {
+ my ($snmp_data_n, $oid, $prefix, $main, $clients) = @_;
+
+ my $time = time;
+
+ $snmp_data_n->{$oid.'.1.1.1.1'}->[1] = 'snmp(over)radius';
+ $snmp_data_n->{$oid.'.1.1.1.2'}->[1] = ($time - $main->{'FreeRADIUS-Stats-Start-Time'})*100;
+ $snmp_data_n->{$oid.'.1.1.1.3'}->[1] = ($time - $main->{'FreeRADIUS-Stats-HUP-Time'})*100;
+ $snmp_data_n->{$oid.'.1.1.1.4'}->[1] = 0;
+ $snmp_data_n->{$oid.'.1.1.1.5'}->[1] += $main->{$prefix.'Access-Requests'};
+ $snmp_data_n->{$oid.'.1.1.1.6'}->[1] += $main->{$prefix.'Auth-Invalid-Requests'};
+ $snmp_data_n->{$oid.'.1.1.1.7'}->[1] += $main->{$prefix.'Auth-Duplicate-Requests'};
+ $snmp_data_n->{$oid.'.1.1.1.8'}->[1] += $main->{$prefix.'Access-Accepts'};
+ $snmp_data_n->{$oid.'.1.1.1.9'}->[1] += $main->{$prefix.'Access-Rejects'};
+ $snmp_data_n->{$oid.'.1.1.1.10'}->[1] += $main->{$prefix.'Access-Challenges'};
+ $snmp_data_n->{$oid.'.1.1.1.11'}->[1] += $main->{$prefix.'Auth-Malformed-Requests'};
+ $snmp_data_n->{$oid.'.1.1.1.12'}->[1] += 0;
+ $snmp_data_n->{$oid.'.1.1.1.13'}->[1] += $main->{$prefix.'Auth-Dropped-Requests'};
+ $snmp_data_n->{$oid.'.1.1.1.14'}->[1] += $main->{$prefix.'Auth-Unknown-Types'};
+
+ for (1 .. scalar @$clients) {
+ next unless exists $clients->[$_-1]->{'FreeRADIUS-Stats-Client-IP-Address'} || exists $clients->[$_-1]->{'FreeRADIUS-Stats-Client-IPv6-Address'};
+ $snmp_data_n->{$oid.'.1.1.1.16.1.5.'.$_}->[1] += $clients->[$_-1]->{$prefix.'Access-Requests'} || 0;
+ $snmp_data_n->{$oid.'.1.1.1.16.1.6.'.$_}->[1] += $clients->[$_-1]->{$prefix.'Auth-Duplicate-Requests'} || 0;
+ $snmp_data_n->{$oid.'.1.1.1.16.1.7.'.$_}->[1] += $clients->[$_-1]->{$prefix.'Access-Accepts'} || 0;
+ $snmp_data_n->{$oid.'.1.1.1.16.1.8.'.$_}->[1] += $clients->[$_-1]->{$prefix.'Access-Rejects'} || 0;
+ $snmp_data_n->{$oid.'.1.1.1.16.1.9.'.$_}->[1] += $clients->[$_-1]->{$prefix.'Access-Challenges'} || 0;
+ $snmp_data_n->{$oid.'.1.1.1.16.1.10.'.$_}->[1] += $clients->[$_-1]->{$prefix.'Auth-Malformed-Requests'} || 0;
+ $snmp_data_n->{$oid.'.1.1.1.16.1.11.'.$_}->[1] += 0;
+ $snmp_data_n->{$oid.'.1.1.1.16.1.12.'.$_}->[1] += $clients->[$_-1]->{$prefix.'Auth-Dropped-Requests'} || 0;
+ $snmp_data_n->{$oid.'.1.1.1.16.1.13.'.$_}->[1] += $clients->[$_-1]->{$prefix.'Auth-Unknown-Types'} || 0;
+ $snmp_data_n->{$oid.'.1.1.1.16.1.14.'.$_}->[1] += 0;
+ }
+}
+
+#
+# Fill part of subtree with data from radius ACCT statistics
+#
+sub radius_snmp_stats_fill_acct {
+ my ( $snmp_data_n, $oid, $prefix, $main, $clients ) = @_;
+
+ my $time = time;
+
+ $snmp_data_n->{$oid.'.1.1.1.1'}->[1] = 'snmp(over)radius';
+ $snmp_data_n->{$oid.'.1.1.1.2'}->[1] = ($time - $main->{'FreeRADIUS-Stats-Start-Time'})*100;
+ $snmp_data_n->{$oid.'.1.1.1.3'}->[1] = ($time - $main->{'FreeRADIUS-Stats-HUP-Time'})*100;
+ $snmp_data_n->{$oid.'.1.1.1.4'}->[1] = 0;
+ $snmp_data_n->{$oid.'.1.1.1.5'}->[1] += $main->{$prefix.'Accounting-Requests'};
+ $snmp_data_n->{$oid.'.1.1.1.6'}->[1] += $main->{$prefix.'Acct-Invalid-Requests'};
+ $snmp_data_n->{$oid.'.1.1.1.7'}->[1] += $main->{$prefix.'Acct-Duplicate-Requests'};
+ $snmp_data_n->{$oid.'.1.1.1.8'}->[1] += $main->{$prefix.'Accounting-Responses'};
+ $snmp_data_n->{$oid.'.1.1.1.9'}->[1] += $main->{$prefix.'Acct-Malformed-Requests'};
+ $snmp_data_n->{$oid.'.1.1.1.10'}->[1] += 0;
+ $snmp_data_n->{$oid.'.1.1.1.11'}->[1] += $main->{$prefix.'Acct-Dropped-Requests'};
+ $snmp_data_n->{$oid.'.1.1.1.12'}->[1] += 0;
+ $snmp_data_n->{$oid.'.1.1.1.13'}->[1] += $main->{$prefix.'Acct-Unknown-Types'};
+
+ for (1 .. scalar @$clients) {
+ next unless exists $clients->[$_-1]->{'FreeRADIUS-Stats-Client-IP-Address'} || exists $clients->[$_-1]->{'FreeRADIUS-Stats-Client-IPv6-Address'};
+ $snmp_data_n->{$oid.'.1.1.1.15.1.5.'.$_}->[1] += $clients->[$_-1]->{$prefix.'Acct-Dropped-Requests'} || 0;
+ $snmp_data_n->{$oid.'.1.1.1.15.1.6.'.$_}->[1] += $clients->[$_-1]->{$prefix.'Accounting-Requests'} || 0;
+ $snmp_data_n->{$oid.'.1.1.1.15.1.7.'.$_}->[1] += $clients->[$_-1]->{$prefix.'Acct-Duplicate-Requests'} || 0;
+ $snmp_data_n->{$oid.'.1.1.1.15.1.8.'.$_}->[1] += $clients->[$_-1]->{$prefix.'Accounting-Responses'} || 0;
+ $snmp_data_n->{$oid.'.1.1.1.15.1.9.'.$_}->[1] += 0;
+ $snmp_data_n->{$oid.'.1.1.1.15.1.10.'.$_}->[1] += $clients->[$_-1]->{$prefix.'Acct-Malformed-Requests'} || 0;
+ $snmp_data_n->{$oid.'.1.1.1.15.1.11.'.$_}->[1] += 0;
+ $snmp_data_n->{$oid.'.1.1.1.15.1.12.'.$_}->[1] += $clients->[$_-1]->{$prefix.'Acct-Unknown-Types'} || 0;
+ $snmp_data_n->{$oid.'.1.1.1.15.1.13.'.$_}->[1] += 0;
+ }
+}
+
+#
+# Update statistics
+#
+sub radius_snmp_stats {
+ my ($main, $clients) = @_;
+
+ my %snmp_data_n;
+
+ #
+ # We have to go through all oid's
+ #
+ foreach my $oid_s ( keys %{$cfg->{snmp}->{oid_sub}} ) {
+
+ #
+ # We're rebuilding the tree for data. We could do it only once, but it
+ # will change when we will start handling more dynamic tree (clients)
+ #
+ my %types = map { $_ => 1 } map { /(?:proxy)?(\w+)/; $1 } @{$cfg->{snmp}->{oid_sub}->{$oid_s}};
+ WARN 'two conflicting types for oid '.$oid_s if scalar keys %types > 1;
+
+ if ((keys %types)[0] eq 'auth') {
+ radius_snmp_stats_init_auth(\%snmp_data_n, $cfg->{snmp}->{oid_root}.'.'.$oid_s, $clients);
+ }
+ elsif ( (keys %types)[0] eq 'acct' ) {
+ radius_snmp_stats_init_acct(\%snmp_data_n, $cfg->{snmp}->{oid_root}.'.'.$oid_s, $clients);
+ }
+ else {
+ WARN 'unknown subtree type '.(keys %types)[0];
+ }
+
+ #
+ # Refill the statistics
+ #
+ foreach my $type (@{$cfg->{snmp}->{oid_sub}->{$oid_s}}) {
+ if ($type eq 'auth') {
+ radius_snmp_stats_fill_auth(
+ \%snmp_data_n, $cfg->{snmp}->{oid_root}.'.'.$oid_s,
+ 'FreeRADIUS-Total-', $main, $clients);
+ }
+ elsif ($type eq 'proxyauth') {
+ radius_snmp_stats_fill_auth(
+ \%snmp_data_n, $cfg->{snmp}->{oid_root}.'.'.$oid_s,
+ 'FreeRADIUS-Total-Proxy-', $main, $clients);
+ }
+ elsif ($type eq 'acct') {
+ radius_snmp_stats_fill_acct(
+ \%snmp_data_n, $cfg->{snmp}->{oid_root}.'.'.$oid_s,
+ 'FreeRADIUS-Total-', $main, $clients);
+ }
+ elsif ($type eq 'proxyacct') {
+ radius_snmp_stats_fill_acct(
+ \%snmp_data_n, $cfg->{snmp}->{oid_root}.'.'.$oid_s,
+ 'FreeRADIUS-Total-Proxy-', $main, $clients);
+ }
+ else {
+ WARN 'unknown subtree type '.$type;
+ }
+
+ }
+ }
+
+ #
+ # Copy the rebuilt tree to the shared variables
+ #
+ my @k = map { oid_s($_) } sort { $a <=> $b } map { NetSNMP::OID->new($_) } keys %snmp_data_n;
+ my %snmp_next_n = ();
+ $snmp_next_n{$k[$_]} = $k[$_+1] for (0 .. $#k-1);
+
+ lock %snmp_data;
+ lock @snmp_data_k;
+ lock %snmp_next;
+
+ %snmp_data = %snmp_data_n;
+ @snmp_data_k = @k;
+ %snmp_next = %snmp_next_n;
+
+}
+
+=head1 NAME
+
+freeradius snmp agentx subagent
+
+=head1 VERSION
+
+=head1 SYNOPSIS
+
+make sure snmpd is agentx master (snmpd.conf):
+master agentx
+
+run the script (no demonizing support yet):
+
+./freeradius-snmp.pl
+
+then you can walk the tree (default oid):
+
+snmpbulkwalk -On -v2c -cpublic localhost .1.3.6.1.2.1.67
+
+if per-client stats collection is enabled then you can do the following:
+
+snmptable -v2c -cpublic localhost .1.3.6.1.2.1.67.1.1.1.1.16
+snmptable -v2c -cpublic localhost .1.3.6.1.2.1.67.2.1.1.1.15
+
+=head1 DESCRIPTION
+
+=head1 DEPENDENCIES
+
+Net-Radius (either 1.56 + net-radius-freeradius-dictionary.diff to use freeradius dictionaries
+ or vanilla upstream one + dictionary.hacked)
+NetSNMP perl modules (available with net-snmp distribution)
+Digest::HMAC
+Log::Log4perl
+
+=head1 AUTHOR
+
+Stanislaw Sawa <stanislaw.sawa(at)sns.bskyb.com>
+
+=head1 COPYRIGHT
+
+Copyright (C) 2008 Sky Network Services.
+Copyright (C) 2022 Network RADIUS.
+
+This program is free software; you can redistribute it and/or modify it
+under the same terms as Perl itself.
diff --git a/scripts/snmp-proxy/net-radius-freeradius-dictionary.diff b/scripts/snmp-proxy/net-radius-freeradius-dictionary.diff
new file mode 100644
index 0000000..f379cf4
--- /dev/null
+++ b/scripts/snmp-proxy/net-radius-freeradius-dictionary.diff
@@ -0,0 +1,81 @@
+--- Net-Radius-1.56.orig/Radius/Dictionary.pm 2008-06-20 14:08:57.000000000 +0100
++++ Net-Radius-1.56.1/Radius/Dictionary.pm 2008-06-20 15:54:33.000000000 +0100
+@@ -30,14 +30,23 @@
+
+ sub readfile {
+ my ($self, $filename) = @_;
++ my $dict;
+
+- open DICT, "<$filename";
++ open $dict, "<$filename";
+
+- while (defined(my $l = <DICT>)) {
++ my @in_vendor = ();
++
++ while (defined(my $l = <$dict>)) {
+ next if $l =~ /^\#/;
+ next unless my @l = split /\s+/, $l;
+
+- if ($l[0] =~ m/^vendor$/i)
++ if ($l[0] =~ m/^\$include$/i)
++ {
++ my @fn = split /\//, $filename;
++ $fn[$#fn] = $l[1];
++ $self->readfile(join '/', @fn);
++ }
++ elsif ($l[0] =~ m/^vendor$/i)
+ {
+ if (defined $l[1] and defined $l[2] and $l[2] =~ /^[xo0-9]+$/)
+ {
+@@ -53,8 +62,42 @@
+ warn "Garbled VENDOR line $l\n";
+ }
+ }
++ elsif ($l[0] =~ m/^begin-vendor$/i)
++ {
++ if ( defined $l[1] )
++ {
++ push @in_vendor, $l[1];
++ }
++ else
++ {
++ warn "Garbled BEGIN-VENDOR line $l\n";
++ }
++ }
++ elsif ($l[0] =~ m/^end-vendor$/i)
++ {
++ if ( defined $l[1] )
++ {
++ if ( $in_vendor[$#in_vendor] eq $l[1] ) {
++ pop @in_vendor;
++ }else {
++ warn "mismatched END-VENDOR line $l\n";
++ }
++ }
++ else
++ {
++ warn "Garbled END-VENDOR line $l\n";
++ }
++ }
+ elsif ($l[0] =~ m/^attribute$/i)
+ {
++ if (@l == 5) {
++ my @tags = grep { not ( m/^encrypt=\d$/ or m/^has_tag$/ ) } split /,/, pop @l;
++ push @l, join ',', @tags if scalar @tags;
++ }
++ if (@l == 4 and scalar @in_vendor) {
++ push @l, $in_vendor[$#in_vendor];
++ }
++
+ if (@l == 4)
+ {
+ $self->{attr}->{$l[1]} = [@l[2,3]];
+@@ -166,7 +209,7 @@
+ warn "Warning: Weird dictionary line: $l\n";
+ }
+ }
+- close DICT;
++ close $dict;
+ }
+
+ # Accessors for standard attributes
diff --git a/scripts/solaris/.gitignore b/scripts/solaris/.gitignore
new file mode 100644
index 0000000..91ef483
--- /dev/null
+++ b/scripts/solaris/.gitignore
@@ -0,0 +1 @@
+svc-radius
diff --git a/scripts/solaris/README.md b/scripts/solaris/README.md
new file mode 100644
index 0000000..8e1c02a
--- /dev/null
+++ b/scripts/solaris/README.md
@@ -0,0 +1,58 @@
+# Solaris startup scripts
+
+SMF is the Solaris version of upstart (or the reverse), it imports
+XML configuration file for services, and manages service
+dependencies. It will automatically restart daemons in they die,
+and provides a standard interface for checking the status of a
+service and administratively disabling/enabling it.
+
+
+# Installation/configuration
+
+## Solaris 10
+
+Do the following as the root user ``sudo -s``.
+
+Copy the service management script ``svc-radius`` to ``/lib/srv/method/``:
+
+```bash
+cp ./svc-radius /lib/svc/method/
+chown root:bin /lib/svc/method/svc-radius
+chmod 555 /lib/svc/method/svc-radius
+```
+
+Copy the ``radius.xml`` manifest to
+``/var/svc/manifest/network/``, and import it into SMF:
+
+```bash
+cp ./radius.xml /var/svc/manifest/network/
+svccfg import /var/svc/manifest/network/radius.xml
+```
+
+
+### Authorizing additional users
+
+First create an authorisation entry for the radius service:
+
+```bash
+echo "solaris.smf.manage.radius/server:::FreeRADIUS Server management::" >> /etc/security/auth_attr
+```
+
+Next instruct SMF to use RBAC for authorising actions on this
+particular service (only works with local accounts):
+
+```bash
+svccfg -s radius setprop general/action_authorization=astring: 'solaris.smf.manage.radius/server'
+```
+
+Then assign this authorisation to our one or more users:
+
+```bash
+usermod -A solaris.smf.manage.radius/server <user>
+```
+
+And finally test with (as authorized user):
+
+```bash
+svcs radius
+```
diff --git a/scripts/solaris/radius.xml b/scripts/solaris/radius.xml
new file mode 100644
index 0000000..d9b0506
--- /dev/null
+++ b/scripts/solaris/radius.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0"?>
+<!DOCTYPE service_bundle SYSTEM
+"/usr/share/lib/xml/dtd/service_bundle.dtd.1">
+<service_bundle type='manifest' name='radius'>
+<service
+ name='network/radius'
+ type='service'
+ version='1'>
+ <create_default_instance enabled='false' />
+ <single_instance/>
+
+ <dependency name='fs-local'
+ grouping='require_all'
+ restart_on='none'
+ type='service'>
+ <service_fmri value='svc:/system/filesystem/local' />
+ </dependency>
+
+ <dependency name='fs-autofs'
+ grouping='optional_all'
+ restart_on='none'
+ type='service'>
+ <service_fmri value='svc:/system/filesystem/autofs' />
+ </dependency>
+
+ <dependency name='net-loopback'
+ grouping='require_all'
+ restart_on='none'
+ type='service'>
+ <service_fmri value='svc:/network/loopback' />
+ </dependency>
+
+ <dependency name='net-physical'
+ grouping='require_all'
+ restart_on='none'
+ type='service'>
+ <service_fmri value='svc:/network/physical' />
+ </dependency>
+
+ <exec_method
+ type='method'
+ name='start'
+ exec='/lib/svc/method/svc-radius %m'
+ timeout_seconds='10' />
+ <exec_method
+ type='method'
+ name='stop'
+ exec='/lib/svc/method/svc-radius %m %{restarter/contract}'
+ timeout_seconds='10' />
+ <exec_method
+ type='method'
+ name='refresh'
+ exec='/lib/svc/method/svc-radius %m'
+ timeout_seconds='10' />
+
+ <stability value='Unstable' />
+ <template>
+ <common_name>
+ <loctext xml:lang='C'> radius
+ </loctext>
+ </common_name>
+ <documentation>
+ <manpage title='radius' section='1M'
+ manpath='/usr/share/man' />
+ </documentation>
+ </template>
+</service>
+</service_bundle>
diff --git a/scripts/solaris/svc-radius.in b/scripts/solaris/svc-radius.in
new file mode 100755
index 0000000..f5aee81
--- /dev/null
+++ b/scripts/solaris/svc-radius.in
@@ -0,0 +1,99 @@
+#!/bin/sh
+. /lib/svc/share/smf_include.sh
+#
+#
+# radiusd Start the radius daemon.
+#
+# 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) 2001-2012 The FreeRADIUS Project http://www.freeradius.org
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+sbindir=@sbindir@
+localstatedir=@localstatedir@
+logdir=@logdir@
+rundir=${localstatedir}/run/radiusd
+sysconfdir=@sysconfdir@
+
+#
+# If you have issues with OpenSSL, uncomment these next lines.
+#
+# Something similar may work for MySQL, and you may also
+# have to LD_PRELOAD libz.so
+#
+#LD_LIBRARY_PATH= -lcrypto -lssl -lcrypto
+#LD_RUN_PATH= -lcrypto -lssl -lcrypto:
+#LD_PRELOAD= -lcrypto -lssl -lcryptolibcrypto.so
+export LD_LIBRARY_PATH LD_RUN_PATH LD_PRELOAD
+
+RADIUSD=$sbindir/radiusd
+RADDBDIR=@raddbdir@
+DESC="FreeRADIUS"
+
+#
+# See 'man radiusd' for details on command-line options.
+#
+ARGS=""
+
+test -f $RADIUSD || exit $SMF_EXIT_ERR_CONFIG
+test -f $RADDBDIR/radiusd.conf || exit $SMF_EXIT_ERR_CONFIG
+
+#if [ ! -d $rundir ] ; then
+# mkdir $rundir
+# chown radmin:radius
+# chmod 775 $rundir
+#fi
+#
+#if [ ! -d $logdir ] ; then
+# mkdir $logdir
+# chown radmin:radius $logdir
+# chmod 770 $logdir
+# chmod g+s $logdir
+#fi
+#
+#if [ ! -f $logdir/radius.log ]; then
+# touch $logdir/radius.log
+#fi
+#
+#chown radmin:radius $logdir/radius.log
+#chmod 660 $logdir/radius.log
+
+case "$1" in
+ start)
+ echo -n "Starting $DESC: "
+ $RADIUSD $ARGS
+ echo "radiusd"
+ ;;
+ stop)
+ echo -n "Stopping $DESC: "
+ smf_kill_contract $2 TERM 1
+ [ $? -ne 0 ] && exit 1
+ echo "radiusd."
+ ;;
+ refresh)
+ echo "Reloading $DESC configuration files."
+ [ -f $rundir/radiusd.pid ] && kill -HUP `cat $rundir/radiusd.pid`
+ ;;
+ check)
+ $RADIUSD -CX $ARGS
+ exit $?
+ ;;
+ *)
+ echo "Usage: $0 {start|stop|refresh|check}"
+ exit 1
+esac
+
+exit $SMF_EXIT_OK
diff --git a/scripts/sql/align_sql_pools.pl b/scripts/sql/align_sql_pools.pl
new file mode 100755
index 0000000..04d2d4b
--- /dev/null
+++ b/scripts/sql/align_sql_pools.pl
@@ -0,0 +1,311 @@
+#!/usr/bin/perl -Tw
+
+######################################################################
+#
+# Copyright (C) 2020 Network RADIUS
+#
+# $Id$
+#
+######################################################################
+#
+# Helper script for generating the SQL commands to align the SQL IP pools in a
+# database with a given specification.
+#
+# The radippool table is updated is a way that preserves existing leases,
+# provided that the corresponding IP addresses still exist in their pool.
+#
+# This script typically receives the output of the generate_pool_addresses.pl
+# script, as follows:
+#
+# generate_pool_addresses.pl <options> | align_sqlippools.pl <sql_dialect>
+#
+# For example:
+#
+# generate_pool_addresses.pl main_pool 10.0.1.0 10.0.1.255 | \
+# align_sqlippools.pl mariadb
+#
+# generate_pool_addresses.pl yaml pool_defs.yml existing_ips.txt | \
+# align_sqlippools.pl postgresql
+#
+# For the latter example the existing_ips.txt file might be created as
+# follows:
+#
+# psql radius -qtAc 'SELECT framedipaddress FROM radippool' > existing_ips.txt
+#
+# Note: The generate_pool_addresses.pl script describes the input format
+# expected by this script (as well as the format of the pool_defs.yml and
+# existing_ips.txt files.)
+#
+# Output:
+#
+# The output of this script is the SQL command sequence for aligning the pools
+# with the definition provided, which you should review before running them
+# against your database.
+#
+
+use strict;
+use Template;
+
+my %template=load_templates();
+
+if ($#ARGV != 0) {
+ print STDERR <<'EOF';
+Usage: generate_pool_addresses.pl ... | align_sqlippools.pl <dialect>
+
+EOF
+ exit 1;
+}
+
+my $dialect=$ARGV[0];
+
+unless (defined $template{$dialect}) {
+ print STDERR "Unknown dialect. Pick one of: ";
+ print STDERR "$_ " foreach sort keys %template;
+ print STDERR "\n";
+ exit 1;
+}
+
+my @ips=();
+
+my $line = 0;
+while (<STDIN>) {
+ $line++;
+
+ chomp;
+
+ next if $_ =~ /^#/ || $_ =~ /^\s*$/;
+
+ # The SQL works out what addresses to remove by itself
+ next if $_ =~ /^-/;
+
+ (my $action, my $pool_name, my $ip) = $_ =~ /^(.)\s+(.+)\s+([^\s]+)$/;
+
+ unless (defined $ip) {
+ warn "Unrecognised line $line: $_";
+ next;
+ }
+
+ push @ips, { poolname => $pool_name, ip => $ip };
+
+}
+
+my $tt=Template->new();
+$tt->process(\$template{$dialect}, {ips => \@ips, batchsize => 100}) || die $tt->error();
+
+exit 0;
+
+
+#
+# SQL dialect templates
+#
+
+sub load_templates {
+
+ my %template;
+
+#
+# MariaDB
+#
+ $template{'mariadb'} = <<'END_mariadb';
+-- Temporary table holds the provided IP pools
+DROP TEMPORARY TABLE IF EXISTS radippool_temp;
+CREATE TEMPORARY TABLE radippool_temp (
+ id int(11) unsigned NOT NULL auto_increment,
+ pool_name varchar(30) NOT NULL,
+ framedipaddress varchar(15) NOT NULL,
+ PRIMARY KEY (id),
+ KEY pool_name_framedipaddress (pool_name,framedipaddress)
+);
+
+-- Populate the temporary table
+[%- FOREACH m IN ips %]
+[%- "\n\nINSERT INTO radippool_temp (pool_name,framedipaddress) VALUES" IF loop.index % batchsize == 0 %]
+[%- IF (loop.index+1) % batchsize == 0 OR loop.last %]
+('[% m.poolname %]','[% m.ip %]');
+[%- ELSE %]
+('[% m.poolname %]','[% m.ip %]'),
+[%- END %]
+[%- END %]
+
+START TRANSACTION;
+
+-- Delete old pools that have been removed
+DELETE r FROM radippool r
+ LEFT JOIN radippool_temp t USING (pool_name,framedipaddress)
+ WHERE t.id IS NULL;
+
+-- Add new pools that have been created
+INSERT INTO radippool (pool_name,framedipaddress)
+ SELECT pool_name,framedipaddress FROM radippool_temp t WHERE NOT EXISTS (
+ SELECT * FROM radippool r
+ WHERE r.pool_name=t.pool_name AND r.framedipaddress=t.framedipaddress
+ );
+
+COMMIT;
+END_mariadb
+
+
+#
+# PostgreSQL
+#
+ $template{'postgresql'} = <<'END_postgresql';
+-- Temporary table holds the provided IP pools
+DROP TABLE IF EXISTS radippool_temp;
+CREATE TEMPORARY TABLE radippool_temp (
+ pool_name varchar(64) NOT NULL,
+ FramedIPAddress INET NOT NULL
+);
+CREATE INDEX radippool_temp_idx ON radippool_temp USING btree (pool_name,FramedIPAddress);
+
+-- Populate the temporary table
+[%- FOREACH m IN ips %]
+[%- "\n\nINSERT INTO radippool_temp (pool_name,framedipaddress) VALUES" IF loop.index % batchsize == 0 %]
+[%- IF (loop.index+1) % batchsize == 0 OR loop.last %]
+('[% m.poolname %]','[% m.ip %]');
+[%- ELSE %]
+('[% m.poolname %]','[% m.ip %]'),
+[%- END %]
+[%- END %]
+
+START TRANSACTION;
+
+-- Delete old pools that have been removed
+DELETE FROM radippool r WHERE NOT EXISTS (
+ SELECT FROM radippool_temp t
+ WHERE t.pool_name = r.pool_name AND t.framedipaddress = r.framedipaddress
+);
+
+-- Add new pools that have been created
+INSERT INTO radippool (pool_name,framedipaddress)
+ SELECT pool_name,framedipaddress FROM radippool_temp t WHERE NOT EXISTS (
+ SELECT * FROM radippool r
+ WHERE r.pool_name=t.pool_name AND r.framedipaddress=t.framedipaddress
+ );
+
+COMMIT;
+END_postgresql
+
+#
+# Oracle
+#
+ $template{'oracle'} = <<'END_oracle';
+-- Temporary table holds the provided IP pools
+CREATE GLOBAL TEMPORARY TABLE radippool_temp (
+ pool_name VARCHAR(30) NOT NULL,
+ FramedIPAddress VARCHAR(15) NOT NULL
+) ON COMMIT DELETE ROWS;
+CREATE INDEX radippool_temp_idx ON radippool_temp (pool_name,FramedIPAddress);
+
+-- Populate the temporary table
+[%- FOREACH m IN ips %]
+[%- "\nINSERT INTO radippool_temp (pool_name,framedipaddress) VALUES " %]('[% m.poolname %]','[% m.ip %]');
+[%- END %]
+
+-- Delete old pools that have been removed
+DELETE FROM radippool WHERE (pool_name, framedipaddress)
+ NOT IN (SELECT pool_name, framedipaddress FROM radippool_temp);
+
+-- Add new pools that have been created
+INSERT INTO radippool (pool_name,framedipaddress)
+ SELECT pool_name,framedipaddress FROM radippool_temp t WHERE NOT EXISTS (
+ SELECT * FROM radippool r
+ WHERE r.pool_name=t.pool_name AND r.framedipaddress=t.framedipaddress
+ );
+
+COMMIT;
+END_oracle
+
+#
+# SQLite
+#
+
+ $template{'sqlite'} = <<'END_sqlite';
+-- Temporary table holds the provided IP pools
+DROP TABLE IF EXISTS radippool_temp;
+CREATE TABLE radippool_temp (
+ pool_name varchar(30) NOT NULL,
+ framedipaddress varchar(15) NOT NULL
+);
+
+CREATE INDEX radippool_temp_idx ON radippool_temp (pool_name,FramedIPAddress);
+
+-- Populate the temporary table
+[%- FOREACH m IN ips %]
+[%- "\n\nINSERT INTO radippool_temp (pool_name,framedipaddress) VALUES" IF loop.index % batchsize == 0 %]
+[%- IF (loop.index+1) % batchsize == 0 OR loop.last %]
+('[% m.poolname %]','[% m.ip %]');
+[%- ELSE %]
+('[% m.poolname %]','[% m.ip %]'),
+[%- END %]
+[%- END %]
+
+BEGIN TRANSACTION;
+
+-- Delete old pools that have been removed
+DELETE FROM radippool WHERE rowid IN (
+ SELECT r.rowid FROM radippool r
+ LEFT JOIN radippool_temp t USING (pool_name,framedipaddress)
+ WHERE t.rowid IS NULL);
+
+-- Add new pools that have been created
+INSERT INTO radippool (pool_name,framedipaddress)
+ SELECT pool_name,framedipaddress FROM radippool_temp t WHERE NOT EXISTS (
+ SELECT * FROM radippool r
+ WHERE r.pool_name=t.pool_name AND r.framedipaddress=t.framedipaddress
+ );
+
+COMMIT;
+
+DROP TABLE radippool_temp;
+END_sqlite
+
+#
+# MS SQL
+#
+ $template{'mssql'} = <<'END_mssql';
+-- Temporary table holds the provided IP pools
+DROP TABLE IF EXISTS #radippool_temp;
+GO
+
+CREATE TABLE #radippool_temp (
+ id int identity(1, 1) NOT NULL,
+ pool_name varchar(30) NOT NULL,
+ framedipaddress varchar(15) NOT NULL,
+ PRIMARY KEY (id),
+);
+GO
+
+CREATE INDEX pool_name_framedipaddress ON #radippool_temp(pool_name, framedipaddress);
+GO
+
+-- Populate the temporary table
+[%- FOREACH m IN ips %]
+[%- "\n\nINSERT INTO #radippool_temp (pool_name,framedipaddress) VALUES" IF loop.index % batchsize == 0 %]
+[%- IF (loop.index+1) % batchsize == 0 OR loop.last %]
+('[% m.poolname %]','[% m.ip %]');
+GO
+[%- ELSE %]
+('[% m.poolname %]','[% m.ip %]'),
+[%- END %]
+[%- END %]
+
+BEGIN TRAN;
+
+-- Delete old pools that have been removed
+DELETE r FROM radippool r
+ LEFT JOIN #radippool_temp t ON r.pool_name = t.pool_name AND r.framedipaddress = t.framedipaddress
+ WHERE t.id IS NULL;
+
+-- Add new pools that have been created
+INSERT INTO radippool (pool_name,framedipaddress)
+ SELECT pool_name,framedipaddress FROM #radippool_temp t WHERE NOT EXISTS (
+ SELECT * FROM radippool r
+ WHERE r.pool_name=t.pool_name AND r.framedipaddress=t.framedipaddress
+ );
+
+COMMIT TRAN;
+END_mssql
+
+ return %template;
+
+}
diff --git a/scripts/sql/generate_pool_addresses.pl b/scripts/sql/generate_pool_addresses.pl
new file mode 100755
index 0000000..85fe030
--- /dev/null
+++ b/scripts/sql/generate_pool_addresses.pl
@@ -0,0 +1,456 @@
+#!/usr/bin/perl -Tw
+
+######################################################################
+#
+# Copyright (C) 2020 Network RADIUS
+#
+# $Id$
+#
+######################################################################
+#
+# Helper script for populating IP pools with address entries.
+#
+# This script generates output that is useful for populating an IP pool for
+# use with FreeRADIUS (and possibly other purposes). The pool may be
+# implemented as an SQL IP Pool (rlm_sqlippool) or any other backing store
+# that has one entry per IP address.
+#
+# This script output a list of address to add, retain and remove in order to
+# align a pool to a specification. It is likely that you will want to
+# process the output to generate the actual commands (e.g. SQL statements)
+# that make changes to the datastore. For example:
+#
+# generate_pool_addresses.pl ... | align_sql_pools.pl postgresql
+#
+#
+# Use with a single address range
+# -------------------------------
+#
+# For basic use, arguments can be provided to this script that denote the ends
+# of a single IP (v4 or v6) address range together with the pool_name.
+#
+# Optionally the number of IPs to sparsely populate the range with can be
+# provided. If the range is wider than a /16 then the population of the range
+# is capped at 65536 IPs, unless otherwise specified.
+#
+# In the case that a sparse range is defined, a file containing pre-existing
+# IP entries can be provided. The range will be populated with entries from
+# this file that fall within the range, prior to the remainder of the range
+# being populated with random address in the range.
+#
+# generate_pool_addresses.pl <pool_name> <range_start> <range_end> \
+# [ <capacity> [ <existing_ips_file> ] ]
+#
+# Note: Sparse ranges are populated using a deterministic, pseudo-random
+# function. This allows pools to be trivially extended without having to
+# supply the existing contents using a file. If you require
+# less-predictable randomness or a different random sequence then remove
+# or modify the line calling srand(), below.
+#
+#
+# Use with multiple pools and address ranges
+# ------------------------------------------
+#
+# For more complex us, the script allows a set of pool definitions to be
+# provided in a YAML file which describes a set of one or more pools, each
+# containing a set of one or more ranges. The first argument in this case is
+# always "yaml":
+#
+# generate_pool_addresses.pl yaml <pool_defs_yaml_file> [ <existing_ips_file> ]
+#
+# The format for the YAML file is demonstrated by the following example:
+#
+# pool_with_a_single_contiguous_range:
+# - start: 192.0.2.3
+# end: 192.0.2.250
+#
+# pool_with_a_single_sparse_range:
+# - start: 10.10.10.0
+# end: 10.10.20.255
+# capacity: 200
+#
+# pool_with_multiple_ranges:
+# - start: 10.10.10.1
+# end: 10.10.10.253
+# - start: 10.10.100.0
+# end: 10.10.199.255
+# capacity: 1000
+#
+# v6_pool_with_contiguous_range:
+# - start: '2001:db8:1:2:3:4:5:10'
+# end: '2001:db8:1:2:3:4:5:7f'
+#
+# v6_pool_with_sparse_range:
+# - start: '2001:db8:1:2::'
+# end: '2001:db8:1:2:ffff:ffff:ffff:ffff'
+# capacity: 200
+#
+# As with the basic use case, a file containing pre-existing IP entries can be
+# provided with which any sparse ranges will be populated ahead of any random
+# addresses.
+#
+#
+# Output
+# ------
+#
+# The script returns line-based output beginning with "+", "=" or "-", and
+# includes the pool_name and an IP address.
+#
+# + pool_name 192.0.2.10
+#
+# A new address to be added to the corresponding range in the pool.
+#
+# = pool_name 192.0.2.20
+#
+# A pre-existing address that is to be retained in the pool. (Only if a
+# pre-existing pool entries file is given.)
+#
+# - pool_name 192.0.2.30
+#
+# A pre-existing address that is to be removed from the corresponding
+# range in the pool. (Only if a pre-existing pool entries file is given.)
+#
+# # main_pool: 192.0.10.3 - 192.0.12.250 (500)
+#
+# Lines beginning with "#" are comments
+#
+#
+# Examples
+# --------
+#
+# generate_pool_addresses.pl main_pool 192.0.2.3 192.0.2.249
+#
+# Will create a pool from a full populated IPv4 range, i.e. all IPs in the
+# range available for allocation).
+#
+# generate_pool_addresses.pl main_pool 10.66.0.0 10.66.255.255 10000
+#
+# Will create a pool from a sparsely populated IPv4 range for a /16
+# network (maximum of 65.536 addresses), populating the range with 10,000
+# addreses. The effective size of the pool can be increased in future by
+# increasing the capacity of the range with:
+#
+# generate_pool_addresses.pl main_pool 10.66.0.0 10.66.255.255 20000
+#
+# This generates the same initial set of 10,000 addresses as the previous
+# example but will create 20,000 addresses overall, unless the random seed
+# has been amended since the initial run.
+#
+# generate_pool_addresses.pl main_pool 2001:db8:1:2:: \
+# 2001:db8:1:2:ffff:ffff:ffff:ffff
+#
+# Will create a pool from the IPv6 range 2001:db8:1:2::/64, initially
+# populating the range with 65536 (by default) addresses.
+#
+# generate_pool_addresses.pl main_pool 2001:db8:1:2:: \
+# 2001:db8:1:2:ffff:ffff:ffff:ffff \
+# 10000 existing_ips.txt
+#
+# Will create a pool using the same range as the previous example, but
+# this time the range will be populated with 10,000 addresses. The range
+# will be populated using lines extracted from the `existing_ips.txt` file
+# that represent IPs which fall within range.
+#
+# generate_pool_addresses.pl yaml pool_defs.yml existing_ips.txt
+#
+# Will create one of more pools using the definitions found in the
+# pool_defs.yml YAML file. The pools will contain one or more ranges with
+# each of the ranges first being populated with entries from the
+# existing_ips.txt file that fall within the range, before being filled
+# with random addresses to the defined capacity.
+#
+
+use strict;
+use Net::IP qw/ip_bintoip ip_iptobin ip_bincomp ip_binadd ip_is_ipv4 ip_is_ipv6/;
+
+my $yaml_available = 0;
+
+eval {
+ require YAML::XS;
+ YAML::XS->import('LoadFile');
+ $yaml_available = 1;
+};
+
+if ($#ARGV < 2 || $#ARGV > 4) {
+ usage();
+ exit 1;
+}
+
+if ($ARGV[0] eq 'yaml') {
+
+ if ($#ARGV > 3) {
+ usage();
+ exit 1;
+ }
+
+ unless ($yaml_available) {
+ die "ERROR: YAML is not available. Install the YAML::XS Perl module.";
+ }
+ process_yaml_file();
+
+ goto done;
+
+}
+
+process_commandline();
+
+done:
+
+exit 0;
+
+
+sub usage {
+ print STDERR <<'EOF'
+Usage:
+ generate_pool_addresses.pl <pool_name> <range_start> <range_end> [ <capacity> [ <existing_ips_file> ] ]
+or:
+ generate_pool_addresses.pl yaml <pool_defs_yaml_file> [ <existing_ips_file> ]
+
+EOF
+}
+
+
+sub process_commandline {
+
+ $SIG{__DIE__} = sub { usage(); die(@_); };
+
+ my $pool_name = $ARGV[0];
+ my $range_start = $ARGV[1];
+ my $range_end = $ARGV[2];
+ my $capacity = $ARGV[3];
+
+ my @entries = ();
+ @entries = load_entries($ARGV[4]) if ($#ARGV >= 4);
+
+ handle_range($pool_name, $range_start, $range_end, $capacity, @entries);
+
+}
+
+
+sub process_yaml_file {
+
+ my $yaml_file = $ARGV[1];
+
+ unless (-r $yaml_file) {
+ die "ERROR: Cannot open <pool_defs_yaml_file> for reading: $yaml_file";
+ }
+
+ my %pool_defs = %{LoadFile($yaml_file)};
+
+ my @entries = ();
+ @entries = load_entries($ARGV[2]) if ($#ARGV >= 2);
+
+ foreach my $pool_name (sort keys %pool_defs) {
+ foreach my $range (@{$pool_defs{$pool_name}}) {
+ my $range_start = $range->{start};
+ my $range_end = $range->{end};
+ my $capacity = $range->{capacity};
+ handle_range($pool_name, $range_start, $range_end, $capacity, @entries);
+ }
+ }
+
+}
+
+
+sub load_entries {
+
+ my $entries_file = shift;
+
+ my @entries = ();
+ unless (-r $entries_file) {
+ die "ERROR: Cannot open <existing_ips_file> for reading: $entries_file"
+ }
+ open(my $fh, "<", $entries_file) || die "Failed to open $entries_file";
+ while(<$fh>) {
+ chomp;
+ push @entries, $_;
+ }
+
+ return @entries;
+
+}
+
+
+sub handle_range {
+
+ my $pool_name = shift;
+ my $range_start = shift;
+ my $range_end = shift;
+ my $capacity = shift;
+ my @entries = @_;
+
+ unless (ip_is_ipv4($range_start) || ip_is_ipv6($range_start)) {
+ die "ERROR: Incorrectly formatted IPv4/IPv6 address for range_start: $range_start";
+ }
+
+ unless (ip_is_ipv4($range_end) || ip_is_ipv6($range_end)) {
+ die "ERROR: Incorrectly formatted IPv4/IPv6 address for range_end: $range_end";
+ }
+
+ my $ip_start = new Net::IP($range_start);
+ my $ip_end = new Net::IP($range_end);
+ my $ip_range = new Net::IP("$range_start - $range_end");
+
+ unless (defined $ip_range) {
+ die "ERROR: The range defined by <range_start> - <range_end> is invalid: $range_start - $range_end";
+ }
+
+ my $range_size = $ip_range->size;
+ $capacity = $range_size < 65536 ? "$range_size" : 65536 unless defined $capacity;
+
+ if ($range_size < $capacity) {
+ $capacity = "$range_size";
+ warn "WARNING: Insufficent IPs in the range. Will create $capacity entries.";
+ }
+
+ # Prune the entries to only those within the specified range
+ for (my $i = 0; $i <= $#entries; $i++) {
+ my $version = ip_is_ipv4($entries[$i]) ? 4 : 6;
+ my $binip = ip_iptobin($entries[$i],$version);
+ if ($ip_start->version != $version ||
+ ip_bincomp($binip, 'lt', $ip_start->binip) == 1 ||
+ ip_bincomp($binip, 'gt', $ip_end->binip) == 1) {
+ $entries[$i]='';
+ }
+ }
+
+ #
+ # We use the sparse method if the number of entries available occupies < 80% of
+ # the network range, otherwise we use a method that involves walking the
+ # entire range.
+ #
+
+ srand(42); # Set the seed for the PRNG
+
+ if (length($range_size) > 9 || $capacity / "$range_size" < 0.8) { # From "BigInt" to FP
+ @entries = sparse_fill($pool_name, $ip_start, $ip_end, $capacity, @entries);
+ } else {
+ @entries = dense_fill($pool_name, $ip_start, $ip_end, $ip_range, $capacity, @entries);
+ }
+
+ print "# $pool_name: $range_start - $range_end ($capacity)\n";
+ print "$_\n" foreach @entries;
+ print "\n";
+
+}
+
+
+#
+# With this sparse fill method we randomly allocate within the scope of the
+# smallest enclosing network prefix, checking that we are within the given
+# range, retrying if we are outside or we hit a duplicate.
+#
+# This method can efficiently choose a small number of addresses relative to
+# the size of the range. It becomes slower as the population of a range nears
+# the range's limit since it is harder to choose a free address at random.
+#
+# It is useful for selecting a handful of addresses from an enourmous IPv6 /64
+# network for example.
+#
+sub sparse_fill {
+
+ my $pool_name = shift;
+ my $ip_start = shift;
+ my $ip_end = shift;
+ my $capacity = shift;
+ my @entries = @_;
+
+ # Find the smallest network that encloses the given range
+ my $version = $ip_start->version;
+ ( $ip_start->binip ^ $ip_end->binip ) =~ /^\0*/;
+ my $net_prefix = $+[0];
+ my $net_bits = substr($ip_start->binip, 0, $net_prefix);
+ my $host_length = length($ip_start->binip) - $net_prefix;
+
+ my %ips = ();
+ my $i = 0;
+ while ($i < $capacity) {
+
+ # Use the given entries first
+ my $rand_ip;
+ my $given_lease = 0;
+ shift @entries while $#entries >= 0 && $entries[0] eq '';
+ if ($#entries >= 0) {
+ $rand_ip = ip_iptobin(shift @entries, $version);
+ $given_lease = 1;
+ } else {
+ $rand_ip = $net_bits;
+ $rand_ip .= [0..1]->[rand 2] for 1..$host_length;
+ # Check that we are inside the given range
+ next if ip_bincomp($rand_ip, 'lt', $ip_start->binip) == 1 ||
+ ip_bincomp($rand_ip, 'gt', $ip_end->binip) == 1;
+ }
+
+ next if defined $ips{$rand_ip};
+
+ $ips{$rand_ip} = $given_lease ? '=' : '+';
+ $i++;
+
+ }
+
+ # Allow the pool to be shrunk
+ $ips{ip_iptobin($_, $version)} = '-' foreach @entries;
+
+ return map { $ips{$_}." ".$pool_name." ".ip_bintoip($_, $version) } sort keys %ips;
+
+}
+
+
+#
+# With this dense fill method, after first selecting the given entries we walk
+# the network range picking IPs with evenly distributed probability.
+#
+# This method can efficiently choose a large number of addresses relative to
+# the size of a range, provided that the range isn't massive. It becomes
+# slower as the range size increases.
+#
+sub dense_fill {
+
+ my $pool_name = shift;
+ my $ip_start = shift;
+ my $ip_end = shift;
+ my $ip_range = shift;
+ my $capacity = shift;
+ my @entries = @_;
+
+ my $version = $ip_start->version;
+
+ my $one = ("0"x($version == 4 ? 31 : 127)) . '1';
+
+ my %ips = ();
+ my $remaining_entries = $capacity;
+ my $remaining_ips = $ip_range->size;
+ my $ipbin = $ip_start->binip;
+
+ while ($remaining_entries > 0 && (ip_bincomp($ipbin, 'le', $ip_end->binip) == 1)) {
+
+ # Use the given entries first
+ shift @entries while $#entries >= 0 && $entries[0] eq '';
+ if ($#entries >= 0) {
+ $ips{ip_iptobin(shift @entries, $version)} = '=';
+ $remaining_entries--;
+ $remaining_ips--;
+ next;
+ }
+
+ goto next_ip if defined $ips{$ipbin};
+
+ # Skip the IP that we have already selected by given entries, otherwise
+ # randomly pick it
+ if (!defined $ips{$ipbin} &&
+ (rand) <= $remaining_entries / "$remaining_ips") { # From "BigInt" to FP
+ $ips{$ipbin} = '+';
+ $remaining_entries--;
+ }
+
+ $remaining_ips--;
+ $ipbin = ip_binadd($ipbin,$one);
+
+ }
+
+ # Allow the pool to be shrunk
+ $ips{ip_iptobin($_, $version)} = '-' foreach @entries;
+
+ return map { $ips{$_}." ".$pool_name." ".ip_bintoip($_, $version) } sort keys %ips;
+
+}
diff --git a/scripts/sql/radsqlrelay b/scripts/sql/radsqlrelay
new file mode 100755
index 0000000..74531ba
--- /dev/null
+++ b/scripts/sql/radsqlrelay
@@ -0,0 +1,342 @@
+#!/usr/bin/perl -w
+##
+## radsqlrelay.pl This program tails a SQL logfile and forwards
+## the queries to a database server. Used to
+## replicate accounting records to one (central)
+## database, even if the database has extended
+## downtime.
+##
+## Version: $Id$
+##
+## Author: Nicolas Baradakis <nicolas.baradakis@cegetel.net>
+##
+## Copyright (C) 2005 Cegetel
+## Copyright (C) 2019 Network RADIUS
+##
+## 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
+##
+
+use strict;
+
+use DBI;
+use Fcntl;
+use Getopt::Std;
+use POSIX qw(:unistd_h :errno_h);
+use Time::HiRes qw(clock_gettime usleep CLOCK_MONOTONIC);
+
+# We send watchdogs at half the indicated interval if the
+# Linux::Systemd::Daemon module is available and the WATCHDOG_USEC environment
+# variable is set by the systemd service manager.
+my $watchdog_usec;
+my $next_watchdog;
+eval {
+ require Linux::Systemd::Daemon;
+ Linux::Systemd::Daemon->import();
+ $watchdog_usec = $ENV{'WATCHDOG_USEC'} || undef;
+};
+
+# To synthetically test the watchdog functionality then uncomment these next
+# lines:
+#
+# $watchdog_usec = 30 *1000*1000;
+# sub sd_notify {}
+
+my $maxcollect = 100; # tunable, works for MySQL!
+
+my $lastinsert;
+my @values;
+
+my $need_exit = 0;
+my $debug = 0;
+
+sub got_signal()
+{
+ $need_exit = 1;
+ sd_notify(stopping => 1, status => 'Signalled. Shutting down.') if $watchdog_usec;
+}
+
+sub debug
+{
+ print shift if $debug;
+}
+
+# /!\ OS-dependent structure
+# Linux struct flock
+# short l_type;
+# short l_whence;
+# off_t l_start;
+# off_t l_len;
+# pid_t l_pid;
+# c2ph says: typedef='s2 l2 i', sizeof=16
+my $FLOCK_STRUCT = 's2l2i';
+
+sub setlock($;$$)
+{
+ my ($fh, $start, $len) = @_;
+ $start = 0 unless defined $start;
+ $len = 0 unless defined $len;
+
+ #type whence start till pid
+ my $packed = pack($FLOCK_STRUCT, F_WRLCK, SEEK_SET, $start, $len, 0);
+ if (fcntl($fh, F_SETLKW, $packed)) { return 1 }
+ else { return 0 }
+}
+
+sub usage()
+{
+ print STDERR <<HERE;
+usage: radsqlrelay [options] file_path
+options:
+ -? Print this help message.
+ -1 One-shot mode: push the file to database and exit.
+ -b database Name of the database to use.
+ -d sql_driver Driver to use: mysql, pg, oracle.
+ -f file Read password from file, instead of command line.
+ -h host Connect to host.
+ -P port Port number to use for connection.
+ -p password Password to use when connecting to server.
+ -u user User for login.
+ -x Turn on debugging.
+HERE
+}
+
+
+# Sleep for given amount of time, but don't oversleep the watchdog interval.
+# Send a watchdog notification if it is due.
+# interval can be given as 0 to just check whether a watchdog is due and send
+# it as necessary, in which case we do not yield.
+sub sleep_for ($)
+{
+ my $interval=shift;
+ $interval*=1000*1000;
+ if ($watchdog_usec) {
+ my $now=clock_gettime(CLOCK_MONOTONIC)*1000*1000;
+ if ($now >= $next_watchdog) {
+ $next_watchdog=$now+($watchdog_usec / 2);
+ debug "Sending watchdog\n";
+ sd_notify(watchdog => 1);
+ debug "Next watchdog due in ".(($next_watchdog-$now)/1000/1000)." secs.\n";
+ }
+ # Don't oversleep!
+ $interval=$next_watchdog-$now if $next_watchdog-$now < $interval;
+ }
+ return unless $interval; # Don't yield if we are not asked to sleep
+ debug "Sleeping for ".($interval/1000/1000)." secs.\n";
+ usleep ($interval);
+}
+
+
+sub connect_wait($)
+{
+ my $dbinfo = shift;
+ my $dbh;
+ debug "Connecting to " . $dbinfo->{base};
+ while (!$dbh) {
+ debug ".";
+ $dbh = DBI->connect($dbinfo->{base}, $dbinfo->{user}, $dbinfo->{pass},
+ { RaiseError => 0, PrintError => 0,
+ AutoCommit => 1 });
+ sleep_for (1) if !$dbh;
+ exit if $need_exit;
+ }
+ debug "\n";
+ $dbinfo->{handle} = $dbh;
+}
+
+
+
+sub process_file($$)
+{
+ my ($dbinfo, $path) = @_;
+
+ sub do_inserts($) {
+ my $dbinfo = shift;
+ debug "I";
+ if (scalar(@values) > 0) {
+ my $query = $lastinsert . " ";
+ $query .= join(" ), ( ",@values);
+ $query .= " );";
+ do_query($dbinfo,$query);
+ }
+ @values = ();
+ }
+
+ sub do_query($$) {
+ my ($dbinfo,$query) = @_;
+ debug ">";
+ until ($dbinfo->{handle}->do($query)) {
+ # If an error occured and we're disconnected then try to recomnnect
+ # and redo the query, otherwise give up so we don't become stuck.
+ print $dbinfo->{handle}->errstr."\n";
+ if ($dbinfo->{handle}->ping) {
+ sleep_for (1);
+ last;
+ } else {
+ print "error: Lost connection to database\n";
+ $dbinfo->{handle}->disconnect;
+ connect_wait($dbinfo);
+ }
+ }
+ sleep_for(0) if $watchdog_usec; # Send a watchdog if it is due
+ }
+
+ unless (-e $path.'.work') {
+ debug "Waiting for $path\n";
+ until (rename($path, $path.'.work')) {
+ if ($! == ENOENT) {
+ sleep_for(1);
+ return if $need_exit;
+ } else {
+ print STDERR "error: Couldn't move $path to $path.work: $!\n";
+ exit 1;
+ }
+ }
+ debug "Renamed $path to $path.work\n";
+ }
+
+ debug "\nOpening $path.work\n";
+ open(FILE, "+< $path.work") or die "error: Couldn't open $path.work: $!\n";
+ debug "Getting file lock\n";
+ setlock(\*FILE) or die "error: Couldn't lock $path.work: $!\n";
+
+ $lastinsert = "";
+ @values = ();
+
+ debug "Reading: ";
+ my $lines = 0;
+ while (<FILE>) {
+ chomp (my $line = $_);
+ $lines++;
+
+ if (!($line =~ /^\s*insert\s+into\s+`?\w+`?\s+(?:\(.*?\)\s+)?
+ values\s*\(.*\)\s*;\s*$/ix)) {
+ # This is no INSERT, so start new collection
+ do_inserts($dbinfo);
+ debug ".";
+ $lastinsert = "";
+ # must output this line
+ do_query($dbinfo, "$line");
+
+ } else {
+ # This is an INSERT, so collect it
+ debug "+";
+ my $insert = $line;
+ my $values = $line;
+ $insert =~ s/^\s*(insert\s+into\s+`?\w+`?\s+(?:\(.*?\)\s+)?
+ values\s*\().*\)\s*;\s*$/$1/ix;
+ $values =~ s/^\s*insert\s+into\s+`?\w+`?\s+(?:\(.*?\)\s+)?
+ values\s*\((.*)\)\s*;\s*$/$1/ix;
+
+ if (($lastinsert ne "") && ($insert ne $lastinsert)) {
+ # This is different from the last one
+ do_inserts($dbinfo);
+ }
+ push(@values, $values);
+ $lastinsert = $insert; # start new collection
+ }
+
+ # limit to $maxcollect collected lines
+ if (scalar(@values) >= $maxcollect) {
+ debug "hit maxcollect limit, doing inserts";
+ do_inserts($dbinfo);
+ }
+ }
+
+ # Cleanup
+ debug "\nNo more lines to read, doing any final inserts: ";
+ do_inserts($dbinfo);
+ debug "\n";
+
+ debug "Processed $lines lines\n";
+ debug "Removing and closing $path.work\n\n";
+ unlink($path.'.work');
+ close(FILE); # and unlock
+}
+
+# sub main()
+
+my %args = (
+ b => 'radius',
+ d => 'mysql',
+ h => 'localhost',
+ p => 'radius',
+ u => 'radius',
+);
+my $ret = getopts("b:d:f:h:P:p:u:x1?", \%args);
+if (!$ret or @ARGV != 1) {
+ usage();
+ exit 1;
+}
+if ($args{'?'}) {
+ usage();
+ exit 0;
+}
+$debug = 1 if $args{'x'};
+
+my $data_source;
+if (lc($args{d}) eq 'mysql') {
+ $data_source = "DBI:mysql:database=$args{b};host=$args{h}";
+} elsif (lc($args{d}) eq 'pg') {
+ $data_source = "DBI:Pg:dbname=$args{b};host=$args{h}";
+} elsif (lc($args{d}) eq 'oracle') {
+ $data_source = "DBI:Oracle:$args{b}";
+ # Oracle does not conform to the SQL standard for multirow INSERTs
+ $maxcollect = 1;
+} else {
+ print STDERR "error: SQL driver not supported yet: $args{d}\n";
+ exit 1;
+}
+$data_source .= ";port=$args{P}" if $args{'P'};
+
+my $pw;
+if($args{f}) {
+ open(FILE, "< $args{f}") or die "error: Couldn't open $args{f}: $!\n";
+ $pw = <FILE>;
+ chomp($pw);
+ close(FILE);
+} else {
+ # args{p} is always defined.
+ $pw = $args{p};
+}
+
+$SIG{INT} = \&got_signal;
+$SIG{TERM} = \&got_signal;
+
+if ($watchdog_usec) {
+ debug "Watchdog set to $watchdog_usec\n";
+ my $now=clock_gettime(CLOCK_MONOTONIC)*1000*1000;
+ $next_watchdog=$now+($watchdog_usec / 2);
+ sd_notify(ready => 1, status => 'Started');
+}
+
+my %dbinfo = (
+ base => $data_source,
+ user => $args{u},
+ pass => $pw,
+);
+connect_wait(\%dbinfo);
+
+my $path = shift @ARGV;
+
+until ($need_exit) {
+ process_file(\%dbinfo, $path);
+ last if ($args{1} || $need_exit);
+ debug "Sleeping\n";
+ sleep_for(10);
+}
+
+debug "Disconnecting from database\n";
+$dbinfo{handle}->disconnect;
+
diff --git a/scripts/sql/rlm_sqlippool_tool b/scripts/sql/rlm_sqlippool_tool
new file mode 100755
index 0000000..47a48fc
--- /dev/null
+++ b/scripts/sql/rlm_sqlippool_tool
@@ -0,0 +1,961 @@
+#!/usr/bin/perl -Tw
+
+######################################################################
+#
+# Copyright (C) 2020 Network RADIUS
+#
+# $Id$
+#
+######################################################################
+#
+# Helper script for populating IP pools with address entries.
+#
+# This script generates SQL output that is useful for populating an IP pool
+# for use with FreeRADIUS (and possibly other purposes). Alternatively,
+# if called with the -f option will directly operate on the database configured
+# within the FreeRADIUS configuration to update the IP pool table specified
+#
+# Note: Direct connection to databases is done using Perl DBI. You may need
+# to install the appropriate Perl DBD driver to enable this functionality.
+# Formatted SQL output is produced using Perl Template::Toolkit which
+# will need to be installed if this output is required.
+#
+#
+# Use with a single address range
+# -------------------------------
+#
+# For basic use, arguments can be provided to this script that denote the ends
+# of a single IP (v4 or v6) address range together with the pool_name and
+# SQL dialect or a raddb directory from which the database config will be
+# read.
+#
+# If a raddb directory is specified, then the instance of the FreeRADIUS sql
+# module to be found in the config can be specified. It defaults to "sql".
+#
+# Optionally the number of IPs to sparsely populate the range with can be
+# provided. If the range is wider than a /16 then the population of the range
+# is capped at 65536 IPs, unless otherwise specified.
+#
+# In the case that a sparse range is defined, a file containing pre-existing
+# IP entries can be provided. The range will be populated with entries from
+# this file that fall within the range, prior to the remainder of the range
+# being populated with random address in the range.
+#
+# rlm_sqlippool_tool -p <pool_name> -s <range_start> -e <range_end> \
+# -t <table_name> (-d <sql_dialect> | -f <raddb_dir> [ -i <instance> ]) \
+# [ -c <capacity> ] [ -x <existing_ips_file> ]
+#
+# Note: Sparse ranges are populated using a deterministic, pseudo-random
+# function. This allows pools to be trivially extended without having to
+# supply the existing contents using a file. If you require
+# less-predictable randomness or a different random sequence then remove
+# or modify the line calling srand(), below.
+#
+#
+# Use with multiple pools and address ranges
+# ------------------------------------------
+#
+# For more complex us, the script allows a set of pool definitions to be
+# provided in a YAML file which describes a set of one or more pools, each
+# containing a set of one or more ranges.
+#
+# rlm_sqlippool_tool -y <pool_defs_yaml_file> -t <table_name> \
+# ( -d <dialect> | -f <raddb_dir> [ -i <instance> ] ) \
+# [ -x <existing_ips_file> ]
+#
+# The format for the YAML file is demonstrated by the following example:
+#
+# pool_with_a_single_contiguous_range:
+# - start: 192.0.2.3
+# end: 192.0.2.250
+#
+# pool_with_a_single_sparse_range:
+# - start: 10.10.10.0
+# end: 10.10.20.255
+# capacity: 200
+#
+# pool_with_multiple_ranges:
+# - start: 10.10.10.1
+# end: 10.10.10.253
+# - start: 10.10.100.0
+# end: 10.10.199.255
+# capacity: 1000
+#
+# v6_pool_with_contiguous_range:
+# - start: '2001:db8:1:2:3:4:5:10'
+# end: '2001:db8:1:2:3:4:5:7f'
+#
+# v6_pool_with_sparse_range:
+# - start: '2001:db8:1:2::'
+# end: '2001:db8:1:2:ffff:ffff:ffff:ffff'
+# capacity: 200
+#
+# As with the basic use case, a file containing pre-existing IP entries can be
+# provided with which any sparse ranges will be populated ahead of any random
+# addresses.
+#
+#
+# Output
+# ------
+#
+# The script returns SQL formatted appropriately for one of a number of
+# different SQL dialects.
+#
+# The SQL first creates a temporary table to insert the new pools into,
+# inserts the addresses, then removes any exisitng entries from the pool
+# table that do not exist in the new pool. Finally any new entries that
+# don't exist in the existing pool table are copied from the temporary
+# table.
+#
+# The SQL templates assume that the pool name will be in a field called
+# "pool_name" and the IP address in a field named "framedipaddress",
+# matching the default schema for ippools and DHCP ippools as shipped with
+# FreeRADIUS.
+#
+#
+# Examples
+# --------
+#
+# rlm_sqlippool_tool -p main_pool -s 192.0.2.3 -e 192.0.2.249 \
+# -d postgresql -t radippool
+#
+# Will create a pool from a full populated IPv4 range, i.e. all IPs in the
+# range available for allocation, with SQL output suitable for PostgreSQL
+#
+# rlm_sqlippool_tool -p main_pool -s 10.66.0.0 -e 10.66.255.255 -c 10000 \
+# -d mysql -t radippool
+#
+# Will create a pool from a sparsely populated IPv4 range for a /16
+# network (maximum of 65.536 addresses), populating the range with 10,000
+# addreses. With SQL output suitable for MySQL.
+# The effective size of the pool can be increased in future by increasing
+# the capacity of the range with:
+#
+# rlm_sqlippool_tool -p main_pool -s 10.66.0.0 -e 10.66.255.255 -c 20000 \
+# -d mysql -t radippool
+#
+# This generates the same initial set of 10,000 addresses as the previous
+# example but will create 20,000 addresses overall, unless the random seed
+# has been amended since the initial run.
+#
+# rlm_sqlippool_tool -p main_pool -s 2001:db8:1:2:: \
+# -e 2001:db8:1:2:ffff:ffff:ffff:ffff -d mssql -t radippool
+#
+# Will create a pool from the IPv6 range 2001:db8:1:2::/64, initially
+# populating the range with 65536 (by default) addresses.
+#
+# rlm_sqlippool_tool -p main_pool -s 2001:db8:1:2:: \
+# -e 2001:db8:1:2:ffff:ffff:ffff:ffff \
+# -c 10000 -x existing_ips.txt -d mysql -t radippool
+#
+# Will create a pool using the same range as the previous example, but
+# this time the range will be populated with 10,000 addresses. The range
+# will be populated using lines extracted from the `existing_ips.txt` file
+# that represent IPs which fall within range.
+#
+# rlm_sqlippool_tool -y pool_defs.yml -d postgresql -t radippool \
+# -x existing_ips.txt
+#
+# Will create one of more pools using the definitions found in the
+# pool_defs.yml YAML file. The pools will contain one or more ranges with
+# each of the ranges first being populated with entries from the
+# existing_ips.txt file that fall within the range, before being filled
+# with random addresses to the defined capacity.
+#
+
+use strict;
+use Net::IP qw/ip_bintoip ip_iptobin ip_bincomp ip_binadd ip_is_ipv4 ip_is_ipv6/;
+
+#
+# Option defaults
+#
+my $opts = {
+ instance => 'sql',
+ capacity => 65536
+};
+
+#
+# Parse the command line arguments
+#
+my $opt = '';
+for (my $i = 0; $i <= $#ARGV; $i++) {
+ if ($ARGV[$i] =~ m/^-(.)$/) {
+ if ($1 eq 'p') {
+ $opt = 'pool_name';
+ } elsif ($1 eq 's') {
+ $opt = 'range_start';
+ } elsif ($1 eq 'e') {
+ $opt = 'range_end';
+ } elsif ($1 eq 'c') {
+ $opt = 'capacity';
+ } elsif ($1 eq 't') {
+ $opt = 'table_name';
+ } elsif ($1 eq 'd') {
+ $opt = 'dialect';
+ } elsif ($1 eq 'y') {
+ $opt = 'yaml';
+ } elsif ($1 eq 'x') {
+ $opt = 'entries';
+ } elsif ($1 eq 'f') {
+ $opt = 'raddb_dir';
+ } elsif ($1 eq 'i') {
+ $opt = 'instance';
+ } else {
+ usage();
+ exit 1;
+ }
+ } else {
+ if ($opt eq '') {
+ usage();
+ exit 1;
+ } else {
+ $opts->{$opt} = $ARGV[$i]
+ }
+ }
+}
+
+#
+# If a raddb dir is set then we parse the mods-enabled config
+#
+
+if ($opts->{raddb_dir}) {
+ my $found = 0;
+ if (-d $opts->{raddb_dir}.'/mods-enabled') {
+ opendir(my $dh, $opts->{raddb_dir}.'/mods-enabled') || die 'ERROR: Could not open directory '.$opts->{raddb_dir}.'/mods-enabled';
+ my @dir = grep { -f "$opts->{raddb_dir}/mods-enabled/$_" } readdir($dh);
+ closedir($dh);
+ my $instance = $opts->{instance};
+ foreach my $file (@dir) {
+ open (my $fh, $opts->{raddb_dir}.'/mods-enabled/'.$file);
+ my $level = 0;
+ my $section = '';
+ my $subsection = '';
+ while (<$fh>) {
+ if ($found) {
+ $_ =~ s/#.*//; # Remove comments
+ if ($_ =~ m/\s*([a-z_]+)\s*=\s*(.*)/) {
+ my $param = $1;
+ my $value = $2;
+ $value =~ s/^"//;
+ $value =~ s/"\s*$//;
+ if ($level == 1) {
+ $opts->{$param} = $value;
+ } elsif ($level == 2) {
+ $opts->{$section}->{$param} = $value;
+ } elsif ($level == 3) {
+ $opts->{$section}->{$subsection}->{$param} = $value;
+ }
+ }
+ if ($_ =~ m/([a-z_]*)\s+\{/) { # Find nested sectinos
+ $level++ ;
+ if ($level == 2) {
+ $section = $1;
+ } elsif ($level == 3) {
+ $subsection = $1;
+ }
+ }
+ $level-- if ($_ =~ m/\s+\}/); # Close of nesting
+ last if ($level == 0); # We've got to the end of the instance
+ }
+ if ($_ =~ m/\b$instance\s+\{/) {
+ # We've found the specified SQL instance
+ $found = 1;
+ $level = 1;
+ }
+ }
+ close ($fh);
+ if ($found) {
+ last;
+ }
+ }
+ } else {
+ die 'ERROR: Specified FreeRADIUS config directory does not contain mods-enabled';
+ }
+ if ($found == 0) {
+ die 'ERROR: SQL instance not found in FreeRADIUS config';
+ }
+}
+
+#
+# The SQL dialect and table name must be set
+#
+if ((!($opts->{dialect})) || (!($opts->{table_name}))) {
+ usage();
+ exit 1;
+}
+
+if ($opts->{yaml}) {
+ my $yaml_available = 0;
+
+ eval {
+ require YAML::XS;
+ YAML::XS->import('LoadFile');
+ $yaml_available = 1;
+ };
+
+ unless ($yaml_available) {
+ die "ERROR: YAML is not available. Install the YAML::XS Perl module.";
+ }
+ process_yaml_file($opts);
+
+ goto done;
+
+}
+
+
+if ((!($opts->{pool_name})) || (!($opts->{range_start})) || (!($opts->{range_end}))) {
+ usage();
+ exit 1;
+}
+
+process_commandline($opts);
+
+done:
+
+exit 0;
+
+
+sub usage {
+ print STDERR <<'EOF'
+Usage:
+ rlm_sqlippool_tool -p <pool_name> -s <range_start> -e <range_end> -t <table_name> (-d <sql_dialect> | -f <raddb_dir> [ -i <instance> ]) [ -c <capacity> ] [ -x <existing_ips_file> ]
+or:
+ rlm_sqlippool_tool -y <pool_defs_yaml_file> -t <table_name> (-d <dialect> | -f <raddb_dir> [ -i <instance> ]) [ -x <existing_ips_file> ]
+
+EOF
+}
+
+
+sub process_commandline {
+
+ my $opts = shift;
+ $SIG{__DIE__} = sub { usage(); die(@_); };
+
+ (my $template, my $queries)=load_templates($opts->{table_name});
+
+ unless (defined $template->{$opts->{dialect}}) {
+ print STDERR "Unknown dialect. Pick one of: ";
+ print STDERR "$_ " foreach sort keys %{$template};
+ print STDERR "\n";
+ exit 1;
+ }
+
+ my @entries = ();
+ @entries = load_entries($opts->{entries}) if ($opts->{entries});
+
+ @entries = handle_range($opts->{range_start}, $opts->{range_end}, $opts->{capacity}, @entries);
+
+ if ($opts->{radius_db}) {
+ &call_database($opts, $queries, @entries);
+ } else {
+ &output_sql($template->{$opts->{dialect}}, {ranges => [{pool_name => $opts->{pool_name}, ips => \@entries}], batchsize => 100, tablename => $opts->{table_name}});
+ }
+}
+
+sub process_yaml_file {
+
+ my $opts = shift;
+
+ unless (-r $opts->{yaml}) {
+ die "ERROR: Cannot open <pool_defs_yaml_file> for reading: $opts->{yaml}";
+ }
+
+ my %pool_defs = %{LoadFile($opts->{yaml})};
+
+ (my $template, my $queries)=load_templates($opts->{table_name});
+
+ unless (defined $template->{$opts->{dialect}}) {
+ print STDERR "Unknown dialect. Pick one of: ";
+ print STDERR "$_ " foreach sort keys %{$template};
+ print STDERR "\n";
+ exit 1;
+ }
+
+ my @entries = ();
+ @entries = load_entries($opts->{entries}) if ($opts->{entries});
+
+ my @ranges;
+ foreach my $pool_name (sort keys %pool_defs) {
+ foreach my $range (@{$pool_defs{$pool_name}}) {
+ my $range_start = $range->{start};
+ my $range_end = $range->{end};
+ my $capacity = $range->{capacity};
+ my @ips = handle_range($range_start, $range_end, $capacity, @entries);
+ push (@ranges, {pool_name => $pool_name, ips => \@ips});
+ }
+ }
+
+ if ($opts->{radius_db}) {
+ &call_database($opts, $queries, @entries);
+ } else {
+ &output_sql($template->{$opts->{dialect}}, {ranges => \@ranges, batchsize => 100, tablename => $opts->{table_name}});
+ }
+}
+
+sub output_sql {
+ my $template = shift();
+ my $vars = shift();
+
+ my $tt_available = 0;
+ eval {
+ require Template;
+ $tt_available = 1;
+ };
+ if ($tt_available) {
+ my $tt=Template->new();
+ $tt->process(\$template, $vars) || die $tt->error();
+ } else {
+ die "ERROR: Template Toolkit is not available. Install the Template Perl module.";
+ }
+}
+
+sub call_database {
+
+ my $opts = shift;
+ my $queries = shift;
+ my @entries = @_;
+
+ my $dbi_avail = 0;
+ eval {
+ require DBI;
+ $dbi_avail = 1;
+ };
+ unless($dbi_avail) {
+ die "ERROR: DBI is not available. Install the DBI Perl module.";
+ }
+
+ my $dsn;
+ if ($opts->{dialect} eq 'mysql') {
+ $dsn = "DBI:mysql:database=$opts->{radius_db};host=$opts->{server}";
+ if (defined($opts->{mysql}->{tls})) {
+ $dsn .= ';mysql_ssl=1';
+ $dsn .= ';mysql_ssl_ca_file='.$opts->{mysql}->{tls}->{ca_file} if ($opts->{mysql}->{tls}->{ca_file});
+ $dsn .= ';mysql_ssl_ca_path='.$opts->{mysql}->{tls}->{ca_path} if ($opts->{mysql}->{tls}->{ca_path});
+ $dsn .= ';mysql_ssl_client_key='.$opts->{mysql}->{tls}->{private_key_file} if ($opts->{mysql}->{tls}->{private_key_file});
+ $dsn .= ';mysql_ssl_client_cert='.$opts->{mysql}->{tls}->{certificate_file} if ($opts->{mysql}->{tls}->{certificate_file});
+ $dsn .= ';mysql_ssl_cipher='.$opts->{mysql}->{tls}->{cipher} if ($opts->{mysql}->{tls}->{cipher});
+ }
+ } elsif ($opts->{dialect} eq 'postgresql') {
+ # Parse FreeRADIUS alternative connection string
+ if ($opts->{radius_db} =~ m/host=(.+?)\b/) {
+ $opts->{server} = $1;
+ }
+ if ($opts->{radius_db} =~ m/user=(.+?)\b/) {
+ $opts->{login} = $1;
+ }
+ if ($opts->{radius_db} =~ m/password=(.+?)\b/) {
+ $opts->{password} = $1;
+ }
+ if ($opts->{radius_db} =~ m/sslmode=(.+?)\b/) {
+ $opts->{sslmode} = $1;
+ }
+ if ($opts->{radius_db} =~ m/dbname=(.+?)\b/) {
+ $opts->{radius_db} = $1;
+ }
+ $dsn = "DBI:Pg:dbname=$opts->{radius_db};host=$opts->{server}";
+ #
+ # DBD doesn't have all the options used by FreeRADIUS - just enable ssl if
+ # FreeRADIUS has SSL options enabled
+ #
+ $dsn .= ';sslmode=prefer' if ($opts->{sslmode});
+ } elsif ($opts->{dialect} eq 'sqlite') {
+ $dsn = "DBI:SQLite:dbname=$opts->{sqlite}->{filename}";
+ } elsif ($opts->{dialect} eq 'mssql') {
+ if ($opts->{driver} eq 'rlm_sql_unixodbc') {
+ $dsn = "DBI:ODBC:DSN=$opts->{server}";
+ } else {
+ $dsn = "DBI:Sybase:server=$opts->{server};database=$opts->{radius_db}";
+ }
+ } elsif ($opts->{dialect} eq 'oracle') {
+ # Extract data from Oracle connection string as used by FreeRADIUS
+ if ($opts->{radius_db} =~ m/HOST=(.+?)\)/) {
+ $opts->{server} = $1;
+ }
+ if ($opts->{radius_db} =~ m/PORT=(.+?)\)/) {
+ $opts->{port} =$1;
+ }
+ if ($opts->{radius_db} =~ m/SID=(.+?)\)/) {
+ $opts->{sid} = $1;
+ }
+ $dsn = "DBI:Oracle:host=$opts->{server};sid=$opts->{sid}";
+ } else {
+ $dsn = "DBI:$opts->{dialect}:database=$opts->{radius_db};host=$opts->{server}";
+ }
+ $dsn .= ";port=$opts->{port}" if ($opts->{port}) && ($opts->{driver} ne 'rlm_sql_unixodbc');
+
+ # Read the results by running our query against the database
+ my $dbh = DBI->connect($dsn, $opts->{login}, $opts->{password}) || die "Unable to connect to database";
+
+ foreach my $query (@{$queries->{$opts->{dialect}}->{pre}}) {
+ $dbh->do($query);
+ }
+
+ my $sth = $dbh->prepare($queries->{$opts->{dialect}}->{insert});
+ foreach my $ip (@entries) {
+ $sth->execute($opts->{pool_name}, $ip);
+ }
+ $sth->finish();
+
+ foreach my $query (@{$queries->{$opts->{dialect}}->{post}}) {
+ $dbh->do($query);
+ }
+
+ $dbh->disconnect();
+}
+
+sub load_entries {
+
+ my $entries_file = shift;
+
+ my @entries = ();
+ unless (-r $entries_file) {
+ die "ERROR: Cannot open <existing_ips_file> for reading: $entries_file"
+ }
+ open(my $fh, "<", $entries_file) || die "Failed to open $entries_file";
+ while(<$fh>) {
+ chomp;
+ push @entries, $_;
+ }
+
+ return @entries;
+
+}
+
+
+sub handle_range {
+
+ my $range_start = shift;
+ my $range_end = shift;
+ my $capacity = shift;
+ my @entries = @_;
+
+ unless (ip_is_ipv4($range_start) || ip_is_ipv6($range_start)) {
+ die "ERROR: Incorrectly formatted IPv4/IPv6 address for range_start: $range_start";
+ }
+
+ unless (ip_is_ipv4($range_end) || ip_is_ipv6($range_end)) {
+ die "ERROR: Incorrectly formatted IPv4/IPv6 address for range_end: $range_end";
+ }
+
+ my $ip_start = new Net::IP($range_start);
+ my $ip_end = new Net::IP($range_end);
+ my $ip_range = new Net::IP("$range_start - $range_end");
+
+ unless (defined $ip_range) {
+ die "ERROR: The range defined by <range_start> - <range_end> is invalid: $range_start - $range_end";
+ }
+
+ my $range_size = $ip_range->size;
+
+ if ($range_size < $capacity) {
+ $capacity = "$range_size";
+ warn 'WARNING: Insufficent IPs in the range. Will create '.$capacity.' entries.';
+ }
+
+ # Prune the entries to only those within the specified range
+ for (my $i = 0; $i <= $#entries; $i++) {
+ my $version = ip_is_ipv4($entries[$i]) ? 4 : 6;
+ my $binip = ip_iptobin($entries[$i],$version);
+ if ($ip_start->version != $version ||
+ ip_bincomp($binip, 'lt', $ip_start->binip) == 1 ||
+ ip_bincomp($binip, 'gt', $ip_end->binip) == 1) {
+ $entries[$i]='';
+ }
+ }
+
+ #
+ # We use the sparse method if the number of entries available occupies < 80% of
+ # the network range, otherwise we use a method that involves walking the
+ # entire range.
+ #
+
+ srand(42); # Set the seed for the PRNG
+
+ if ($capacity / "$range_size" > 0.9) {
+ @entries = walk_fill($ip_start, $ip_end, $capacity, @entries);
+ } elsif (length($range_size) > 9 || $capacity / "$range_size" < 0.8) { # From "BigInt" to FP
+ @entries = sparse_fill($ip_start, $ip_end, $capacity, @entries);
+ } else {
+ @entries = dense_fill($ip_start, $ip_end, $ip_range, $capacity, @entries);
+ }
+
+ return @entries;
+}
+
+
+#
+# With this sparse fill method we randomly allocate within the scope of the
+# smallest enclosing network prefix, checking that we are within the given
+# range, retrying if we are outside or we hit a duplicate.
+#
+# This method can efficiently choose a small number of addresses relative to
+# the size of the range. It becomes slower as the population of a range nears
+# the range's limit since it is harder to choose a free address at random.
+#
+# It is useful for selecting a handful of addresses from an enourmous IPv6 /64
+# network for example.
+#
+sub sparse_fill {
+
+ my $ip_start = shift;
+ my $ip_end = shift;
+ my $capacity = shift;
+ my @entries = @_;
+
+ # Find the smallest network that encloses the given range
+ my $version = $ip_start->version;
+ ( $ip_start->binip ^ $ip_end->binip ) =~ /^\0*/;
+ my $net_prefix = $+[0];
+ my $net_bits = substr($ip_start->binip, 0, $net_prefix);
+ my $host_length = length($ip_start->binip) - $net_prefix;
+
+ my %ips = ();
+ my $i = 0;
+ while ($i < $capacity) {
+
+ # Use the given entries first
+ my $rand_ip;
+ my $given_lease = 0;
+ shift @entries while $#entries >= 0 && $entries[0] eq '';
+ if ($#entries >= 0) {
+ $rand_ip = ip_iptobin(shift @entries, $version);
+ $given_lease = 1;
+ } else {
+ $rand_ip = $net_bits;
+ $rand_ip .= [0..1]->[rand 2] for 1..$host_length;
+ # Check that we are inside the given range
+ next if ip_bincomp($rand_ip, 'lt', $ip_start->binip) == 1 ||
+ ip_bincomp($rand_ip, 'gt', $ip_end->binip) == 1;
+ }
+
+ next if defined $ips{$rand_ip};
+
+ $ips{$rand_ip} = $given_lease ? '=' : '+';
+ $i++;
+
+ }
+
+ return map { ip_bintoip($_, $version) } keys %ips;
+
+}
+
+
+#
+# With this dense fill method, after first selecting the given entries we walk
+# the network range picking IPs with evenly distributed probability.
+#
+# This method can efficiently choose a large number of addresses relative to
+# the size of a range, provided that the range isn't massive. It becomes
+# slower as the range size increases.
+#
+sub dense_fill {
+
+ my $ip_start = shift;
+ my $ip_end = shift;
+ my $ip_range = shift;
+ my $capacity = shift;
+ my @entries = @_;
+
+ my $version = $ip_start->version;
+
+ my $one = ("0"x($version == 4 ? 31 : 127)) . '1';
+
+ my %ips = ();
+ my $remaining_entries = $capacity;
+ my $remaining_ips = $ip_range->size;
+ my $ipbin = $ip_start->binip;
+
+ while ($remaining_entries > 0 && (ip_bincomp($ipbin, 'le', $ip_end->binip) == 1)) {
+
+ # Use the given entries first
+ shift @entries while $#entries >= 0 && $entries[0] eq '';
+ if ($#entries >= 0) {
+ $ips{ip_iptobin(shift @entries, $version)} = '=';
+ $remaining_entries--;
+ $remaining_ips--;
+ next;
+ }
+
+ goto next_ip if defined $ips{$ipbin};
+
+ # Skip the IP that we have already selected by given entries, otherwise
+ # randomly pick it
+ if (!defined $ips{$ipbin} &&
+ (rand) <= $remaining_entries / "$remaining_ips") { # From "BigInt" to FP
+ $ips{$ipbin} = '+';
+ $remaining_entries--;
+ }
+
+ $remaining_ips--;
+ $ipbin = ip_binadd($ipbin,$one);
+
+ }
+
+ return map { ip_bintoip($_, $version) } keys %ips;
+
+}
+
+#
+# With this walk fill method we walk the IP range from the beginning
+# for as many IPs as are required
+#
+# It is useful for selecting a fully populated network.
+#
+
+sub walk_fill {
+ my $ip_start = shift;
+ my $ip_end = shift;
+ my $capacity = shift;
+ my @entries = @_;
+
+ my $version = $ip_start->version;
+
+ my $one = ("0"x($version == 4 ? 31 : 127)) . '1';
+
+ my %ips = ();
+ my $remaining_entries = $capacity;
+ my $ipbin = $ip_start->binip;
+
+ # Sort existing IPs and remove any blank entries. Allows existing entries to be
+ # matched quickly in the new pool
+ my @sorted_entries = sort @entries;
+ shift @sorted_entries while $#sorted_entries >= 0 && $sorted_entries[0] eq '';
+
+ # Walk through the IP range from the beginning
+ while ($remaining_entries > 0 && (ip_bincomp($ipbin, 'le', $ip_end->binip) == 1)) {
+
+ if ($#sorted_entries >= 0) {
+ # If there are existing entries check if they match
+ $ips{$ipbin} = (ip_bincomp($ipbin, 'eq', ip_iptobin($sorted_entries[0]) == 1) && shift(@sorted_entries) ? '=' : '+');
+ } else {
+ $ips{$ipbin} = '+';
+ }
+ $remaining_entries--;
+ $ipbin = ip_binadd($ipbin,$one);
+
+ }
+
+ return map { ip_bintoip($_, $version) } keys %ips;
+
+}
+
+
+
+#
+# SQL dialect templates
+#
+
+sub load_templates {
+
+ my $tablename = shift;
+
+ my $template;
+ my $queries;
+#
+# MySQL / MariaDB
+#
+ $queries->{'mysql'}->{pre} = [
+ 'DROP TEMPORARY TABLE IF EXISTS '.$tablename.'_temp;',
+ 'CREATE TEMPORARY TABLE '.$tablename.'_temp (
+ id int(11) unsigned NOT NULL auto_increment,
+ pool_name varchar(30) NOT NULL,
+ framedipaddress varchar(15) NOT NULL,
+ PRIMARY KEY (id),
+ KEY pool_name_framedipaddress (pool_name,framedipaddress)
+);'
+ ];
+ $queries->{'mysql'}->{insert} = 'INSERT INTO '.$tablename.'_temp (pool_name,framedipaddress) VALUES (?, ?)';
+ $queries->{'mysql'}->{post} = [
+ 'START TRANSACTION;',
+ 'DELETE r FROM '.$tablename.' r
+ LEFT JOIN '.$tablename.'_temp t USING (pool_name,framedipaddress)
+ WHERE t.id IS NULL;',
+ 'INSERT INTO '.$tablename.' (pool_name,framedipaddress)
+ SELECT pool_name,framedipaddress FROM '.$tablename.'_temp t WHERE NOT EXISTS (
+ SELECT * FROM '.$tablename.' r
+ WHERE r.pool_name=t.pool_name AND r.framedipaddress=t.framedipaddress
+ );',
+ 'COMMIT;'
+ ];
+ $template->{'mysql'} = join("\n", @{$queries->{'mysql'}->{pre}})."\n";
+ $template->{'mysql'} .= <<'END_mysql';
+-- Populate the temporary table
+[%- FOREACH r IN ranges %]
+[%- FOREACH i IN r.ips %]
+[%- "\n\nINSERT INTO ${tablename}_temp (pool_name,framedipaddress) VALUES" IF loop.index % batchsize == 0 %]
+[%- IF (loop.index+1) % batchsize == 0 OR loop.last %]
+('[% r.pool_name %]','[% i %]');
+[%- ELSE %]
+('[% r.pool_name %]','[% i %]'),
+[%- END %]
+[%- END %]
+[%- END %]
+END_mysql
+ $template->{'mysql'} .= join("\n", @{$queries->{'mysql'}->{post}})."\n";
+
+#
+# PostgreSQL
+#
+ $queries->{'postgresql'}->{pre} = [
+ 'DROP TABLE IF EXISTS '.$tablename.'_temp;',
+ 'CREATE TEMPORARY TABLE '.$tablename.'_temp (
+ pool_name varchar(64) NOT NULL,
+ FramedIPAddress INET NOT NULL
+);',
+ 'CREATE INDEX '.$tablename.'_temp_idx ON '.$tablename.'_temp USING btree (pool_name,FramedIPAddress);'
+ ];
+ $queries->{'postgresql'}->{insert} = 'INSERT INTO '.$tablename.'_temp (pool_name,framedipaddress) VALUES (?, ?)';
+ $queries->{'postgresql'}->{post} = [
+ 'START TRANSACTION;',
+ 'DELETE FROM '.$tablename.' r WHERE NOT EXISTS (
+ SELECT FROM '.$tablename.'_temp t
+ WHERE t.pool_name = r.pool_name AND t.framedipaddress = r.framedipaddress
+);',
+ 'INSERT INTO '.$tablename.' (pool_name,framedipaddress)
+ SELECT pool_name,framedipaddress FROM '.$tablename.'_temp t WHERE NOT EXISTS (
+ SELECT * FROM '.$tablename.' r
+ WHERE r.pool_name=t.pool_name AND r.framedipaddress=t.framedipaddress
+ );',
+ 'COMMIT;'
+ ];
+ $template->{'postgresql'} = join("\n", @{$queries->{'postgresql'}->{pre}})."\n";
+ $template->{'postgresql'} .= <<'END_postgresql';
+-- Populate the temporary table
+[%- FOREACH r IN ranges %]
+[%- FOREACH i IN r.ips %]
+[%- "\n\nINSERT INTO ${tablename}_temp (pool_name,framedipaddress) VALUES" IF loop.index % batchsize == 0 %]
+[%- IF (loop.index+1) % batchsize == 0 OR loop.last %]
+('[% r.pool_name %]','[% i %]');
+[%- ELSE %]
+('[% r.pool_name %]','[% i %]'),
+[%- END %]
+[%- END %]
+[%- END %]
+END_postgresql
+ $template->{'postgresql'} .= join("\n", @{$queries->{'postgresql'}->{post}})."\n";
+#
+# Oracle
+#
+ $queries->{'oracle'}->{pre} = [
+ 'CREATE TABLE '.$tablename.'_temp (
+ pool_name VARCHAR(30) NOT NULL,
+ FramedIPAddress VARCHAR(15) NOT NULL
+)',
+ 'CREATE INDEX '.$tablename.'_temp_idx ON '.$tablename.'_temp (pool_name,FramedIPAddress)'
+ ];
+ $queries->{'oracle'}->{insert} = 'INSERT INTO '.$tablename.'_temp (pool_name,FramedIPAddress) VALUES (?, ?)';
+ $queries->{'oracle'}->{post} = [
+ 'DELETE FROM '.$tablename.' r WHERE NOT EXISTS
+ (SELECT * FROM '.$tablename.'_temp t WHERE
+ r.pool_name = t.pool_name AND r.framedipaddress = t.framedipaddress)',
+ 'INSERT INTO '.$tablename.' (pool_name,framedipaddress)
+ SELECT pool_name,framedipaddress FROM '.$tablename.'_temp t WHERE NOT EXISTS (
+ SELECT * FROM '.$tablename.' r
+ WHERE r.pool_name=t.pool_name AND r.framedipaddress=t.framedipaddress
+ )',
+ 'DROP TABLE '.$tablename.'_temp',
+ 'COMMIT'
+ ];
+
+ $template->{'oracle'} = join(";\n", @{$queries->{'oracle'}->{pre}}).";\n";
+ $template->{'oracle'} .= <<'END_oracle';
+-- Populate the temporary table
+[%- FOREACH r IN ranges %]
+[%- FOREACH i IN r.ips %]
+[%- "\nINSERT INTO ${tablename}_temp (pool_name,framedipaddress) VALUES " %]('[% r.pool_name %]','[% i %]');
+[%- END %]
+[%- END %]
+END_oracle
+ $template->{'oracle'} .= join(";\n", @{$queries->{'oracle'}->{post}})."\n";
+
+#
+# SQLite
+#
+ $queries->{'sqlite'}->{pre} = [
+ 'DROP TABLE IF EXISTS '.$tablename.'_temp;',
+ 'CREATE TABLE '.$tablename.'_temp (
+ pool_name varchar(30) NOT NULL,
+ framedipaddress varchar(15) NOT NULL
+);',
+ 'CREATE INDEX '.$tablename.'_temp_idx ON '.$tablename.'_temp (pool_name,FramedIPAddress);'
+ ];
+ $queries->{'sqlite'}->{insert} = 'INSERT INTO '.$tablename.'_temp (pool_name,framedipaddress) VALUES (?, ?)';
+ $queries->{'sqlite'}->{post} = [
+ 'BEGIN TRANSACTION;',
+ 'DELETE FROM '.$tablename.' WHERE rowid IN (
+ SELECT r.rowid FROM '.$tablename.' r
+ LEFT JOIN '.$tablename.'_temp t USING (pool_name,framedipaddress)
+ WHERE t.rowid IS NULL);',
+ 'INSERT INTO '.$tablename.' (pool_name,framedipaddress)
+ SELECT pool_name,framedipaddress FROM '.$tablename.'_temp t WHERE NOT EXISTS (
+ SELECT * FROM '.$tablename.' r
+ WHERE r.pool_name=t.pool_name AND r.framedipaddress=t.framedipaddress
+ );',
+ 'COMMIT;',
+ 'DROP TABLE '.$tablename.'_temp;'
+ ];
+
+ $template->{'sqlite'} = join("\n", @{$queries->{'sqlite'}->{pre}})."\n";
+ $template->{'sqlite'} .= <<'END_sqlite';
+-- Populate the temporary table
+[%- FOREACH r IN ranges %]
+[%- FOREACH i IN r.ips %]
+[%- "\n\nINSERT INTO ${tablename}_temp (pool_name,framedipaddress) VALUES" IF loop.index % batchsize == 0 %]
+[%- IF (loop.index+1) % batchsize == 0 OR loop.last %]
+('[% r.pool_name %]','[% i %]');
+[%- ELSE %]
+('[% r.pool_name %]','[% i %]'),
+[%- END %]
+[%- END %]
+[%- END %]
+END_sqlite
+ $template->{'sqlite'} .= join("\n", @{$queries->{'sqlite'}->{post}})."\n";
+
+#
+# MS SQL
+#
+ $queries->{'mssql'}->{pre} = [
+ 'DROP TABLE IF EXISTS #'.$tablename.'_temp;',
+ 'CREATE TABLE #'.$tablename.'_temp (
+ id int identity(1, 1) NOT NULL,
+ pool_name varchar(30) NOT NULL,
+ framedipaddress varchar(15) NOT NULL,
+ PRIMARY KEY (id),
+);',
+ 'CREATE INDEX pool_name_framedipaddress ON #'.$tablename.'_temp(pool_name, framedipaddress);'
+ ];
+ $queries->{'mssql'}->{insert} = 'INSERT INTO #'.$tablename.'_temp (pool_name, framedipaddress) VALUES (?, ?)';
+ $queries->{'mssql'}->{post} = [
+ 'BEGIN TRAN;',
+ 'DELETE r FROM '.$tablename.' r
+ LEFT JOIN #'.$tablename.'_temp t ON r.pool_name = t.pool_name AND r.framedipaddress = t.framedipaddress
+ WHERE t.id IS NULL;',
+ 'INSERT INTO '.$tablename.' (pool_name,framedipaddress)
+ SELECT pool_name,framedipaddress FROM #'.$tablename.'_temp t WHERE NOT EXISTS (
+ SELECT * FROM '.$tablename.' r
+ WHERE r.pool_name=t.pool_name AND r.framedipaddress=t.framedipaddress
+ );',
+ 'COMMIT TRAN;'
+ ];
+
+ $template->{'mssql'} = join("\nGO\n", @{$queries->{'mssql'}->{pre}})."\nGO\n";
+ $template->{'mssql'} .= <<'END_mssql';
+-- Populate the temporary table
+[%- FOREACH r IN ranges %]
+[%- FOREACH i IN r.ips %]
+[%- "\n\nINSERT INTO #${tablename}_temp (pool_name,framedipaddress) VALUES" IF loop.index % batchsize == 0 %]
+[%- IF (loop.index+1) % batchsize == 0 OR loop.last %]
+('[% r.pool_name %]','[% i %]');
+GO
+[%- ELSE %]
+('[% r.pool_name %]','[% i %]'),
+[%- END %]
+[%- END %]
+[% END %]
+END_mssql
+ $template->{'mssql'} .= join("\n", @{$queries->{'mssql'}->{post}})."\n";
+
+ return ($template, $queries);
+
+}
+
diff --git a/scripts/sql/users2mysql.pl b/scripts/sql/users2mysql.pl
new file mode 100644
index 0000000..abaa9c0
--- /dev/null
+++ b/scripts/sql/users2mysql.pl
@@ -0,0 +1,157 @@
+#!/usr/bin/perl -w
+#
+# users2mysql.pl -- a script to parse a RADIUS users file and fill
+# a freeradius mysql database...
+#
+#
+# Script developed by Rich Puhek, Znet Telecom
+#
+# last change: Aug 8th, 2002.
+#
+
+
+
+#Modify to suit your db.
+$database="radius";
+$hostname="localhost";
+$user="radius";
+$password="passwd";
+
+
+#location of source users file:
+$users_file="/etc/raddb_cistron_backup/users";
+
+
+#The following are defaults from freeradius 0.7
+# ...shouldn't have to change.
+$groups_table="usergroup";
+$check_table="radcheck";
+$reply_table="radreply";
+
+$debug=3;
+
+use DBD::mysql;
+
+#open the users file, and the db.
+open USERS, $users_file or die "ERROR: Unable to open $users_file $!\n";
+$database = DBI->connect("DBI:mysql:$database:$hostname",$user, $password) or die "ERROR: Unable to connect to $database on $hostname $!\n";
+
+sub check_attribs {
+
+ if (!defined($_[0]) or !defined($_[1])) {
+ print "undefined parameter!\n";
+ return undef;
+ };
+
+ $attr = $_[0];
+ $val = $_[1];
+
+ if ($attr !~ /Password|Framed-IP-Address|Framed-IP-Netmask|Framed-IP-Routing|Framed-Routing|Framed-IP-Route|Password|Simultaneous-Use|Idle-Timeout|Auth-Type|Service-Type|Netmask|Framed-Protocol/ ) {
+ print "unrecognized attribute: $attr\n" if $debug>1;
+ return undef;
+ };
+
+ return undef if ( (! defined($val) ) or
+ ( ($attr =~ /Simultaneous\-Use/i) && ( $val !~ /^[0-9]*$/ ) )
+ );
+ print "attribs ok!\n" if $debug>3;
+ return "TRUE";
+};
+
+sub cleanup {
+ #clean up variables: strip leading/trailing spaces and trailing commas...
+ my $myval;
+ $myval = $_[0];
+ $myval =~ s/^\s//g;
+ $myval =~ s/\s$//g;
+ $myval =~ s/,$//;
+ return $myval;
+};
+
+
+sub user_attribute {
+ #push values into db...
+ $dtable=$_[0];
+ $duser=$_[1];
+ $dattrib=$_[2];
+ $dval=$_[3];
+
+ print "inserting \"$dattrib\", \"$dval\" for \"$duser\" in rad$dtable\n" if ( $dtable !~ /group/ and $debug>2);
+ print "inserting \"$duser\" into usergroup table as member of \"$dattrib\"\n" if ( $dtable =~ /group/ and $debug>2);
+
+ if ( $dtable =~ /group/ ) {
+ $table = "usergroup";
+ } elsif ( $dtable =~ /check/ ) {
+ $table = "radcheck";
+ } elsif ( $dtable =~ /reply/ ) {
+ $table = "radreply";
+ } else {
+ die "argh! what table is $dtable?\n";
+ };
+
+
+ if ( $table =~ /usergroup/ ) {
+ if ( $dattrib =~ /static/ ) {
+ #Delete the "dynamic" entry...
+ $return = $database->do ("DELETE FROM `$table` WHERE `UserName`='$duser' LIMIT 1");
+ };
+ $return = $database->do ("INSERT INTO `$table` SET `UserName`='$duser',`GroupName`='$dattrib'");
+
+ } else {
+ $return = $database->do ("INSERT INTO `$table` SET `UserName`='$duser',`Attribute`='$dattrib',`Value`='$dval', `op`=':='");
+ };
+ return $return;
+};
+
+
+while (<USERS>) {
+
+ chop;
+ #Skip comment lines and blank lines...
+ next if ( /^\#/ );
+ next if ( /^$/ );
+ next if ( /^\s*$/ );
+
+ if ( /^[a-zA-Z0-9]+/ ) {
+ print "located a user entry: $_\n" if $debug>6;
+ ($user,$rest) = split /\s/, $_, 2;
+ #Put user into usergroup as dynamic, if the user's attributes
+ # include an IP address, the script will change that later...
+ user_attribute("group",$user,"dynamic","");
+ @attribs = split /,/, $rest;
+ } else {
+ # Already found the user, now finding attributes...
+ @attribs = $_;
+ };
+
+ foreach $attr (@attribs) {
+ ($attrib,$value) = split /=/, $attr, 2;
+ #TODO: insert sanity checks here!
+ $value = cleanup($value) if (defined($value));
+ $attrib = cleanup($attrib) if (defined($attrib));
+ unless (check_attribs($attrib,$value)) {
+ print "ERROR: something bad with line $.: \"$attrib\", \"$value\"\n";
+ next;
+ };
+ print "attrib: $attrib has value: $value\n" if $debug>8;
+
+ if ( $attrib =~ /Framed-IP-Address/ ) {
+ #user is a static IP user...
+ $static{$user} = 1;
+ user_attribute("group",$user,"static","");
+ };
+
+ if ( $attrib =~ /Password|Simultaneous-Use/ ) {
+ #This is an individual check attribute, so we'll pass it along...
+ user_attribute("check",$user,$attrib,$value);
+ };
+ if ( $attrib =~ /Framed-IP-Address|Framed-IP-Routing|Framed-Routing/ ) {
+ #This is an individual reply attribute, so we'll pass this along...
+ user_attribute("reply",$user,$attrib,$value);
+ };
+ };
+
+};
+
+close USERS;
+exit($database->disconnect); \ No newline at end of file
diff --git a/share/LICENSE b/share/LICENSE
new file mode 100644
index 0000000..90074ad
--- /dev/null
+++ b/share/LICENSE
@@ -0,0 +1,339 @@
+Creative Commons Attribution 4.0 International Public License
+
+By exercising the Licensed Rights (defined below), You accept and agree
+to be bound by the terms and conditions of this Creative Commons
+Attribution 4.0 International Public License ("Public License"). To the
+extent this Public License may be interpreted as a contract, You are
+granted the Licensed Rights in consideration of Your acceptance of
+these terms and conditions, and the Licensor grants You such rights in
+consideration of benefits the Licensor receives from making the
+Licensed Material available under these terms and conditions.
+
+
+Section 1 -- Definitions.
+
+ a. Adapted Material means material subject to Copyright and Similar
+ Rights that is derived from or based upon the Licensed Material
+ and in which the Licensed Material is translated, altered,
+ arranged, transformed, or otherwise modified in a manner requiring
+ permission under the Copyright and Similar Rights held by the
+ Licensor. For purposes of this Public License, where the Licensed
+ Material is a musical work, performance, or sound recording,
+ Adapted Material is always produced where the Licensed Material is
+ synched in timed relation with a moving image.
+
+ b. Adapter's License means the license You apply to Your Copyright
+ and Similar Rights in Your contributions to Adapted Material in
+ accordance with the terms and conditions of this Public License.
+
+ c. Copyright and Similar Rights means copyright and/or similar rights
+ closely related to copyright including, without limitation,
+ performance, broadcast, sound recording, and Sui Generis Database
+ Rights, without regard to how the rights are labeled or
+ categorized. For purposes of this Public License, the rights
+ specified in Section 2(b)(1)-(2) are not Copyright and Similar
+ Rights.
+
+ d. Effective Technological Measures means those measures that, in the
+ absence of proper authority, may not be circumvented under laws
+ fulfilling obligations under Article 11 of the WIPO Copyright
+ Treaty adopted on December 20, 1996, and/or similar international
+ agreements.
+
+ e. Exceptions and Limitations means fair use, fair dealing, and/or
+ any other exception or limitation to Copyright and Similar Rights
+ that applies to Your use of the Licensed Material.
+
+ f. Licensed Material means the artistic or literary work, database,
+ or other material to which the Licensor applied this Public
+ License.
+
+ g. Licensed Rights means the rights granted to You subject to the
+ terms and conditions of this Public License, which are limited to
+ all Copyright and Similar Rights that apply to Your use of the
+ Licensed Material and that the Licensor has authority to license.
+
+ h. Licensor means the individual(s) or entity(ies) granting rights
+ under this Public License.
+
+ i. Share means to provide material to the public by any means or
+ process that requires permission under the Licensed Rights, such
+ as reproduction, public display, public performance, distribution,
+ dissemination, communication, or importation, and to make material
+ available to the public including in ways that members of the
+ public may access the material from a place and at a time
+ individually chosen by them.
+
+ j. Sui Generis Database Rights means rights other than copyright
+ resulting from Directive 96/9/EC of the European Parliament and of
+ the Council of 11 March 1996 on the legal protection of databases,
+ as amended and/or succeeded, as well as other essentially
+ equivalent rights anywhere in the world.
+
+ k. You means the individual or entity exercising the Licensed Rights
+ under this Public License. Your has a corresponding meaning.
+
+
+Section 2 -- Scope.
+
+ a. License grant.
+
+ 1. Subject to the terms and conditions of this Public License,
+ the Licensor hereby grants You a worldwide, royalty-free,
+ non-sublicensable, non-exclusive, irrevocable license to
+ exercise the Licensed Rights in the Licensed Material to:
+
+ a. reproduce and Share the Licensed Material, in whole or
+ in part; and
+
+ b. produce, reproduce, and Share Adapted Material.
+
+ 2. Exceptions and Limitations. For the avoidance of doubt, where
+ Exceptions and Limitations apply to Your use, this Public
+ License does not apply, and You do not need to comply with
+ its terms and conditions.
+
+ 3. Term. The term of this Public License is specified in Section
+ 6(a).
+
+ 4. Media and formats; technical modifications allowed. The
+ Licensor authorizes You to exercise the Licensed Rights in
+ all media and formats whether now known or hereafter created,
+ and to make technical modifications necessary to do so. The
+ Licensor waives and/or agrees not to assert any right or
+ authority to forbid You from making technical modifications
+ necessary to exercise the Licensed Rights, including
+ technical modifications necessary to circumvent Effective
+ Technological Measures. For purposes of this Public License,
+ simply making modifications authorized by this Section 2(a)
+ (4) never produces Adapted Material.
+
+ 5. Downstream recipients.
+
+ a. Offer from the Licensor -- Licensed Material. Every
+ recipient of the Licensed Material automatically
+ receives an offer from the Licensor to exercise the
+ Licensed Rights under the terms and conditions of this
+ Public License.
+
+ b. No downstream restrictions. You may not offer or impose
+ any additional or different terms or conditions on, or
+ apply any Effective Technological Measures to, the
+ Licensed Material if doing so restricts exercise of the
+ Licensed Rights by any recipient of the Licensed
+ Material.
+
+ 6. No endorsement. Nothing in this Public License constitutes or
+ may be construed as permission to assert or imply that You
+ are, or that Your use of the Licensed Material is, connected
+ with, or sponsored, endorsed, or granted official status by,
+ the Licensor or others designated to receive attribution as
+ provided in Section 3(a)(1)(A)(i).
+
+ b. Other rights.
+
+ 1. Moral rights, such as the right of integrity, are not
+ licensed under this Public License, nor are publicity,
+ privacy, and/or other similar personality rights; however, to
+ the extent possible, the Licensor waives and/or agrees not to
+ assert any such rights held by the Licensor to the limited
+ extent necessary to allow You to exercise the Licensed
+ Rights, but not otherwise.
+
+ 2. Patent and trademark rights are not licensed under this
+ Public License.
+
+ 3. To the extent possible, the Licensor waives any right to
+ collect royalties from You for the exercise of the Licensed
+ Rights, whether directly or through a collecting society
+ under any voluntary or waivable statutory or compulsory
+ licensing scheme. In all other cases the Licensor expressly
+ reserves any right to collect such royalties.
+
+
+Section 3 -- License Conditions.
+
+Your exercise of the Licensed Rights is expressly made subject to the
+following conditions.
+
+ a. Attribution.
+
+ 1. If You Share the Licensed Material (including in modified
+ form), You must:
+
+ a. retain the following if it is supplied by the Licensor
+ with the Licensed Material:
+
+ i. identification of the creator(s) of the Licensed
+ Material and any others designated to receive
+ attribution, in any reasonable manner requested by
+ the Licensor (including by pseudonym if
+ designated);
+
+ ii. a copyright notice;
+
+ iii. a notice that refers to this Public License;
+
+ iv. a notice that refers to the disclaimer of
+ warranties;
+
+ v. a URI or hyperlink to the Licensed Material to the
+ extent reasonably practicable;
+
+ b. indicate if You modified the Licensed Material and
+ retain an indication of any previous modifications; and
+
+ c. indicate the Licensed Material is licensed under this
+ Public License, and include the text of, or the URI or
+ hyperlink to, this Public License.
+
+ 2. You may satisfy the conditions in Section 3(a)(1) in any
+ reasonable manner based on the medium, means, and context in
+ which You Share the Licensed Material. For example, it may be
+ reasonable to satisfy the conditions by providing a URI or
+ hyperlink to a resource that includes the required
+ information.
+
+ 3. If requested by the Licensor, You must remove any of the
+ information required by Section 3(a)(1)(A) to the extent
+ reasonably practicable.
+
+ 4. If You Share Adapted Material You produce, the Adapter's
+ License You apply must not prevent recipients of the Adapted
+ Material from complying with this Public License.
+
+
+Section 4 -- Sui Generis Database Rights.
+
+Where the Licensed Rights include Sui Generis Database Rights that
+apply to Your use of the Licensed Material:
+
+ a. for the avoidance of doubt, Section 2(a)(1) grants You the right
+ to extract, reuse, reproduce, and Share all or a substantial
+ portion of the contents of the database;
+
+ b. if You include all or a substantial portion of the database
+ contents in a database in which You have Sui Generis Database
+ Rights, then the database in which You have Sui Generis Database
+ Rights (but not its individual contents) is Adapted Material; and
+
+ c. You must comply with the conditions in Section 3(a) if You Share
+ all or a substantial portion of the contents of the database.
+
+For the avoidance of doubt, this Section 4 supplements and does not
+replace Your obligations under this Public License where the Licensed
+Rights include other Copyright and Similar Rights.
+
+
+Section 5 -- Disclaimer of Warranties and Limitation of Liability.
+
+ a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
+ EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
+ AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
+ ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
+ IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
+ WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
+ ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
+ KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
+ ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
+
+ b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
+ TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
+ NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
+ INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
+ COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
+ USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
+ ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
+ DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
+ IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
+
+ c. The disclaimer of warranties and limitation of liability provided
+ above shall be interpreted in a manner that, to the extent
+ possible, most closely approximates an absolute disclaimer and
+ waiver of all liability.
+
+
+Section 6 -- Term and Termination.
+
+ a. This Public License applies for the term of the Copyright and
+ Similar Rights licensed here. However, if You fail to comply with
+ this Public License, then Your rights under this Public License
+ terminate automatically.
+
+ b. Where Your right to use the Licensed Material has terminated under
+ Section 6(a), it reinstates:
+
+ 1. automatically as of the date the violation is cured, provided
+ it is cured within 30 days of Your discovery of the
+ violation; or
+
+ 2. upon express reinstatement by the Licensor.
+
+ For the avoidance of doubt, this Section 6(b) does not affect any
+ right the Licensor may have to seek remedies for Your violations
+ of this Public License.
+
+ c. For the avoidance of doubt, the Licensor may also offer the
+ Licensed Material under separate terms or conditions or stop
+ distributing the Licensed Material at any time; however, doing so
+ will not terminate this Public License.
+
+ d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
+ License.
+
+
+Section 7 -- Other Terms and Conditions.
+
+ a. The Licensor shall not be bound by any additional or different
+ terms or conditions communicated by You unless expressly agreed.
+
+ b. Any arrangements, understandings, or agreements regarding the
+ Licensed Material not stated herein are separate from and
+ independent of the terms and conditions of this Public License.
+
+
+Section 8 -- Interpretation.
+
+ a. For the avoidance of doubt, this Public License does not, and
+ shall not be interpreted to, reduce, limit, restrict, or impose
+ conditions on any use of the Licensed Material that could lawfully
+ be made without permission under this Public License.
+
+ b. To the extent possible, if any provision of this Public License is
+ deemed unenforceable, it shall be automatically reformed to the
+ minimum extent necessary to make it enforceable. If the provision
+ cannot be reformed, it shall be severed from this Public License
+ without affecting the enforceability of the remaining terms and
+ conditions.
+
+ c. No term or condition of this Public License will be waived and no
+ failure to comply consented to unless expressly agreed to by the
+ Licensor.
+
+ d. Nothing in this Public License constitutes or may be interpreted
+ as a limitation upon, or waiver of, any privileges and immunities
+ that apply to the Licensor or You, including from the legal
+ processes of any jurisdiction or authority.
+
+
+=======================================================================
+
+Creative Commons is not a party to its public
+licenses. Notwithstanding, Creative Commons may elect to apply one of
+its public licenses to material it publishes and in those instances
+will be considered the “Licensor.†The text of the Creative Commons
+public licenses is dedicated to the public domain under the CC0 Public
+Domain Dedication. Except for the limited purpose of indicating that
+material is shared under a Creative Commons public license or as
+otherwise permitted by the Creative Commons policies published at
+creativecommons.org/policies, Creative Commons does not authorize the
+use of the trademark "Creative Commons" or any other trademark or logo
+of Creative Commons without its prior written consent including,
+without limitation, in connection with any unauthorized modifications
+to any of its public licenses or any other arrangements,
+understandings, or agreements concerning use of licensed material. For
+the avoidance of doubt, this paragraph does not form part of the
+public licenses.
+
+Creative Commons may be contacted at creativecommons.org.
diff --git a/share/Makefile b/share/Makefile
new file mode 100644
index 0000000..d3b199c
--- /dev/null
+++ b/share/Makefile
@@ -0,0 +1,13 @@
+#
+# Scripts to format dictionary files.
+#
+# $Id$
+#
+
+#
+# This should only be run by hand, and then sanity checked by hand!
+#
+format: $(wildcard dictionary*)
+ @for x in $(wildcard dictionary*) ; do \
+ ./format.pl $$x; \
+ done
diff --git a/share/attrnew.pl b/share/attrnew.pl
new file mode 100755
index 0000000..3ace68f
--- /dev/null
+++ b/share/attrnew.pl
@@ -0,0 +1,93 @@
+#!/usr/bin/env perl
+#
+# Print out the ATTRIBUTE's which are defined only once on input,
+# and any VALUE's which are defined for those attributes. It does NOT
+# print out unique VALUEs for multiple-defined attributes, though.
+#
+# Usage: cat dictionary1 dictionary2 | ./attrnew.pl > unique
+#
+# This is a bit of a hack. In order to make it work, you've got to
+# add a "fake" attribute to the end of dictionary1, so that you know
+# which attributes belong to which dictionary...
+#
+# $Id$
+#
+
+$line = 0;
+while (<>) {
+ $line++;
+
+ #
+ # Get attribute.
+ #
+ if (/^ATTRIBUTE\s+([\w-]+)\s+(\w+)\s+(\w+)(.*)/) {
+ $name=$1;
+ $value = $2;
+ $type = $3;
+ $stuff = $4;
+
+ $value =~ tr/[A-F]/[a-f]/; # normal form for hex
+ $value =~ tr/X/x/;
+
+ if ($value =~ /^0x/) {
+ $index = hex $value;
+ } else {
+ $index = $value;
+ }
+
+ if (defined $attributes{$index}) {
+ $dup{$index}++;
+ } else {
+ $first_ref{$line} = $index;
+ }
+
+ $attributes{$index} = "$name $value $type$stuff";
+ $name2val{$name} = $index;
+ next;
+ }
+
+ #
+ # Values.
+ #
+ if (/^VALUE\s+([\w-]+)\s+([\w-\/,.]+)\s+(\w+)(.*)/) {
+ $attr = $1;
+ $name = $2;
+ $value = $3;
+ $stuff = $d;
+
+ $value =~ tr/[A-F]/[a-f]/; # normal form for hex
+ $value =~ tr/X/x/;
+
+ if ($value =~ /^0x/) {
+ $index = hex $value;
+ } else {
+ $index = $value;
+ }
+
+ if (!defined $name2val{$attr}) {
+ print "# FIXME: FORWARD REF?\nVALUE $attr $name $value$stuff\n";
+ next;
+ }
+
+ $values{$name2val{$attr}}{$index} = "$attr $name $value$stuff";
+ next;
+ }
+}
+
+#
+# Print out the attributes sorted by number.
+#
+foreach $line (sort {$a <=> $b} keys %first_ref) {
+ $attr_val = $first_ref{$line};
+
+ next if (defined $dup{$attr_val});
+
+ print "ATTRIBUTE ", $attributes{$attr_val}, "\n";
+
+ next if (!defined %{$values{$attr_val}});
+
+ foreach $value (sort {$a <=> $b} keys %{$values{$attr_val}}) {
+ print "VALUE ", $values{$attr_val}{$value}, "\n";
+ }
+
+}
diff --git a/share/attrsort.pl b/share/attrsort.pl
new file mode 100755
index 0000000..8967259
--- /dev/null
+++ b/share/attrsort.pl
@@ -0,0 +1,87 @@
+#!/usr/bin/env perl
+#
+# Sort the attributes in a dictionary, and put them into a canonical
+# form. This will DESTROY any comments!
+#
+# Usage: cat dictionary | ./attrsort.pl > new
+#
+# This is a bit of a hack. The main purpose is to be able to quickly
+# "diff" two dictionaries which have significant differences...
+#
+# $Id$
+#
+
+while (<>) {
+ #
+ # Get attribute.
+ #
+ if (/^ATTRIBUTE\s+([\w-]+)\s+(\w+)\s+(\w+)(.*)/) {
+ $name=$1;
+ $value = $2;
+ $type = $3;
+ $stuff = $4;
+
+ $value =~ tr/[A-F]/[a-f]/; # normal form for hex
+ $value =~ tr/X/x/;
+
+ if ($value =~ /^0x/) {
+ $index = hex $value;
+ } else {
+ $index = $value;
+ }
+
+ $attributes{$index} = "$name $value $type$stuff";
+ $name2val{$name} = $index;
+ next;
+ }
+
+ #
+ # Values.
+ #
+ if (/^VALUE\s+([\w-]+)\s+([\w-\/,.]+)\s+(\w+)(.*)/) {
+ $attr = $1;
+ $name = $2;
+ $value = $3;
+ $stuff = $d;
+
+ $value =~ tr/[A-F]/[a-f]/; # normal form for hex
+ $value =~ tr/X/x/;
+
+ if ($value =~ /^0x/) {
+ $index = hex $value;
+ } else {
+ $index = $value;
+ }
+
+ if (!defined $name2val{$attr}) {
+ print "# FIXME: FORWARD REF?\nVALUE $attr $name $value$stuff\n";
+ next;
+ }
+
+ $values{$name2val{$attr}}{$index} = "$attr $name $value$stuff";
+ next;
+ }
+}
+
+#
+# Print out the attributes sorted by number.
+#
+foreach $attr_val (sort {$a <=> $b} keys %attributes) {
+ print "ATTRIBUTE ", $attributes{$attr_val}, "\n";
+}
+
+foreach $value (sort {$a <=> $b} keys %values) {
+ print $value, "\t", $attributes{$value}, "\n";
+}
+
+#
+# And again, this time printing out values.
+#
+foreach $attr_val (sort {$a <=> $b} keys %attributes) {
+
+ next if (!defined %{$values{$attr_val}});
+
+ foreach $value (sort {$a <=> $b} keys %{$values{$attr_val}}) {
+ print "VALUE ", $values{$attr_val}{$value}, "\n";
+ }
+}
diff --git a/share/backref.pl b/share/backref.pl
new file mode 100755
index 0000000..0630022
--- /dev/null
+++ b/share/backref.pl
@@ -0,0 +1,192 @@
+#!/usr/bin/env perl
+#
+# Cross-reference RFC attributes.
+#
+# $Id$
+#
+
+$begin_vendor = 0;
+$blank = 0;
+
+while (@ARGV) {
+ $filename = shift;
+
+ open FILE, "<$filename" or die "Failed to open $filename: $!\n";
+
+ @output = ();
+
+ while (<FILE>) {
+ #
+ # Clear out trailing whitespace
+ #
+ s/[ \t]+$//;
+
+ #
+ # And CR's
+ #
+ s/\r//g;
+
+ #
+ # Suppress multiple blank lines
+ #
+ if (/^\s+$/) {
+ next if ($blank == 1);
+ $blank = 1;
+ next;
+ }
+ $blank = 0;
+
+ #
+ # Remember the vendor
+ #
+ if (/^VENDOR\s+([\w-]+)\s+(\w+)(.*)/) {
+ $name=$1;
+ $len = length $name;
+ if ($len < 32) {
+ $lenx = 32 - $len;
+ $lenx += 7; # round up
+ $lenx /= 8;
+ $lenx = int $lenx;
+ $tabs = "\t" x $lenx;
+ } else {
+ $tabs = " ";
+ }
+ $vendor = $name;
+ next;
+ }
+
+ #
+ # Remember if we did begin-vendor.
+ #
+ if (/^BEGIN-VENDOR\s+([\w-]+)/) {
+ $begin_vendor = 1;
+ if (!defined $vendor) {
+ $vendor = $1;
+ } elsif ($vendor ne $1) {
+ # do something smart
+ }
+
+ next;
+ }
+
+ #
+ # Get attribute.
+ #
+ if (/^ATTRIBUTE\s+([\w-]+)\s+(\w+)\s+(\w+)(.*)/) {
+ $name=$1;
+ $len = length $name;
+ if ($len < 40) {
+ $lenx = 40 - $len;
+ $lenx += 7; # round up
+ $lenx /= 8;
+ $lenx = int $lenx;
+ $tabs = "\t" x $lenx;
+ if ($tabs eq "") {
+ $tabs = " ";
+ }
+ } else {
+ $tabs = " ";
+ }
+
+ $value = $2;
+ $type = $3;
+ $stuff = $4;
+
+ if ($begin_vendor == 0) {
+ #
+ # FIXME: Catch and print conflicting attributes.
+ #
+ $file{$value} = $filename;
+ $file{$value} =~ s/dictionary\.//;
+ $name{$value} = $name . $tabs;
+ }
+
+ #
+ # See if it's old format, with the vendor at the end of
+ # the line. If so, make it the new format.
+ #
+ if ($stuff =~ /$vendor/) {
+ if ($begin_vendor == 0) {
+ $begin_vendor = 1;
+ }
+ $stuff =~ s/$vendor//;
+ $stuff =~ s/\s+$//;
+ }
+
+ next;
+ }
+
+ #
+ # Values.
+ #
+ if (/^VALUE\s+([\w-]+)\s+([\w-\/,.]+)\s+(\w+)(.*)/) {
+ $attr=$1;
+ $len = length $attr;
+ if ($len < 32) {
+ $lenx = 32 - $len;
+ $lenx += 7; # round up
+ $lenx /= 8;
+ $lenx = int $lenx;
+ $tabsa = "\t" x $lenx;
+ if ($tabsa eq "") {
+ $tabsa = " ";
+ $len += 1;
+ } else {
+ $len -= $len % 8;
+ $len += 8 * length $tabsa;
+ }
+ } else {
+ $tabsa = " ";
+ $len += 1;
+ }
+
+ #
+ # For the code below, we assume that the attribute lengths
+ #
+ if ($len < 32) {
+ $lena = 0;
+ } else {
+ $lena = $len - 32;
+ }
+
+ $name = $2;
+ $len = length $name;
+ if ($len < 24) {
+ $lenx = 24 - $lena - $len;
+ $lenx += 7; # round up
+ $lenx /= 8;
+ $lenx = int $lenx;
+ $tabsn = "\t" x $lenx;
+ if ($tabsn eq "") {
+ $tabsn = " ";
+ }
+ } else {
+ $tabsn = " ";
+ }
+
+ next;
+ }
+
+ #
+ # Remember if we did this.
+ #
+ if (/^END-VENDOR/) {
+ $begin_vendor = 0;
+ }
+
+ #
+ # Everything else gets dumped out as-is.
+ #
+ }
+
+ close FILE;
+
+}
+
+#
+# Print out the attributes.
+#
+foreach $attr (sort {$a <=> $b} keys %file) {
+ print $name{$attr}, $attr, "\t", $file{$attr}, "\n";
+}
+
diff --git a/share/dct2fr b/share/dct2fr
new file mode 100755
index 0000000..e61fb83
--- /dev/null
+++ b/share/dct2fr
@@ -0,0 +1,31 @@
+#!/usr/bin/perl
+
+#
+# Horrible hack to convert Funk dictionaries to FreeRADIUS ones.
+#
+# It won't convert everything, and the files still need to be
+# edited afterwards, but it's a start.
+#
+# ./dct2fr foo.dct > dictionary.foo
+# vi dictionary.foo
+# replace 'foo' with the real vendor name
+# ./format.pl dictionary.foo
+#
+
+while (<>) {
+ if (/^MACRO\s+([^ \t\(]+)\(t,s\)\s+26\s+\[vid=(\d+)\s+type1=\%t\%\s+len1=\+2\s+data=\%s\%/) {
+ $name = $1;
+ $vendor = $2;
+
+ print "VENDOR foo $2\n";
+ print "BEGIN-VENDOR foo\n";
+ }
+
+# if (/^ATTRIBUTE\s+([^ \t]+)\s+$name\s*\((\d+),s+(\w+)\)/i) {
+
+ if (/^ATTRIBUTE\s+([^ \t]+)\s+$name\s*\((\d+)\s*,\s*(\w+)/i) {
+ print "ATTRIBUTE $1 $2 $3\n";
+ }
+}
+
+print "END-VENDOR foo\n";
diff --git a/share/dictionary b/share/dictionary
new file mode 100644
index 0000000..f91d6b8
--- /dev/null
+++ b/share/dictionary
@@ -0,0 +1,340 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Version $Id$
+#
+# DO NOT EDIT THE FILES IN THIS DIRECTORY
+#
+# The files in this directory are maintained and updated by
+# the FreeRADIUS project. Newer releases of software may update
+# or change these files.
+#
+# Use the main dictionary file (usually /etc/raddb/dictionary)
+# for local system attributes and $INCLUDEs.
+#
+#
+#
+# This file contains dictionary translations for parsing
+# requests and generating responses. All transactions are
+# composed of Attribute/Value Pairs. The value of each attribute
+# is specified as one of a few data types. Valid data types are:
+#
+# string - printable text, generally UTF-8 encoded. (The RFCs call this "text")
+# ipaddr - 4 octets in network byte order
+# ipv4prefix - 1 octet reserved, one octet prefix, 4 octets ipaddr
+# integer - 32 bit value in big endian order
+# integer64 - 64 bit value in big endian order
+# date - 32 bit value in big endian order - seconds since
+# 00:00:00 GMT, Jan. 1, 1970
+# ifid - 8 octets in network byte order
+# ipv6addr - 16 octets in network byte order
+# ipv6prefix - 1 octet reserved, one octet prefix, 16 octets ipv6addr
+# tlv - type-length-value
+#
+# FreeRADIUS includes data types which are not defined
+# in the RFC's. These data types are:
+#
+# abinary - Ascend's binary filter format.
+# byte - 8 bit unsigned integer
+# ether - 6 octets of hh:hh:hh:hh:hh:hh
+# where 'h' is hex digits, upper or lowercase.
+# short - 16-bit unsigned integer in network byte order
+# signed - 32-bit signed integer in network byte order
+# octets - raw octets, printed and input as hex strings.
+# e.g.: 0x123456789abcdef The RFCs call this "string".
+#
+# FreeRADIUS uses a number of data types which are defined in
+# RFC 6929. These data types should NEVER be used in any other
+# dictionary. We won't even list them here.
+#
+#
+# Enumerated values are stored in the user file with dictionary
+# VALUE translations for easy administration.
+#
+# Example:
+#
+# ATTRIBUTE VALUE
+# --------------- -----
+# Framed-Protocol = PPP
+# 7 = 1 (integer encoding)
+#
+
+#
+# Include compatibility dictionary for older users file. Move
+# this directive to the end of this file if you want to see the
+# old names in the logfiles, instead of the new names.
+#
+$INCLUDE dictionary.compat
+
+#
+# These dictionaries define attributes in the IETF managed space.
+# (i.e. 1..255). This is wrong. We include them here to allow them.
+# The IETF allocated ones are listed below, which gives them priority.
+#
+# i.e. don't do this. Don't use these attributes
+#
+$INCLUDE dictionary.usr.illegal
+$INCLUDE dictionary.ascend.illegal
+
+#
+# IETF allocated attributes and values. Split out into
+# the RFC which defined them.
+#
+# For a complete list of the standard attributes and values,
+# see:
+# http://www.iana.org/assignments/radius-types
+#
+$INCLUDE dictionary.rfc2865
+$INCLUDE dictionary.rfc2866
+$INCLUDE dictionary.rfc2867
+$INCLUDE dictionary.rfc2868
+$INCLUDE dictionary.rfc2869
+$INCLUDE dictionary.rfc3162
+$INCLUDE dictionary.rfc3576
+$INCLUDE dictionary.rfc3580
+$INCLUDE dictionary.rfc4072
+$INCLUDE dictionary.rfc4372
+$INCLUDE dictionary.rfc4603
+$INCLUDE dictionary.rfc4675
+$INCLUDE dictionary.rfc4679
+$INCLUDE dictionary.rfc4818
+$INCLUDE dictionary.rfc4849
+$INCLUDE dictionary.rfc5176
+$INCLUDE dictionary.rfc5447
+$INCLUDE dictionary.rfc5580
+$INCLUDE dictionary.rfc5607
+$INCLUDE dictionary.rfc5904
+$INCLUDE dictionary.rfc6519
+$INCLUDE dictionary.rfc6572
+$INCLUDE dictionary.rfc6677
+$INCLUDE dictionary.rfc6911
+$INCLUDE dictionary.rfc6929
+$INCLUDE dictionary.rfc6930
+$INCLUDE dictionary.rfc7055
+$INCLUDE dictionary.rfc7155
+$INCLUDE dictionary.rfc7268
+$INCLUDE dictionary.rfc7499
+$INCLUDE dictionary.rfc7930
+$INCLUDE dictionary.rfc8045
+$INCLUDE dictionary.rfc8559
+
+#
+# Mostly values which have been allocated by IANA under
+# "expert review", but which don't have an RFC associated with them.
+#
+$INCLUDE dictionary.iana
+
+#
+# Commented out because of attribute conflicts.
+#
+#$INCLUDE dictionary.alvarion.wimax.v2_2
+#$INCLUDE dictionary.nokia.conflict
+#$INCLUDE dictionary.openser
+#$INCLUDE dictionary.starent.vsa1
+#$INCLUDE dictionary.wimax.wichorus
+
+#
+# Vendor dictionaries are listed after the standard ones.
+#
+$INCLUDE dictionary.3com
+$INCLUDE dictionary.3gpp
+$INCLUDE dictionary.3gpp2
+$INCLUDE dictionary.acc
+$INCLUDE dictionary.acme
+$INCLUDE dictionary.actelis
+$INCLUDE dictionary.adtran
+$INCLUDE dictionary.adva
+$INCLUDE dictionary.aerohive
+$INCLUDE dictionary.airespace
+$INCLUDE dictionary.alcatel
+$INCLUDE dictionary.alcatel-lucent.aaa
+$INCLUDE dictionary.alcatel.esam
+$INCLUDE dictionary.alcatel.sr
+$INCLUDE dictionary.alteon
+$INCLUDE dictionary.altiga
+$INCLUDE dictionary.alvarion
+$INCLUDE dictionary.apc
+$INCLUDE dictionary.aptilo
+$INCLUDE dictionary.aptis
+$INCLUDE dictionary.arbor
+$INCLUDE dictionary.arista
+$INCLUDE dictionary.aruba
+$INCLUDE dictionary.ascend
+$INCLUDE dictionary.asn
+$INCLUDE dictionary.audiocodes
+$INCLUDE dictionary.avaya
+$INCLUDE dictionary.azaire
+$INCLUDE dictionary.bay
+$INCLUDE dictionary.bigswitch
+$INCLUDE dictionary.bintec
+$INCLUDE dictionary.bluecoat
+$INCLUDE dictionary.boingo
+$INCLUDE dictionary.bristol
+$INCLUDE dictionary.broadsoft
+$INCLUDE dictionary.brocade
+$INCLUDE dictionary.bskyb
+$INCLUDE dictionary.bt
+$INCLUDE dictionary.cablelabs
+$INCLUDE dictionary.cabletron
+$INCLUDE dictionary.calix
+$INCLUDE dictionary.cambium
+$INCLUDE dictionary.camiant
+$INCLUDE dictionary.centec
+$INCLUDE dictionary.checkpoint
+$INCLUDE dictionary.chillispot
+$INCLUDE dictionary.ciena
+$INCLUDE dictionary.cisco
+$INCLUDE dictionary.cisco.asa
+#
+# The Cisco VPN300 dictionary uses the same Vendor ID as the ASA one.
+# You shouldn't use both at the same time.
+#
+# Note : the altiga dictionary, not listed here, also uses the same Vendor ID
+#
+#$INCLUDE dictionary.cisco.vpn3000
+$INCLUDE dictionary.cisco.bbsm
+$INCLUDE dictionary.cisco.vpn5000
+$INCLUDE dictionary.citrix
+$INCLUDE dictionary.clavister
+$INCLUDE dictionary.cnergee
+$INCLUDE dictionary.colubris
+$INCLUDE dictionary.columbia_university
+$INCLUDE dictionary.compatible
+$INCLUDE dictionary.cosine
+$INCLUDE dictionary.covaro
+$INCLUDE dictionary.dante
+$INCLUDE dictionary.dellemc
+$INCLUDE dictionary.digium
+$INCLUDE dictionary.dlink
+$INCLUDE dictionary.dragonwave
+$INCLUDE dictionary.efficientip
+$INCLUDE dictionary.eleven
+$INCLUDE dictionary.eltex
+$INCLUDE dictionary.epygi
+$INCLUDE dictionary.equallogic
+$INCLUDE dictionary.ericsson
+$INCLUDE dictionary.ericsson.ab
+$INCLUDE dictionary.ericsson.packet.core.networks
+$INCLUDE dictionary.erx
+$INCLUDE dictionary.extreme
+$INCLUDE dictionary.f5
+$INCLUDE dictionary.fdxtended
+$INCLUDE dictionary.force10
+$INCLUDE dictionary.fortinet
+$INCLUDE dictionary.foundry
+$INCLUDE dictionary.freeradius
+$INCLUDE dictionary.freeradius.evs5
+$INCLUDE dictionary.freeswitch
+$INCLUDE dictionary.gandalf
+$INCLUDE dictionary.garderos
+$INCLUDE dictionary.gemtek
+$INCLUDE dictionary.h3c
+$INCLUDE dictionary.hillstone
+$INCLUDE dictionary.hp
+$INCLUDE dictionary.huawei
+$INCLUDE dictionary.iea
+$INCLUDE dictionary.infinera
+$INCLUDE dictionary.infoblox
+$INCLUDE dictionary.infonet
+$INCLUDE dictionary.ipunplugged
+$INCLUDE dictionary.issanni
+$INCLUDE dictionary.itk
+$INCLUDE dictionary.juniper
+$INCLUDE dictionary.karlnet
+$INCLUDE dictionary.kineto
+$INCLUDE dictionary.lancom
+$INCLUDE dictionary.lantronix
+$INCLUDE dictionary.livingston
+$INCLUDE dictionary.localweb
+$INCLUDE dictionary.lucent
+$INCLUDE dictionary.manzara
+$INCLUDE dictionary.meinberg
+$INCLUDE dictionary.mellanox
+$INCLUDE dictionary.meraki
+$INCLUDE dictionary.merit
+$INCLUDE dictionary.meru
+$INCLUDE dictionary.microsemi
+$INCLUDE dictionary.microsoft
+$INCLUDE dictionary.mikrotik
+$INCLUDE dictionary.mimosa
+$INCLUDE dictionary.motorola
+$INCLUDE dictionary.motorola.wimax
+$INCLUDE dictionary.navini
+$INCLUDE dictionary.net
+$INCLUDE dictionary.netelastic
+$INCLUDE dictionary.netscreen
+$INCLUDE dictionary.networkphysics
+$INCLUDE dictionary.nexans
+$INCLUDE dictionary.nile
+$INCLUDE dictionary.nokia
+$INCLUDE dictionary.nomadix
+$INCLUDE dictionary.nortel
+$INCLUDE dictionary.ntua
+$INCLUDE dictionary.packeteer
+$INCLUDE dictionary.paloalto
+$INCLUDE dictionary.patton
+$INCLUDE dictionary.perle
+$INCLUDE dictionary.pfsense
+$INCLUDE dictionary.pica8
+$INCLUDE dictionary.propel
+$INCLUDE dictionary.prosoft
+$INCLUDE dictionary.proxim
+$INCLUDE dictionary.purewave
+$INCLUDE dictionary.quiconnect
+$INCLUDE dictionary.quintum
+$INCLUDE dictionary.rcntec
+$INCLUDE dictionary.redcreek
+$INCLUDE dictionary.riverbed
+$INCLUDE dictionary.riverstone
+$INCLUDE dictionary.roaringpenguin
+$INCLUDE dictionary.ruckus
+$INCLUDE dictionary.ruggedcom
+$INCLUDE dictionary.sangoma
+$INCLUDE dictionary.sg
+$INCLUDE dictionary.shasta
+$INCLUDE dictionary.shiva
+$INCLUDE dictionary.siemens
+$INCLUDE dictionary.slipstream
+$INCLUDE dictionary.sofaware
+$INCLUDE dictionary.softbank
+$INCLUDE dictionary.sonicwall
+$INCLUDE dictionary.springtide
+$INCLUDE dictionary.starent
+$INCLUDE dictionary.surfnet
+$INCLUDE dictionary.symbol
+$INCLUDE dictionary.t_systems_nova
+$INCLUDE dictionary.telebit
+$INCLUDE dictionary.telkom
+$INCLUDE dictionary.telrad
+$INCLUDE dictionary.terena
+$INCLUDE dictionary.trapeze
+$INCLUDE dictionary.travelping
+$INCLUDE dictionary.tripplite
+$INCLUDE dictionary.tropos
+$INCLUDE dictionary.ukerna
+$INCLUDE dictionary.unix
+$INCLUDE dictionary.usr
+$INCLUDE dictionary.utstarcom
+$INCLUDE dictionary.valemount
+$INCLUDE dictionary.vasexperts
+$INCLUDE dictionary.verizon
+$INCLUDE dictionary.versanet
+$INCLUDE dictionary.walabi
+$INCLUDE dictionary.waverider
+$INCLUDE dictionary.wichorus
+$INCLUDE dictionary.wifialliance
+$INCLUDE dictionary.wimax
+$INCLUDE dictionary.wispr
+$INCLUDE dictionary.xedia
+$INCLUDE dictionary.xylan
+$INCLUDE dictionary.yubico
+$INCLUDE dictionary.zeus
+$INCLUDE dictionary.zte
+$INCLUDE dictionary.zyxel
+
+#
+# And finally the server internal attributes.
+# These are attributes which NEVER go into a RADIUS packet.
+#
+$INCLUDE dictionary.freeradius.internal
diff --git a/share/dictionary.3com b/share/dictionary.3com
new file mode 100644
index 0000000..1935387
--- /dev/null
+++ b/share/dictionary.3com
@@ -0,0 +1,54 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# 3com SuperStack Firewall dictionary
+# Bought from Sonicwall, apparently, from Enterprise number 8741.
+#
+# $Id$
+#
+
+VENDOR 3com 43
+
+#
+# These attributes contain the access-level value.
+#
+BEGIN-VENDOR 3com
+
+ATTRIBUTE 3Com-User-Access-Level 1 integer
+
+# Read-only access to basic network tools (ping, etc)
+VALUE 3Com-User-Access-Level 3Com-Visitor 0
+
+# Read-only access to manageable (not security) parameters
+VALUE 3Com-User-Access-Level 3Com-Monitor 1
+
+# Read-write access to manageable (not security) parameters
+VALUE 3Com-User-Access-Level 3Com-Manager 2
+
+# Read-write access to all manageable parameters
+VALUE 3Com-User-Access-Level 3Com-Administrator 3
+
+ATTRIBUTE 3Com-VLAN-Name 2 string
+ATTRIBUTE 3Com-Mobility-Profile 3 string
+ATTRIBUTE 3Com-Encryption-Type 4 string
+ATTRIBUTE 3Com-Time-Of-Day 5 string
+ATTRIBUTE 3Com-SSID 6 string
+
+# String formatted as: YY/MM/DD-HH:MM
+# NOT as a "date" attribute!
+ATTRIBUTE 3Com-End-Date 7 string
+
+# Commented out, because the 3Com documentation
+# gives it the same number as End-Date, above.
+#ATTRIBUTE 3Com-Start-Date 7 string
+
+# URL where the user is redirected after WebAAA
+ATTRIBUTE 3Com-URL 8 string
+
+ATTRIBUTE 3Com-Connect_Id 26 integer
+ATTRIBUTE 3Com-NAS-Startup-Timestamp 59 integer
+ATTRIBUTE 3Com-Ip-Host-Addr 60 string
+ATTRIBUTE 3Com-Product-ID 255 string
+
+END-VENDOR 3com
diff --git a/share/dictionary.3gpp b/share/dictionary.3gpp
new file mode 100644
index 0000000..ce5b6bc
--- /dev/null
+++ b/share/dictionary.3gpp
@@ -0,0 +1,76 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# 3GPP stuff.
+#
+# ftp://ftp.3gpp.org/specs/2002-06/R1999/29_series/29061-3a0.zip
+#
+# $Id$
+#
+VENDOR 3GPP 10415
+
+BEGIN-VENDOR 3GPP
+
+#
+# Most of the 'string' attributes are UTF-8 encoded text.
+# Maybe we want a UTF-8 'type' in the server...
+#
+ATTRIBUTE 3GPP-IMSI 1 string
+ATTRIBUTE 3GPP-Charging-ID 2 integer
+ATTRIBUTE 3GPP-PDP-Type 3 integer
+ATTRIBUTE 3GPP-Charging-Gateway-Address 4 ipaddr
+ATTRIBUTE 3GPP-GPRS-Negotiated-QoS-profile 5 string
+ATTRIBUTE 3GPP-SGSN-Address 6 ipaddr
+ATTRIBUTE 3GPP-GGSN-Address 7 ipaddr
+ATTRIBUTE 3GPP-IMSI-MCC-MNC 8 string
+ATTRIBUTE 3GPP-GGSN-MCC-MNC 9 string
+ATTRIBUTE 3GPP-NSAPI 10 string
+ATTRIBUTE 3GPP-Session-Stop-Indicator 11 byte
+ATTRIBUTE 3GPP-Selection-Mode 12 string
+ATTRIBUTE 3GPP-Charging-Characteristics 13 string
+ATTRIBUTE 3GPP-Charging-Gateway-IPv6-Address 14 ipv6addr
+ATTRIBUTE 3GPP-SGSN-IPv6-Address 15 ipv6addr
+ATTRIBUTE 3GPP-GGSN-IPv6-Address 16 ipv6addr
+
+#
+# This attribute is really an array of IPv6 addresses.
+# Why the heck couldn't they just send multiple attributes?
+#
+ATTRIBUTE 3GPP-IPv6-DNS-Servers 17 octets
+
+ATTRIBUTE 3GPP-SGSN-MCC-MNC 18 string
+ATTRIBUTE 3GPP-Teardown-Indicator 19 byte
+ATTRIBUTE 3GPP-IMEISV 20 string
+ATTRIBUTE 3GPP-RAT-Type 21 byte
+
+#
+# See http://www.3gpp.org/DynaReport/29061.htm
+# http://www.3gpp.org/DynaReport/29274.htm
+#
+ATTRIBUTE 3GPP-Location-Info 22 octets
+ATTRIBUTE 3GPP-User-Location-Info 22 octets
+ATTRIBUTE 3GPP-MS-Time-Zone 23 octets[2]
+ATTRIBUTE 3GPP-Camel-Charging-Info 24 octets
+ATTRIBUTE 3GPP-Packet-Filter 25 octets
+ATTRIBUTE 3GPP-Negotiated-DSCP 26 byte
+ATTRIBUTE 3GPP-Allocate-IP-Type 27 byte
+
+VALUE 3GPP-RAT-Type UTRAN 1
+VALUE 3GPP-RAT-Type GERAN 2
+VALUE 3GPP-RAT-Type WLAN 3
+VALUE 3GPP-RAT-Type GAN 4
+VALUE 3GPP-RAT-Type HSPA-Evolution 5
+VALUE 3GPP-RAT-Type EUTRAN 6
+VALUE 3GPP-RAT-Type Virtual 7
+VALUE 3GPP-RAT-Type IEEE-802.16e 101
+VALUE 3GPP-RAT-Type 3GPP2-eHRPD 102
+VALUE 3GPP-RAT-Type 3GPP2-HRPD 103
+VALUE 3GPP-RAT-Type 3GPP2-1xRTT 104
+
+VALUE 3GPP-Allocate-IP-Type Do-Not-Allocate 0
+VALUE 3GPP-Allocate-IP-Type Allocate-IPv4-Address 1
+VALUE 3GPP-Allocate-IP-Type Allocate-IPv6-Prefix 2
+VALUE 3GPP-Allocate-IP-Type Allocate-IPv4-and-IPv6 3
+
+END-VENDOR 3GPP
diff --git a/share/dictionary.3gpp2 b/share/dictionary.3gpp2
new file mode 100644
index 0000000..8fe3d6f
--- /dev/null
+++ b/share/dictionary.3gpp2
@@ -0,0 +1,192 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# 3GPP2 stuff.
+#
+# http://www.3gpp2.org/Public_html/specs/index.cfm
+# X.S0011-005-C v1.0
+# http://www.3gpp2.org/Public_html/specs/X.S0011-005-C_v2.0_050708.pdf
+# http://www.3gpp2.org/public_html/specs/X.S0011-005-C_v3.0_061030.pdf
+#
+# $Id$
+#
+VENDOR 3GPP2 5535
+
+BEGIN-VENDOR 3GPP2
+
+ATTRIBUTE 3GPP2-Ike-Preshared-Secret-Request 1 integer
+ATTRIBUTE 3GPP2-Security-Level 2 integer
+ATTRIBUTE 3GPP2-Pre-Shared-Secret 3 string # 18 octets
+ATTRIBUTE 3GPP2-Reverse-Tunnel-Spec 4 integer
+ATTRIBUTE 3GPP2-Diffserv-Class-Option 5 integer
+
+# Contains embedded 3GPP2 accounting attributes.
+ATTRIBUTE 3GPP2-Accounting-Container 6 octets
+ATTRIBUTE 3GPP2-Home-Agent-IP-Address 7 ipaddr
+
+# A number formed from the concatenation of the home RADIUS IP address,
+# the FA IP address, and a 32-bit Unix timestamp, all encoded as 8 ASCII
+# hex characters.
+ATTRIBUTE 3GPP2-KeyID 8 string # 22 octets
+
+ATTRIBUTE 3GPP2-PCF-IP-Address 9 ipaddr
+ATTRIBUTE 3GPP2-BSID 10 string
+ATTRIBUTE 3GPP2-User-Id 11 integer
+ATTRIBUTE 3GPP2-Forward-FCH-Mux-Option 12 integer
+ATTRIBUTE 3GPP2-Reverse-FCH-Mux-Option 13 integer
+#
+# 14-15 ?
+#
+ATTRIBUTE 3GPP2-Service-Option 16 integer
+ATTRIBUTE 3GPP2-Forward-Traffic-Type 17 integer
+ATTRIBUTE 3GPP2-Reverse-Traffic-Type 18 integer
+ATTRIBUTE 3GPP2-FCH-Frame-Size 19 integer
+ATTRIBUTE 3GPP2-Forward-FCH-RC 20 integer
+ATTRIBUTE 3GPP2-Reverse-FCH-RC 21 integer
+ATTRIBUTE 3GPP2-IP-Technology 22 integer
+ATTRIBUTE 3GPP2-Compulsory-Tunnel-Indicator 23 integer
+ATTRIBUTE 3GPP2-Release-Indicator 24 integer
+ATTRIBUTE 3GPP2-Bad-PPP-Frame-Count 25 integer
+#
+# 26-29 ?
+#
+ATTRIBUTE 3GPP2-Number-Active-Transitions 30 integer
+ATTRIBUTE 3GPP2-Terminating-SDB-Octet-Count 31 integer
+ATTRIBUTE 3GPP2-Originating-SDB-OCtet-Count 32 integer
+ATTRIBUTE 3GPP2-Terminating-Number-SDBs 33 integer
+ATTRIBUTE 3GPP2-Originating-Number-SDBs 34 integer
+# 35 ?
+ATTRIBUTE 3GPP2-IP-QoS 36 integer
+# 37-38 ?
+ATTRIBUTE 3GPP2-Airlink-Priority 39 integer
+ATTRIBUTE 3GPP2-Airlink-Record-Type 40 integer # ?
+#ATTRIBUTE 3GPP2-R-P-Session-ID 41 string
+ATTRIBUTE 3GPP2-Airlink-Sequence-Number 42 integer # ?
+ATTRIBUTE 3GPP2-Received-HDLC-Octets 43 integer
+ATTRIBUTE 3GPP2-Correlation-Id 44 string
+ATTRIBUTE 3GPP2-Module-Orig-Term-Indicator 45 octets # ?
+ATTRIBUTE 3GPP2-Inbound-Mobile-IP-Sig-Octets 46 integer
+ATTRIBUTE 3GPP2-Outbound-Mobile-IP-Sig-Octets 47 integer
+ATTRIBUTE 3GPP2-Session-Continue 48 integer
+ATTRIBUTE 3GPP2-Active-Time 49 integer
+ATTRIBUTE 3GPP2-DCCH-Frame-Size 50 integer
+ATTRIBUTE 3GPP2-Begin-Session 51 integer
+ATTRIBUTE 3GPP2-ESN 52 string
+# 53 ?
+ATTRIBUTE 3GPP2-S-Key 54 octets
+ATTRIBUTE 3GPP2-S-Request 55 integer
+ATTRIBUTE 3GPP2-S-Lifetime 56 date
+ATTRIBUTE 3GPP2-MN-HA-SPI 57 integer
+ATTRIBUTE 3GPP2-MN-HA-Shared-Key 58 string encrypt=2
+
+ATTRIBUTE 3GPP2-Remote-IP-Address 59 tlv
+ATTRIBUTE 3GPP2-Remote-IP-Address-Value 59.1 ipaddr
+ATTRIBUTE 3GPP2-Remote-IP-Address-Mask 59.2 integer
+ATTRIBUTE 3GPP2-Remote-IP-Qualifier 59.3 short
+
+# 60 - 69 are marked "reserved"
+
+ATTRIBUTE 3GPP2-Remote-IPv6-Address 70 tlv
+ATTRIBUTE 3GPP2-Remote-IPv6-Address-Value 70.1 ipv6addr
+ATTRIBUTE 3GPP2-Remote-IPv6-Address-Prefix-Length 70.2 integer
+ATTRIBUTE 3GPP2-Remote-IPv6-Address-Qualifier 70.3 tlv
+
+ATTRIBUTE 3GPP2-Remote-Address-Table-Index 71 tlv
+ATTRIBUTE 3GPP2-Remote-Address-Table-Index-Value 71.1 short
+ATTRIBUTE 3GPP2-Remote-Address-Table-Index-Qualifier 71.2 short
+
+ATTRIBUTE 3GPP2-Remote-IPv4-Addr-Octet-Count 72 tlv
+ATTRIBUTE 3GPP2-Remote-IPv4-Addr-Octet-Count-Address 72.1 ipaddr
+ATTRIBUTE 3GPP2-Remote-IPv4-Addr-Octet-Count-Mask 72.2 integer
+ATTRIBUTE 3GPP2-Remote-IPv4-Addr-Octet-Count-Forward 72.3 integer
+ATTRIBUTE 3GPP2-Remote-IPv4-Addr-Octet-Count-Reverse 72.4 integer
+ATTRIBUTE 3GPP2-Remote-IPv4-Addr-Octet-Count-Table-Index 72.5 short
+ATTRIBUTE 3GPP2-Remote-IPv4-Addr-Octet-Count-Forward-Overflow 72.6 short
+ATTRIBUTE 3GPP2-Remote-IPv4-Addr-Octet-Count-Reverse-Overflow 72.7 short
+
+ATTRIBUTE 3GPP2-Allowed-Diffserv-Marking 73 tlv
+ATTRIBUTE 3GPP2-Allowed-Diffserv-Marking-Allowed 73.1 short
+ATTRIBUTE 3GPP2-Allowed-Diffserv-Marking-Max-Class 73.2 short
+ATTRIBUTE 3GPP2-Allowed-Diffserv-Marking-Reverse-Runnel 73.3 short
+
+ATTRIBUTE 3GPP2-Service-Option-Profile 74 tlv
+ATTRIBUTE 3GPP2-Service-Option-Profile-Option 74.1 short
+
+ATTRIBUTE 3GPP2-DNS-Update-Required 75 integer
+
+# Is this 76 or 78? Check...
+#ATTRIBUTE 3GPP2-Always-On 76 integer
+# 77 ?
+#ATTRIBUTE 3GPP2-Always-On 78 integer
+ATTRIBUTE 3GPP2-Foreign-Agent-Address 79 ipaddr
+ATTRIBUTE 3GPP2-Last-User-Activity-Time 80 integer
+ATTRIBUTE 3GPP2-MN-AAA-Removal-Indication 81 integer
+ATTRIBUTE 3GPP2-RN-Packet-Data-Inactivity-Timer 82 integer
+ATTRIBUTE 3GPP2-Forward-PDCH-RC 83 integer
+ATTRIBUTE 3GPP2-Forward-DCCH-Mux-Option 84 integer
+ATTRIBUTE 3GPP2-Reverse-DCCH-Mux-Option 85 integer
+ATTRIBUTE 3GPP2-Forward-DCCH-RC 86 integer
+ATTRIBUTE 3GPP2-Reverse-DHHC-RC 87 integer
+ATTRIBUTE 3GPP2-Session-Termination-Capability 88 integer
+ATTRIBUTE 3GPP2-Allowed-Persistent-TFTs 89 integer
+
+ATTRIBUTE 3GPP2-Prepaid-Acct-Quota 90 tlv
+
+ATTRIBUTE 3GPP2-Prepaid-Acct-Quota-QuotaIDentifier 90.1 integer
+ATTRIBUTE 3GPP2-Prepaid-Acct-Quota-VolumeQuota 90.2 integer
+ATTRIBUTE 3GPP2-Prepaid-Acct-Quota-VolumeQuotaOverflow 90.3 integer
+ATTRIBUTE 3GPP2-Prepaid-Acct-Quota-VolumeThreshold 90.4 integer
+ATTRIBUTE 3GPP2-Prepaid-Acct-Quota-VolumeThresholdOverflow 90.5 integer
+ATTRIBUTE 3GPP2-Prepaid-Acct-Quota-UpdateReason 90.8 short
+
+# The next two attributes contain sub-types
+ATTRIBUTE 3GPP2-Prepaid-acct-Capability 91 octets
+ATTRIBUTE 3GPP2-MIP-Lifetime 92 octets
+
+ATTRIBUTE 3GPP2-Acct-Stop-Trigger 93 integer
+
+ATTRIBUTE 3GPP2-Service-Reference-Id 94 tlv
+ATTRIBUTE 3GPP2-Service-Reference-Id-Value 94.1 short
+ATTRIBUTE 3GPP2-Service-Reference-Main-SC-Indicator 94.2 short
+
+ATTRIBUTE 3GPP2-DNS-Update-Capability 95 integer
+ATTRIBUTE 3GPP2-Disconnect-Reason 96 integer
+
+ATTRIBUTE 3GPP2-Remote-IPv6-Octet-Count 97 tlv
+ATTRIBUTE 3GPP2-Remote-IPv6-Count-Address 97.1 ipv6addr
+ATTRIBUTE 3GPP2-Remote-IPv6-Prefix-Length 97.2 short
+ATTRIBUTE 3GPP2-Remote-IPv6-Forward-Octet-Count 97.3 integer
+ATTRIBUTE 3GPP2-Remote-IPv6-Reverse-Octet-Count 97.4 integer
+ATTRIBUTE 3GPP2-Remote-IPv6-Table-Index 97.5 short
+ATTRIBUTE 3GPP2-Remote-IPv6-Reverse-Octet-Count-Overflow 97.6 short
+
+ATTRIBUTE 3GPP2-PrePaid-Tariff-Switching 98 tlv
+ATTRIBUTE 3GPP2-Prepaid-Quota-Identifier 98.1 integer
+ATTRIBUTE 3GPP2-Prepaid-Volume-Used-After-Tariff-Switch 98.2 integer
+ATTRIBUTE 3GPP2-Prepaid-Volume-Used-ATS-Overflow 98.3 short
+ATTRIBUTE 3GPP2-Prepaid-Tariff-Switch-Interval 98.4 integer
+ATTRIBUTE 3GPP2-Prepaid-Time-Interval-After-Tariff-Switch-Update 98.5 integer
+
+ATTRIBUTE 3GPP2-MEID 116 octets # sub tlvs?
+
+ATTRIBUTE 3GPP2-DNS-Server-IP-Address 117 tlv
+ATTRIBUTE 3GPP2-DNS-Server-Primary-IP-Address 117.1 ipaddr
+ATTRIBUTE 3GPP2-DNS-Server-Secondary-IP-Address 117.2 ipaddr
+ATTRIBUTE 3GPP2-DNS-Server-Flag 117.3 byte
+ATTRIBUTE 3GPP2-DNS-Server-Entity-Type 117.4 byte
+
+VALUE 3GPP2-DNS-Server-Entity-Type HAAA 1
+VALUE 3GPP2-DNS-Server-Entity-Type VAAA 2
+
+ATTRIBUTE 3GPP2-Carrier-ID 142 string
+
+# More sub-types
+ATTRIBUTE 3GPP2-GMT-Time-Zone-Offset 143 signed
+
+ATTRIBUTE 3GPP2-HA-Request 168 integer
+ATTRIBUTE 3GPP2-HA-Authorised 169 integer
+ATTRIBUTE 3GPP2-IP-Ver-Authorised 172 integer
+ATTRIBUTE 3GPP2-MIPv4-Mesg-Id 173 string
+
+END-VENDOR 3GPP2
diff --git a/share/dictionary.acc b/share/dictionary.acc
new file mode 100644
index 0000000..c296b14
--- /dev/null
+++ b/share/dictionary.acc
@@ -0,0 +1,260 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Dictionary for Acc/Newbridge, models Tigris, Amazon, etc.
+# Written by Stephane Marzloff <smarzloff@carif-idf.org>
+# based on specifications available through ftp and the web.
+#
+# Version: @(#)dictionary.acc 1.00 smarzloff 21-Jun-1999
+#
+
+VENDOR Acc 5
+
+#
+# Acc specific
+BEGIN-VENDOR Acc
+
+ATTRIBUTE Acc-Reason-Code 1 integer
+ATTRIBUTE Acc-Ccp-Option 2 integer
+ATTRIBUTE Acc-Input-Errors 3 integer
+ATTRIBUTE Acc-Output-Errors 4 integer
+ATTRIBUTE Acc-Access-Partition 5 string
+ATTRIBUTE Acc-Customer-Id 6 string
+ATTRIBUTE Acc-Ip-Gateway-Pri 7 ipaddr
+ATTRIBUTE Acc-Ip-Gateway-Sec 8 ipaddr
+ATTRIBUTE Acc-Route-Policy 9 integer
+ATTRIBUTE Acc-ML-MLX-Admin-State 10 integer
+ATTRIBUTE Acc-ML-Call-Threshold 11 integer
+ATTRIBUTE Acc-ML-Clear-Threshold 12 integer
+ATTRIBUTE Acc-ML-Damping-Factor 13 integer
+ATTRIBUTE Acc-Tunnel-Secret 14 string
+ATTRIBUTE Acc-Clearing-Cause 15 integer
+ATTRIBUTE Acc-Clearing-Location 16 integer
+ATTRIBUTE Acc-Service-Profile 17 string
+ATTRIBUTE Acc-Request-Type 18 integer
+ATTRIBUTE Acc-Bridging-Support 19 integer
+ATTRIBUTE Acc-Apsm-Oversubscribed 20 integer
+ATTRIBUTE Acc-Acct-On-Off-Reason 21 integer
+ATTRIBUTE Acc-Tunnel-Port 22 integer
+ATTRIBUTE Acc-Dns-Server-Pri 23 ipaddr
+ATTRIBUTE Acc-Dns-Server-Sec 24 ipaddr
+ATTRIBUTE Acc-Nbns-Server-Pri 25 ipaddr
+ATTRIBUTE Acc-Nbns-Server-Sec 26 ipaddr
+ATTRIBUTE Acc-Dial-Port-Index 27 integer
+ATTRIBUTE Acc-Ip-Compression 28 integer
+ATTRIBUTE Acc-Ipx-Compression 29 integer
+ATTRIBUTE Acc-Connect-Tx-Speed 30 integer
+ATTRIBUTE Acc-Connect-Rx-Speed 31 integer
+ATTRIBUTE Acc-Modem-Modulation-Type 32 string
+ATTRIBUTE Acc-Modem-Error-Protocol 33 string
+ATTRIBUTE Acc-Callback-Delay 34 integer
+ATTRIBUTE Acc-Callback-Num-Valid 35 string
+ATTRIBUTE Acc-Callback-Mode 36 integer
+ATTRIBUTE Acc-Callback-CBCP-Type 37 integer
+ATTRIBUTE Acc-Dialout-Auth-Mode 38 integer
+ATTRIBUTE Acc-Dialout-Auth-Password 39 string
+ATTRIBUTE Acc-Dialout-Auth-Username 40 string
+ATTRIBUTE Acc-Access-Community 42 integer
+ATTRIBUTE Acc-Vpsm-Reject-Cause 43 integer
+ATTRIBUTE Acc-Ace-Token 44 string
+ATTRIBUTE Acc-Ace-Token-Ttl 45 integer
+ATTRIBUTE Acc-Ip-Pool-Name 46 string
+ATTRIBUTE Acc-Igmp-Admin-State 47 integer
+ATTRIBUTE Acc-Igmp-Version 48 integer
+ATTRIBUTE Acc-MN-HA-Secret 73 string
+ATTRIBUTE Acc-Location-Id 98 string
+ATTRIBUTE Acc-Calling-Station-Category 99 integer
+
+VALUE Acc-Reason-Code No-reason-No-Failure 0
+VALUE Acc-Reason-Code Resource-shortage 1
+VALUE Acc-Reason-Code Session-already-open 2
+VALUE Acc-Reason-Code Too-many-RADIUS-users 3
+VALUE Acc-Reason-Code No-authentication-server 4
+VALUE Acc-Reason-Code No-authentication-response 5
+VALUE Acc-Reason-Code No-accounting-server 6
+VALUE Acc-Reason-Code No-accounting-response 7
+VALUE Acc-Reason-Code Access-Denied 8
+VALUE Acc-Reason-Code Temporary-buffer-shortage 9
+VALUE Acc-Reason-Code Protocol-error 10
+VALUE Acc-Reason-Code Invalid-attribute 11
+VALUE Acc-Reason-Code Invalid-service-type 12
+VALUE Acc-Reason-Code Invalid-framed-protocol 13
+VALUE Acc-Reason-Code Invalid-attribute-value 14
+VALUE Acc-Reason-Code Invalid-user-information 15
+VALUE Acc-Reason-Code Invalid-IP-address 16
+VALUE Acc-Reason-Code Invalid-integer-syntax 17
+VALUE Acc-Reason-Code Invalid-NAS-port 18
+VALUE Acc-Reason-Code Requested-by-user 19
+VALUE Acc-Reason-Code Network-disconnect 20
+VALUE Acc-Reason-Code Service-interruption 21
+VALUE Acc-Reason-Code Physical-port-error 22
+VALUE Acc-Reason-Code Idle-timeout 23
+VALUE Acc-Reason-Code Session-timeout 24
+VALUE Acc-Reason-Code Administrative-reset 25
+VALUE Acc-Reason-Code NAS-reload-or-reset 26
+VALUE Acc-Reason-Code NAS-error 27
+VALUE Acc-Reason-Code NAS-request 28
+VALUE Acc-Reason-Code Undefined-reason-given 29
+VALUE Acc-Reason-Code Conflicting-attributes 30
+VALUE Acc-Reason-Code Port-limit-exceeded 31
+VALUE Acc-Reason-Code Facility-not-available 32
+VALUE Acc-Reason-Code Internal-config-error 33
+VALUE Acc-Reason-Code Bad-route-specification 34
+VALUE Acc-Reason-Code Access-Partition-bind-failure 35
+VALUE Acc-Reason-Code Security-violation 36
+VALUE Acc-Reason-Code Request-type-conflict 37
+VALUE Acc-Reason-Code Configuration-disallowed 38
+VALUE Acc-Reason-Code Missing-attribute 39
+VALUE Acc-Reason-Code Invalid-request 40
+VALUE Acc-Reason-Code Missing-parameter 41
+VALUE Acc-Reason-Code Invalid-parameter 42
+VALUE Acc-Reason-Code Call-cleared-with-cause 43
+VALUE Acc-Reason-Code Inopportune-config-request 44
+VALUE Acc-Reason-Code Invalid-config-parameter 45
+VALUE Acc-Reason-Code Missing-config-parameter 46
+VALUE Acc-Reason-Code Incompatible-service-profile 47
+VALUE Acc-Reason-Code Administrative-reset-2 48
+VALUE Acc-Reason-Code Administrative-reload 49
+VALUE Acc-Reason-Code Port-unneeded 50
+VALUE Acc-Reason-Code Port-preempted 51
+VALUE Acc-Reason-Code Port-suspended 52
+VALUE Acc-Reason-Code Service-unavailable 53
+VALUE Acc-Reason-Code Callback 54
+VALUE Acc-Reason-Code User-error 55
+VALUE Acc-Reason-Code Host-request 56
+
+VALUE Acc-Ccp-Option Disabled 1
+VALUE Acc-Ccp-Option Enabled 2
+
+VALUE Acc-Route-Policy Funnel 1
+VALUE Acc-Route-Policy Direct 2
+
+VALUE Acc-ML-MLX-Admin-State Enabled 1
+VALUE Acc-ML-MLX-Admin-State Disabled 2
+
+VALUE Acc-Clearing-Cause Cause-unspecified 0
+VALUE Acc-Clearing-Cause Unassigned-number 1
+VALUE Acc-Clearing-Cause No-route-to-transit-network 2
+VALUE Acc-Clearing-Cause No-route-to-destination 3
+VALUE Acc-Clearing-Cause Channel-unacceptable 6
+VALUE Acc-Clearing-Cause Call-awarded-being-delivered 7
+VALUE Acc-Clearing-Cause Normal-clearing 16
+VALUE Acc-Clearing-Cause User-busy 17
+VALUE Acc-Clearing-Cause No-user-responding 18
+VALUE Acc-Clearing-Cause User-alerted-no-answer 19
+VALUE Acc-Clearing-Cause Call-rejected 21
+VALUE Acc-Clearing-Cause Number-changed 22
+VALUE Acc-Clearing-Cause Non-selected-user-clearing 26
+VALUE Acc-Clearing-Cause Destination-out-of-order 27
+VALUE Acc-Clearing-Cause Invalid-or-incomplete-number 28
+VALUE Acc-Clearing-Cause Facility-rejected 29
+VALUE Acc-Clearing-Cause Response-to-status-inquiry 30
+VALUE Acc-Clearing-Cause Normal-unspecified-cause 31
+VALUE Acc-Clearing-Cause No-circuit-or-channel-available 34
+VALUE Acc-Clearing-Cause Network-out-of-order 38
+VALUE Acc-Clearing-Cause Temporary-failure 41
+VALUE Acc-Clearing-Cause Switching-equipment-congestion 42
+VALUE Acc-Clearing-Cause Access-information-discarded 43
+VALUE Acc-Clearing-Cause Circuit-or-channel-unavailable 44
+VALUE Acc-Clearing-Cause Circuit-or-channed-preempted 45
+VALUE Acc-Clearing-Cause Resources-unavailable 47
+VALUE Acc-Clearing-Cause Quality-of-service-unavailable 49
+VALUE Acc-Clearing-Cause Facility-not-subscribed 50
+VALUE Acc-Clearing-Cause Outgoing-calls-barred 52
+VALUE Acc-Clearing-Cause Incoming-calls-barred 54
+VALUE Acc-Clearing-Cause Bearer-capability-unauthorized 57
+VALUE Acc-Clearing-Cause Bearer-capability-not-available 58
+VALUE Acc-Clearing-Cause Service-not-available 63
+VALUE Acc-Clearing-Cause Bearer-capablity-not-implmented 65
+VALUE Acc-Clearing-Cause Channel-type-not-implemented 66
+VALUE Acc-Clearing-Cause Facility-not-implemented 69
+VALUE Acc-Clearing-Cause Restrcted-digtal-infrmtion-only 70
+VALUE Acc-Clearing-Cause Service-not-implemented 79
+VALUE Acc-Clearing-Cause Invalid-call-reference 81
+VALUE Acc-Clearing-Cause Identified-channel-doesnt-exist 82
+VALUE Acc-Clearing-Cause Call-identify-in-use 84
+VALUE Acc-Clearing-Cause No-call-suspended 85
+VALUE Acc-Clearing-Cause Suspended-call-cleared 86
+VALUE Acc-Clearing-Cause Incompatible-destination 88
+VALUE Acc-Clearing-Cause Invalid-transit-network-selctin 91
+VALUE Acc-Clearing-Cause Invalid-message 95
+VALUE Acc-Clearing-Cause Mandtory-infrmtion-elment-miss 96
+VALUE Acc-Clearing-Cause Message-not-implemented 97
+VALUE Acc-Clearing-Cause Inopportune-message 98
+VALUE Acc-Clearing-Cause Infrmtion-elemnt-not-implmented 99
+VALUE Acc-Clearing-Cause Invlid-infrmtion-element-contnt 100
+VALUE Acc-Clearing-Cause Message-incompatible-with-state 101
+VALUE Acc-Clearing-Cause Recovery-on-timer-expiration 102
+VALUE Acc-Clearing-Cause Mndtry-infrmtion-elmnt-lngt-err 103
+VALUE Acc-Clearing-Cause Protocol-error 111
+VALUE Acc-Clearing-Cause Interworking 127
+
+VALUE Acc-Clearing-Location Local-or-remote-user 0
+VALUE Acc-Clearing-Location Prvte-ntwork-serving-local-user 1
+VALUE Acc-Clearing-Location Pblic-ntwork-serving-local-user 2
+VALUE Acc-Clearing-Location Transit-network 3
+VALUE Acc-Clearing-Location Prvte-ntwork-serv-remote-user 4
+VALUE Acc-Clearing-Location Pblic-ntwork-serv-remote-user 5
+VALUE Acc-Clearing-Location International-network 6
+VALUE Acc-Clearing-Location Beyond-interworking-point 10
+
+VALUE Acc-Request-Type Ring-Indication 1
+VALUE Acc-Request-Type Dial-Request 2
+VALUE Acc-Request-Type User-Authentication 3
+VALUE Acc-Request-Type Tunnel-Authentication 4
+
+VALUE Acc-Bridging-Support Disabled 1
+VALUE Acc-Bridging-Support Enabled 2
+
+VALUE Acc-Apsm-Oversubscribed False 1
+VALUE Acc-Apsm-Oversubscribed True 2
+
+VALUE Acc-Acct-On-Off-Reason NAS-Reset 0
+VALUE Acc-Acct-On-Off-Reason NAS-Reload 1
+VALUE Acc-Acct-On-Off-Reason Configuration-Reset 2
+VALUE Acc-Acct-On-Off-Reason Configuration-Reload 3
+VALUE Acc-Acct-On-Off-Reason Enabled 4
+VALUE Acc-Acct-On-Off-Reason Disabled 5
+
+VALUE Acc-Ip-Compression Disabled 1
+VALUE Acc-Ip-Compression Enabled 2
+
+VALUE Acc-Ipx-Compression Disabled 1
+VALUE Acc-Ipx-Compression Enabled 2
+
+VALUE Acc-Callback-Mode User-Auth 0
+VALUE Acc-Callback-Mode User-Specified-E-164 3
+VALUE Acc-Callback-Mode CBCP-Callback 6
+VALUE Acc-Callback-Mode CLI-Callback 7
+
+VALUE Acc-Callback-CBCP-Type CBCP-None 1
+VALUE Acc-Callback-CBCP-Type CBCP-User-Specified 2
+VALUE Acc-Callback-CBCP-Type CBCP-Pre-Specified 3
+
+VALUE Acc-Dialout-Auth-Mode PAP 1
+VALUE Acc-Dialout-Auth-Mode CHAP 2
+VALUE Acc-Dialout-Auth-Mode CHAP-PAP 3
+VALUE Acc-Dialout-Auth-Mode NONE 4
+
+VALUE Acc-Access-Community PUBLIC 1
+VALUE Acc-Access-Community NETMAN 2
+
+# Acc-Vpsm-Reject-Cause values (available in access-reject packets only)
+VALUE Acc-Vpsm-Reject-Cause No-Access-Partition 1
+VALUE Acc-Vpsm-Reject-Cause Access-Partition-Disabled 2
+VALUE Acc-Vpsm-Reject-Cause Partition-Portlimit-Exceeded 3
+VALUE Acc-Vpsm-Reject-Cause License-Portlimit-Exceeded 4
+VALUE Acc-Vpsm-Reject-Cause Home-Server-Down 5
+VALUE Acc-Vpsm-Reject-Cause Rejected-By-Home-Server 6
+VALUE Acc-Vpsm-Reject-Cause NAS-Administratively-Disabled 7
+
+# Acc-Igmp-Admin-State values
+VALUE Acc-Igmp-Admin-State Enabled 1
+VALUE Acc-Igmp-Admin-State Disabled 2
+
+# Acc-Igmp-Version values
+VALUE Acc-Igmp-Version V1 1
+VALUE Acc-Igmp-Version V2 2
+
+END-VENDOR Acc
diff --git a/share/dictionary.acme b/share/dictionary.acme
new file mode 100644
index 0000000..c783bb1
--- /dev/null
+++ b/share/dictionary.acme
@@ -0,0 +1,241 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Acme Packet RADIUS Dictionary
+#
+# https://support.acmepacket.com
+#
+# Version: 6.2.0 30-Oct-2009 Hadriel Kaplan <hkaplan@acmepacket.com>
+#
+
+VENDOR Acme 9148
+BEGIN-VENDOR Acme
+
+#
+# Voice over IP attributes.
+#
+ATTRIBUTE Acme-FlowID_FS1_F 1 string
+ATTRIBUTE Acme-FlowType_FS1_F 2 string
+ATTRIBUTE Acme-Session-Ingress-CallId 3 string
+ATTRIBUTE Acme-Session-Egress-CallId 4 string
+
+ATTRIBUTE Acme-Flow-In-Realm_FS1_F 10 string
+ATTRIBUTE Acme-Flow-In-Src-Addr_FS1_F 11 ipaddr
+ATTRIBUTE Acme-Flow-In-Src-Port_FS1_F 12 integer
+ATTRIBUTE Acme-Flow-In-Dst-Addr_FS1_F 13 ipaddr
+ATTRIBUTE Acme-Flow-In-Dst-Port_FS1_F 14 integer
+
+ATTRIBUTE Acme-Flow-Out-Realm_FS1_F 20 string
+ATTRIBUTE Acme-Flow-Out-Src-Addr_FS1_F 21 ipaddr
+ATTRIBUTE Acme-Flow-Out-Src-Port_FS1_F 22 integer
+ATTRIBUTE Acme-Flow-Out-Dst-Addr_FS1_F 23 ipaddr
+ATTRIBUTE Acme-Flow-Out-Dst-Port_FS1_F 24 integer
+ATTRIBUTE Acme-Calling-Octets_FS1 28 integer
+ATTRIBUTE Acme-Calling-Packets_FS1 29 integer
+ATTRIBUTE Acme-Calling-RTCP-Packets-Lost_FS1 32 integer
+ATTRIBUTE Acme-Calling-RTCP-Avg-Jitter_FS1 33 integer
+ATTRIBUTE Acme-Calling-RTCP-Avg-Latency_FS1 34 integer
+ATTRIBUTE Acme-Calling-RTCP-MaxJitter_FS1 35 integer
+ATTRIBUTE Acme-Calling-RTCP-MaxLatency_FS1 36 integer
+ATTRIBUTE Acme-Calling-RTP-Packets-Lost_FS1 37 integer
+ATTRIBUTE Acme-Calling-RTP-Avg-Jitter_FS1 38 integer
+ATTRIBUTE Acme-Calling-RTP-MaxJitter_FS1 39 integer
+
+ATTRIBUTE Acme-Session-Generic-Id 40 string
+ATTRIBUTE Acme-Session-Ingress-Realm 41 string
+ATTRIBUTE Acme-Session-Egress-Realm 42 string
+ATTRIBUTE Acme-Session-Protocol-Type 43 string
+
+ATTRIBUTE Acme-Called-Octets_FS1 44 integer
+ATTRIBUTE Acme-Called-Packets_FS1 45 integer
+ATTRIBUTE Acme-Called-RTCP-Packets-Lost_FS1 46 integer
+ATTRIBUTE Acme-Called-RTCP-Avg-Jitter_FS1 47 integer
+ATTRIBUTE Acme-Called-RTCP-Avg-Latency_FS1 48 integer
+ATTRIBUTE Acme-Called-RTCP-MaxJitter_FS1 49 integer
+ATTRIBUTE Acme-Called-RTCP-MaxLatency_FS1 50 integer
+ATTRIBUTE Acme-Called-RTP-Packets-Lost_FS1 51 integer
+ATTRIBUTE Acme-Called-RTP-Avg-Jitter_FS1 52 integer
+ATTRIBUTE Acme-Called-RTP-MaxJitter_FS1 53 integer
+
+ATTRIBUTE Acme-Session-Charging-Vector 54 string
+ATTRIBUTE Acme-Session-Charging-Function_Address 55 string
+
+ATTRIBUTE Acme-Firmware-Version 56 string
+ATTRIBUTE Acme-Local-Time-Zone 57 string
+
+ATTRIBUTE Acme-Post-Dial-Delay 58 integer
+ATTRIBUTE Acme-CDR-Sequence-Number 59 integer
+ATTRIBUTE Acme-Session-Disposition 60 integer
+ATTRIBUTE Acme-Disconnect-Initiator 61 integer
+ATTRIBUTE Acme-Disconnect-Cause 62 integer
+ATTRIBUTE Acme-Intermediate_Time 63 string
+ATTRIBUTE Acme-Primary-Routing-Number 64 string
+ATTRIBUTE Acme-Originating-Trunk-Group 65 string
+ATTRIBUTE Acme-Terminating-Trunk-Group 66 string
+ATTRIBUTE Acme-Originating-Trunk-Context 67 string
+ATTRIBUTE Acme-Terminating-Trunk-Context 68 string
+ATTRIBUTE Acme-P-Asserted-ID 69 string
+ATTRIBUTE Acme-SIP-Diversion 70 string
+ATTRIBUTE Acme-SIP-Status 71 integer
+# 72 unused
+# 73 unused
+ATTRIBUTE Acme-Ingress-Local-Addr 74 string
+ATTRIBUTE Acme-Ingress-Remote-Addr 75 string
+ATTRIBUTE Acme-Egress-Local-Addr 76 string
+ATTRIBUTE Acme-Egress-Remote-Addr 77 string
+
+ATTRIBUTE Acme-FlowID_FS1_R 78 string
+ATTRIBUTE Acme-FlowType_FS1_R 79 string
+ATTRIBUTE Acme-Flow-In-Realm_FS1_R 80 string
+ATTRIBUTE Acme-Flow-In-Src-Addr_FS1_R 81 ipaddr
+ATTRIBUTE Acme-Flow-In-Src-Port_FS1_R 82 integer
+ATTRIBUTE Acme-Flow-In-Dst-Addr_FS1_R 83 ipaddr
+ATTRIBUTE Acme-Flow-In-Dst-Port_FS1_R 84 integer
+ATTRIBUTE Acme-Flow-Out-Realm_FS1_R 85 string
+ATTRIBUTE Acme-Flow-Out-Src-Addr_FS1_R 86 ipaddr
+ATTRIBUTE Acme-Flow-Out-Src-Port_FS1_R 87 integer
+ATTRIBUTE Acme-Flow-Out-Dst-Addr_FS1_R 88 ipaddr
+ATTRIBUTE Acme-Flow-Out-Dst-Port_FS1_R 89 integer
+ATTRIBUTE Acme-FlowID_FS2_F 90 string
+ATTRIBUTE Acme-FlowType_FS2_F 91 string
+ATTRIBUTE Acme-Flow-In-Realm_FS2_F 92 string
+ATTRIBUTE Acme-Flow-In-Src-Addr_FS2_F 93 ipaddr
+ATTRIBUTE Acme-Flow-In-Src-Port_FS2_F 94 integer
+ATTRIBUTE Acme-Flow-In-Dst-Addr_FS2_F 95 ipaddr
+ATTRIBUTE Acme-Flow-In-Dst-Port_FS2_F 96 integer
+ATTRIBUTE Acme-Flow-Out-Realm_FS2_F 97 string
+ATTRIBUTE Acme-Flow-Out-Src-Addr_FS2_F 98 ipaddr
+ATTRIBUTE Acme-Flow-Out-Src-Port_FS2_F 99 integer
+ATTRIBUTE Acme-Flow-Out-Dst-Addr_FS2_F 100 ipaddr
+ATTRIBUTE Acme-Flow-Out-Dst-Port_FS2_F 101 integer
+ATTRIBUTE Acme-Calling-Octets_FS2 102 integer
+ATTRIBUTE Acme-Calling-Packets_FS2 103 integer
+ATTRIBUTE Acme-Calling-RTCP-Packets-Lost_FS2 104 integer
+ATTRIBUTE Acme-Calling-RTCP-Avg-Jitter_FS2 105 integer
+ATTRIBUTE Acme-Calling-RTCP-Avg-Latency_FS2 106 integer
+ATTRIBUTE Acme-Calling-RTCP-MaxJitter_FS2 107 integer
+ATTRIBUTE Acme-Calling-RTCP-MaxLatency_FS2 108 integer
+ATTRIBUTE Acme-Calling-RTP-Packets-Lost_FS2 109 integer
+ATTRIBUTE Acme-Calling-RTP-Avg-Jitter_FS2 110 integer
+ATTRIBUTE Acme-Calling-RTP-MaxJitter_FS2 111 integer
+
+ATTRIBUTE Acme-FlowID_FS2_R 112 string
+ATTRIBUTE Acme-FlowType_FS2_R 113 string
+ATTRIBUTE Acme-Flow-In-Realm_FS2_R 114 string
+ATTRIBUTE Acme-Flow-In-Src-Addr_FS2_R 115 ipaddr
+ATTRIBUTE Acme-Flow-In-Src-Port_FS2_R 116 integer
+ATTRIBUTE Acme-Flow-In-Dst-Addr_FS2_R 117 ipaddr
+ATTRIBUTE Acme-Flow-In-Dst-Port_FS2_R 118 integer
+ATTRIBUTE Acme-Flow-Out-Realm_FS2_R 119 string
+ATTRIBUTE Acme-Flow-Out-Src-Addr_FS2_R 120 ipaddr
+ATTRIBUTE Acme-Flow-Out-Src-Port_FS2_R 121 integer
+ATTRIBUTE Acme-Flow-Out-Dst-Addr_FS2_R 122 ipaddr
+ATTRIBUTE Acme-Flow-Out-Dst-Port_FS2_R 123 integer
+ATTRIBUTE Acme-Called-Octets_FS2 124 integer
+ATTRIBUTE Acme-Called-Packets_FS2 125 integer
+ATTRIBUTE Acme-Called-RTCP-Packets-Lost_FS2 126 integer
+ATTRIBUTE Acme-Called-RTCP-Avg-Jitter_FS2 127 integer
+ATTRIBUTE Acme-Called-RTCP-Avg-Latency_FS2 128 integer
+ATTRIBUTE Acme-Called-RTCP-MaxJitter_FS2 129 integer
+ATTRIBUTE Acme-Called-RTCP-MaxLatency_FS2 130 integer
+ATTRIBUTE Acme-Called-RTP-Packets-Lost_FS2 131 integer
+ATTRIBUTE Acme-Called-RTP-Avg-Jitter_FS2 132 integer
+ATTRIBUTE Acme-Called-RTP-MaxJitter_FS2 133 integer
+
+ATTRIBUTE Acme-Egress-Final-Routing-Number 134 string
+ATTRIBUTE Acme-Session-Ingress-RPH 135 string
+ATTRIBUTE Acme-Session-Egress-RPH 136 string
+ATTRIBUTE Acme-Ingress-Network-Interface-Id 137 string
+ATTRIBUTE Acme-Ingress-Vlan-Tag-Value 138 integer
+ATTRIBUTE Acme-Egress-Network-Interface-Id 139 string
+ATTRIBUTE Acme-Egress-Vlan-Tag-Value 140 integer
+ATTRIBUTE Acme-Refer-Call-Transfer-Id 141 string
+
+# Transcoding attributes
+ATTRIBUTE Acme-FlowMediaType_FS1_F 142 string
+ATTRIBUTE Acme-FlowMediaType_FS1_R 143 string
+ATTRIBUTE Acme-FlowMediaType_FS2_F 144 string
+ATTRIBUTE Acme-FlowMediaType_FS2_R 145 string
+ATTRIBUTE Acme-Flow-PTime_FS1_F 146 integer
+ATTRIBUTE Acme-Flow-PTime_FS1_R 147 integer
+ATTRIBUTE Acme-Flow-PTime_FS2_F 148 integer
+ATTRIBUTE Acme-Flow-PTime_FS2_R 149 integer
+ATTRIBUTE Acme-Session-Media-Process 150 string
+
+# QoS measurement attributes
+ATTRIBUTE Acme-Calling-R-Factor 151 integer
+ATTRIBUTE Acme-Calling-MOS 152 integer
+ATTRIBUTE Acme-Called-R-Factor 153 integer
+ATTRIBUTE Acme-Called-MOS 154 integer
+
+# IPV6 attributes
+ATTRIBUTE Acme-Flow-In-Src-IPv6_Addr_FS1_F 155 ipv6addr
+ATTRIBUTE Acme-Flow-In-Dst-IPv6_Addr_FS1_F 156 ipv6addr
+ATTRIBUTE Acme-Flow-Out-Src-IPv6_Addr_FS1_F 157 ipv6addr
+ATTRIBUTE Acme-Flow-Out-Dst-IPv6_Addr_FS1_F 158 ipv6addr
+ATTRIBUTE Acme-Flow-In-Src-IPv6_Addr_FS1_R 159 ipv6addr
+ATTRIBUTE Acme-Flow-In-Dst-IPv6_Addr_FS1_R 160 ipv6addr
+ATTRIBUTE Acme-Flow-Out-Src-IPv6_Addr_FS1_R 161 ipv6addr
+ATTRIBUTE Acme-Flow-Out-Dst-IPv6_Addr_FS1_R 162 ipv6addr
+ATTRIBUTE Acme-Flow-In-Src-IPv6_Addr_FS2_F 163 ipv6addr
+ATTRIBUTE Acme-Flow-In-Dst-IPv6_Addr_FS2_F 164 ipv6addr
+ATTRIBUTE Acme-Flow-Out-Src-IPv6_Addr_FS2_F 165 ipv6addr
+ATTRIBUTE Acme-Flow-Out-Dst-IPv6_Addr_FS2_F 166 ipv6addr
+ATTRIBUTE Acme-Flow-In-Src-IPv6_Addr_FS2_R 167 ipv6addr
+ATTRIBUTE Acme-Flow-In-Dst-IPv6_Addr_FS2_R 168 ipv6addr
+ATTRIBUTE Acme-Flow-Out-Src-IPv6_Addr_FS2_R 169 ipv6addr
+ATTRIBUTE Acme-Flow-Out-Dst-IPv6_Addr_FS2_R 170 ipv6addr
+
+ATTRIBUTE Acme-Session-Forked-Call-Id 171 string
+
+#
+# Customizable attributes - all strings, but content based on system config
+#
+ATTRIBUTE Acme-Custom-VSA-200 200 string
+ATTRIBUTE Acme-Custom-VSA-201 201 string
+ATTRIBUTE Acme-Custom-VSA-202 202 string
+ATTRIBUTE Acme-Custom-VSA-203 203 string
+ATTRIBUTE Acme-Custom-VSA-204 204 string
+ATTRIBUTE Acme-Custom-VSA-205 205 string
+ATTRIBUTE Acme-Custom-VSA-206 206 string
+ATTRIBUTE Acme-Custom-VSA-207 207 string
+ATTRIBUTE Acme-Custom-VSA-208 208 string
+ATTRIBUTE Acme-Custom-VSA-209 209 string
+ATTRIBUTE Acme-Custom-VSA-210 210 string
+ATTRIBUTE Acme-Custom-VSA-211 211 string
+ATTRIBUTE Acme-Custom-VSA-212 212 string
+ATTRIBUTE Acme-Custom-VSA-213 213 string
+ATTRIBUTE Acme-Custom-VSA-214 214 string
+ATTRIBUTE Acme-Custom-VSA-215 215 string
+ATTRIBUTE Acme-Custom-VSA-216 216 string
+ATTRIBUTE Acme-Custom-VSA-217 217 string
+ATTRIBUTE Acme-Custom-VSA-218 218 string
+ATTRIBUTE Acme-Custom-VSA-219 219 string
+ATTRIBUTE Acme-Custom-VSA-220 220 string
+ATTRIBUTE Acme-Custom-VSA-221 221 string
+ATTRIBUTE Acme-Custom-VSA-222 222 string
+ATTRIBUTE Acme-Custom-VSA-223 223 string
+ATTRIBUTE Acme-Custom-VSA-224 224 string
+ATTRIBUTE Acme-Custom-VSA-225 225 string
+ATTRIBUTE Acme-Custom-VSA-226 226 string
+ATTRIBUTE Acme-Custom-VSA-227 227 string
+ATTRIBUTE Acme-Custom-VSA-228 228 string
+ATTRIBUTE Acme-Custom-VSA-229 229 string
+ATTRIBUTE Acme-Custom-VSA-230 230 string
+
+ATTRIBUTE Acme-Flow-Calling-Media-Stop-Time-FS1 231 string
+ATTRIBUTE Acme-Flow-Called-Media-Stop-Time-FS1 232 string
+ATTRIBUTE Acme-Flow-Calling-Media-Stop-Time-FS2 233 string
+ATTRIBUTE Acme-Flow-Called-Media-Stop-Time-FS2 234 string
+ATTRIBUTE Acme-SIP-Method-Type 235 string
+ATTRIBUTE Acme-Domain-Name 236 string
+ATTRIBUTE Acme-SIP-Contact 237 string
+ATTRIBUTE Acme-SIP-Expires 238 integer
+ATTRIBUTE Acme-Reason-Phrase 239 string
+
+ATTRIBUTE Acme-User-Privilege 253 string
+
+ATTRIBUTE Acme-User-Class 254 string
+
+END-VENDOR Acme
diff --git a/share/dictionary.actelis b/share/dictionary.actelis
new file mode 100644
index 0000000..e071053
--- /dev/null
+++ b/share/dictionary.actelis
@@ -0,0 +1,19 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Actelis dictionary
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR Actelis 5468
+
+BEGIN-VENDOR Actelis
+
+ATTRIBUTE Actelis-Privilege 1 string
+
+END-VENDOR Actelis
diff --git a/share/dictionary.adtran b/share/dictionary.adtran
new file mode 100644
index 0000000..5abf63e
--- /dev/null
+++ b/share/dictionary.adtran
@@ -0,0 +1,18 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+
+VENDOR Adtran 664
+
+BEGIN-VENDOR Adtran
+
+# Managed WiFi attributes
+
+ATTRIBUTE Adtran-AP-Name 100 string
+ATTRIBUTE Adtran-AP-IP 101 ipaddr
+ATTRIBUTE Adtran-AP-Template 102 string
+ATTRIBUTE Adtran-SSID 103 string
+ATTRIBUTE Adtran-Role 104 string
+
+END-VENDOR Adtran
diff --git a/share/dictionary.adva b/share/dictionary.adva
new file mode 100644
index 0000000..b056a70
--- /dev/null
+++ b/share/dictionary.adva
@@ -0,0 +1,41 @@
+# -*- text -*-
+# Copyright (C) 2022 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Dictionary for ADVA Optical Networking Fiber Service Platform
+#
+# $Id$
+#
+# http://www.advaoptical.com
+#
+##############################################################################
+
+VENDOR Adva 2544
+
+BEGIN-VENDOR Adva
+
+ATTRIBUTE Adva-User-Level 100 integer
+
+VALUE Adva-User-Level Super 5
+VALUE Adva-User-Level Admin 4
+VALUE Adva-User-Level Provision 3
+VALUE Adva-User-Level Operate_Control 2
+VALUE Adva-User-Level Reserved 1
+VALUE Adva-User-Level Retrieve 0
+
+ATTRIBUTE Adva-UUM-User-Level 102 integer
+
+VALUE Adva-UUM-User-Level Root 5
+VALUE Adva-UUM-User-Level Admin 4
+VALUE Adva-UUM-User-Level Provision 3
+VALUE Adva-UUM-User-Level Operator 2
+VALUE Adva-UUM-User-Level Reserved 1
+VALUE Adva-UUM-User-Level Monitor 0
+
+# ADVA Network Manager settings
+ATTRIBUTE Adva-Auth-Level-NM 101 string
+
+END-VENDOR Adva
+
diff --git a/share/dictionary.aerohive b/share/dictionary.aerohive
new file mode 100644
index 0000000..53b4dae
--- /dev/null
+++ b/share/dictionary.aerohive
@@ -0,0 +1,75 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Aerohive (now Extreme Networks, Inc.)
+#
+# $Id$
+#
+VENDOR Aerohive 26928
+
+BEGIN-VENDOR Aerohive
+#BEGIN-VENDOR Extreme
+
+# Source: http://docs.aerohive.com/330000/docs/help/english/ng/Content/reference/docs/radius-dictionary.htm
+# Last-updated-date 25-October-2017
+# Extreme supports a small set of Vendor-Specific-Attributes for
+# administrative access to HiveManager Classic, and a different set
+# of Vendor-Specific-Attributes for HiveOS. Both are documented in
+# this file.
+
+# Most customer will wish to import this file in it’s entirety into
+# their local RADIUS data store.
+
+# Beginning of HiveManager Classic VSAs
+# The following ATTRIBUTE and VALUE definitions are required.
+ATTRIBUTE AH-HM-Admin-Group-Id 1 integer
+VALUE AH-HM-Admin-Group-Id Read-Only-Admin 0
+VALUE AH-HM-Admin-Group-Id Super-Admin 1
+VALUE AH-HM-Admin-Group-Id Read-Write-Admin 2
+
+# The following is an example of an admin group that you can define.
+#VALUE AH-HM-Admin-Group-Id Admin-Group100 100
+
+# End of HiveManager Classic VSAs
+# Beginning of HiveOS VSAs
+
+ATTRIBUTE Extreme-User-Vlan 1 integer
+ATTRIBUTE Extreme-Libsip-Patron-Info 3 octets encrypt=2
+ATTRIBUTE Extreme-Libsip-Action 4 integer
+ATTRIBUTE Extreme-Libsip-Additional-Message 5 octets
+ATTRIBUTE Extreme-User-Profile-Attribute 6 integer
+ATTRIBUTE Extreme-Data-Usage-Limit 7 octets
+ATTRIBUTE Extreme-AVPair 8 string
+ATTRIBUTE Extreme-Radius-Code 9 integer
+ATTRIBUTE Extreme-PPSK-Request 201 octets
+ATTRIBUTE Extreme-PPSK-PMK 202 octets
+ATTRIBUTE Extreme-IDM-Message 203 integer
+ATTRIBUTE Extreme-NT-Identity 204 integer
+ATTRIBUTE Extreme-User-Language 205 string
+ATTRIBUTE Extreme-Time-Zone-Offset 207 integer
+ATTRIBUTE Extreme-Daylight-Saving-Offset 208 integer
+ATTRIBUTE Extreme-Client-Monitor-Session 209 octets
+ATTRIBUTE Extreme-Client-Monitor-Problem 210 integer
+ATTRIBUTE Extreme-IDM-Redirect-URL 211 string
+ATTRIBUTE Extreme-MGT-MAC-Address 212 string
+ATTRIBUTE Extreme-Auth-Source 213 integer
+
+#
+# Integer Translations
+#
+
+# Extreme-Libsip-Action Values
+VALUE Extreme-Libsip-Action Permit 0
+VALUE Extreme-Libsip-Action Restricted 1
+VALUE Extreme-Libsip-Action Deny 2
+
+# Extreme-Radius-Code Values
+VALUE Extreme-Radius-Code Disconnect-Request 1
+VALUE Extreme-Radius-Code COA-Request 2
+
+# Extreme-Auth-Source
+VALUE Extreme-Auth-Source Service 1
+VALUE Extreme-Auth-Source Non-Service 2
+
+END-VENDOR Aerohive
diff --git a/share/dictionary.airespace b/share/dictionary.airespace
new file mode 100644
index 0000000..1a49ec6
--- /dev/null
+++ b/share/dictionary.airespace
@@ -0,0 +1,33 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# As found on the net.
+#
+# $Id$
+#
+VENDOR Airespace 14179
+
+BEGIN-VENDOR Airespace
+ATTRIBUTE Airespace-Wlan-Id 1 integer
+ATTRIBUTE Airespace-QOS-Level 2 integer
+ATTRIBUTE Airespace-DSCP 3 integer
+ATTRIBUTE Airespace-8021p-Tag 4 integer
+ATTRIBUTE Airespace-Interface-Name 5 string
+ATTRIBUTE Airespace-ACL-Name 6 string
+ATTRIBUTE Airespace-Data-Bandwidth-Average-Contract 7 integer
+ATTRIBUTE Airespace-Real-Time-Bandwidth-Average-Contract 8 integer
+ATTRIBUTE Airespace-Data-Bandwidth-Burst-Contract 9 integer
+ATTRIBUTE Airespace-Real-Time-Bandwidth-Burst-Contract 10 integer
+ATTRIBUTE Airespace-Guest-Role-Name 11 string
+ATTRIBUTE Airespace-Data-Bandwidth-Average-Contract-Upstream 13 integer
+ATTRIBUTE Airespace-Real-Time-Bandwidth-Average-Contract-Upstream 14 integer
+ATTRIBUTE Airespace-Data-Bandwidth-Burst-Contract-Upstream 15 integer
+ATTRIBUTE Airespace-Real-Time-Bandwidth-Burst-Contract-Upstream 16 integer
+
+VALUE Airespace-QOS-Level Bronze 3
+VALUE Airespace-QOS-Level Silver 0
+VALUE Airespace-QOS-Level Gold 1
+VALUE Airespace-QOS-Level Platinum 2
+
+END-VENDOR Airespace
diff --git a/share/dictionary.alcatel b/share/dictionary.alcatel
new file mode 100644
index 0000000..591424c
--- /dev/null
+++ b/share/dictionary.alcatel
@@ -0,0 +1,101 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Alcatel Broadband Access Server dictionary.
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR Alcatel 3041
+
+BEGIN-VENDOR Alcatel
+
+ATTRIBUTE AAT-Client-Primary-DNS 5 ipaddr
+ATTRIBUTE AAT-Client-Primary-WINS-NBNS 6 ipaddr
+ATTRIBUTE AAT-Client-Secondary-WINS-NBNS 7 ipaddr
+ATTRIBUTE AAT-Client-Secondary-DNS 8 ipaddr
+ATTRIBUTE AAT-PPP-Address 9 ipaddr
+ATTRIBUTE AAT-PPP-Netmask 10 ipaddr
+ATTRIBUTE AAT-Primary-Home-Agent 12 string
+ATTRIBUTE AAT-Secondary-Home-Agent 13 string
+ATTRIBUTE AAT-Home-Agent-Password 14 string
+ATTRIBUTE AAT-Home-Network-Name 15 string
+ATTRIBUTE AAT-Home-Agent-UDP-Port 16 integer
+ATTRIBUTE AAT-IP-Direct 17 ipaddr
+ATTRIBUTE AAT-FR-Direct 18 integer
+ATTRIBUTE AAT-FR-Direct-Profile 19 string
+ATTRIBUTE AAT-FR-Direct-DLCI 20 integer
+ATTRIBUTE AAT-ATM-Direct 21 string
+ATTRIBUTE AAT-IP-TOS 22 integer
+ATTRIBUTE AAT-IP-TOS-Precedence 23 integer
+ATTRIBUTE AAT-IP-TOS-Apply-To 24 integer
+ATTRIBUTE AAT-MCast-Client 27 integer
+ATTRIBUTE AAT-Modem-Port-No 28 integer
+ATTRIBUTE AAT-Modem-Slot-No 29 integer
+ATTRIBUTE AAT-Modem-Shelf-No 30 integer
+ATTRIBUTE AAT-Filter 60 string
+ATTRIBUTE AAT-Vrouter-Name 61 string
+ATTRIBUTE AAT-Require-Auth 62 integer
+ATTRIBUTE AAT-IP-Pool-Definition 63 string
+ATTRIBUTE AAT-Assign-IP-Pool 64 integer
+ATTRIBUTE AAT-Data-Filter 65 string
+ATTRIBUTE AAT-Source-IP-Check 66 integer
+ATTRIBUTE AAT-Modem-Answer-String 67 string
+ATTRIBUTE AAT-Auth-Type 68 integer
+ATTRIBUTE AAT-Qos 70 integer
+ATTRIBUTE AAT-Qoa 71 integer
+ATTRIBUTE AAT-Client-Assign-DNS 72 integer
+ATTRIBUTE AAT-ATM-VPI 128 integer
+ATTRIBUTE AAT-ATM-VCI 129 integer
+ATTRIBUTE AAT-Input-Octets-Diff 130 integer
+ATTRIBUTE AAT-Output-Octets-Diff 131 integer
+ATTRIBUTE AAT-User-MAC-Address 132 string
+ATTRIBUTE AAT-ATM-Traffic-Profile 133 string
+
+VALUE AAT-MCast-Client Multicast-No 0
+VALUE AAT-MCast-Client Multicast-Yes 1
+
+VALUE AAT-Require-Auth Not-Require-Auth 0
+VALUE AAT-Require-Auth Require-Auth 1
+
+VALUE AAT-FR-Direct No 0
+VALUE AAT-FR-Direct Yes 1
+
+VALUE AAT-Source-IP-Check Source-IP-Check-No 0
+VALUE AAT-Source-IP-Check Source-IP-Check-Yes 1
+
+VALUE AAT-IP-TOS IP-TOS-Normal 0
+VALUE AAT-IP-TOS IP-TOS-Disabled 1
+VALUE AAT-IP-TOS IP-TOS-Cost 2
+VALUE AAT-IP-TOS IP-TOS-Reliability 4
+VALUE AAT-IP-TOS IP-TOS-Throughput 8
+VALUE AAT-IP-TOS IP-TOS-Latency 16
+
+VALUE AAT-IP-TOS-Apply-To IP-TOS-Apply-To-Incoming 1024
+VALUE AAT-IP-TOS-Apply-To IP-TOS-Apply-To-Both 3072
+VALUE AAT-IP-TOS-Apply-To IP-TOS-Apply-To-Outgoing 2048
+
+VALUE AAT-IP-TOS-Precedence IP-TOS-Precedence-Pri-Normal 0
+VALUE AAT-IP-TOS-Precedence IP-TOS-Precedence-Pri-One 32
+VALUE AAT-IP-TOS-Precedence IP-TOS-Precedence-Pri-Two 64
+VALUE AAT-IP-TOS-Precedence IP-TOS-Precedence-Pri-Three 96
+VALUE AAT-IP-TOS-Precedence IP-TOS-Precedence-Pri-Four 128
+VALUE AAT-IP-TOS-Precedence IP-TOS-Precedence-Pri-Five 160
+VALUE AAT-IP-TOS-Precedence IP-TOS-Precedence-Pri-Six 192
+VALUE AAT-IP-TOS-Precedence IP-TOS-Precedence-Pri-Seven 224
+
+VALUE AAT-Auth-Type AAT-Auth-None 0
+VALUE AAT-Auth-Type AAT-Auth-Default 1
+VALUE AAT-Auth-Type AAT-Auth-Any 2
+VALUE AAT-Auth-Type AAT-Auth-PAP 3
+VALUE AAT-Auth-Type AAT-Auth-CHAP 4
+VALUE AAT-Auth-Type AAT-Auth-MS-CHAP 5
+
+VALUE AAT-Client-Assign-DNS DNS-Assign-No 0
+VALUE AAT-Client-Assign-DNS DNS-Assign-Yes 1
+
+END-VENDOR Alcatel
diff --git a/share/dictionary.alcatel-lucent.aaa b/share/dictionary.alcatel-lucent.aaa
new file mode 100644
index 0000000..710b4f1
--- /dev/null
+++ b/share/dictionary.alcatel-lucent.aaa
@@ -0,0 +1,88 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# ALU-AAA AAA dictionary
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR ALU-AAA 831
+
+BEGIN-VENDOR ALU-AAA
+
+ATTRIBUTE ALU-AAA-Access-Rule 1 string
+ATTRIBUTE ALU-AAA-AV-Pair 2 string
+ATTRIBUTE ALU-AAA-GSM-Triplets-Needed 3 integer
+ATTRIBUTE ALU-AAA-GSM-Triplet 4 octets
+ATTRIBUTE ALU-AAA-AKA-Quintets-Needed 5 integer
+ATTRIBUTE ALU-AAA-AKA-Quintet 6 octets
+ATTRIBUTE ALU-AAA-AKA-RAND 7 octets
+ATTRIBUTE ALU-AAA-AKA-AUTS 8 octets
+ATTRIBUTE ALU-AAA-Service-Profile 9 string
+ATTRIBUTE ALU-AAA-Lawful-Intercept-Status 10 byte
+ATTRIBUTE ALU-AAA-DF-CC-Address 11 ipaddr
+ATTRIBUTE ALU-AAA-DF-CC-Port 12 short
+ATTRIBUTE ALU-AAA-Client-Program 13 string
+ATTRIBUTE ALU-AAA-Client-Error-Action 14 integer
+ATTRIBUTE ALU-AAA-Client-OS 15 string
+ATTRIBUTE ALU-AAA-Client-Version 16 string
+ATTRIBUTE ALU-AAA-Nonce 17 octets
+ATTRIBUTE ALU-AAA-Femto-Public-Key-Hash 18 octets
+ATTRIBUTE ALU-AAA-Femto-Associated-User-Name 19 string
+ATTRIBUTE ALU-AAA-String-0 100 string
+ATTRIBUTE ALU-AAA-String-1 101 string
+ATTRIBUTE ALU-AAA-String-2 102 string
+ATTRIBUTE ALU-AAA-String-3 103 string
+ATTRIBUTE ALU-AAA-Integer-0 104 integer
+ATTRIBUTE ALU-AAA-Integer-1 105 integer
+ATTRIBUTE ALU-AAA-Integer-2 106 integer
+ATTRIBUTE ALU-AAA-Integer-3 107 integer
+ATTRIBUTE ALU-AAA-Address-0 108 combo-ip
+ATTRIBUTE ALU-AAA-Address-1 109 combo-ip
+ATTRIBUTE ALU-AAA-Address-2 110 combo-ip
+ATTRIBUTE ALU-AAA-Address-3 111 combo-ip
+ATTRIBUTE ALU-AAA-Value-0 112 octets
+ATTRIBUTE ALU-AAA-Value-1 113 octets
+ATTRIBUTE ALU-AAA-Value-2 114 octets
+ATTRIBUTE ALU-AAA-Value-3 115 octets
+ATTRIBUTE ALU-AAA-Key-0 116 octets encrypt=2
+ATTRIBUTE ALU-AAA-Key-1 117 octets encrypt=2
+ATTRIBUTE ALU-AAA-Key-2 118 octets encrypt=2
+ATTRIBUTE ALU-AAA-Key-3 119 octets encrypt=2
+ATTRIBUTE ALU-AAA-Opaque-0 120 octets
+ATTRIBUTE ALU-AAA-Opaque-1 121 octets
+ATTRIBUTE ALU-AAA-Opaque-2 122 octets
+ATTRIBUTE ALU-AAA-Opaque-3 123 octets
+ATTRIBUTE ALU-AAA-Eval-0 124 string
+ATTRIBUTE ALU-AAA-Eval-1 125 string
+ATTRIBUTE ALU-AAA-Eval-2 126 string
+ATTRIBUTE ALU-AAA-Eval-3 127 string
+ATTRIBUTE ALU-AAA-Exec-0 128 string
+ATTRIBUTE ALU-AAA-Exec-1 129 string
+ATTRIBUTE ALU-AAA-Exec-2 130 string
+ATTRIBUTE ALU-AAA-Exec-3 131 string
+ATTRIBUTE ALU-AAA-Original-Receipt-Time 199 octets
+ATTRIBUTE ALU-AAA-Reply-Message 201 string
+ATTRIBUTE ALU-AAA-Called-Station-Id 202 string
+ATTRIBUTE ALU-AAA-NAS-IP-Address 203 ipaddr
+ATTRIBUTE ALU-AAA-NAS-Port 204 integer
+ATTRIBUTE ALU-AAA-Old-State 205 string
+ATTRIBUTE ALU-AAA-New-State 206 string
+ATTRIBUTE ALU-AAA-Event 207 string
+ATTRIBUTE ALU-AAA-Old-Timestamp 208 date
+ATTRIBUTE ALU-AAA-New-Timestamp 209 date
+ATTRIBUTE ALU-AAA-Delta-Session 210 integer
+ATTRIBUTE ALU-AAA-Civic-Location 211 octets
+ATTRIBUTE ALU-AAA-Geospatial-Location 212 octets
+
+VALUE ALU-AAA-Client-Error-Action Ignore 1
+VALUE ALU-AAA-Client-Error-Action Disconnect 2
+
+VALUE ALU-AAA-Delta-Session False 0
+VALUE ALU-AAA-Delta-Session True 1
+
+END-VENDOR ALU-AAA
diff --git a/share/dictionary.alcatel.esam b/share/dictionary.alcatel.esam
new file mode 100644
index 0000000..66f7193
--- /dev/null
+++ b/share/dictionary.alcatel.esam
@@ -0,0 +1,253 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Alcatel ESAM's VSAs
+#
+#
+
+# The vendor specific attribute type is two bytes, where the
+# first is the project ID and the second is the project specific
+# attribute ID. The project ID 7 is assigned to 7302 ISAM
+# project.
+
+VENDOR Alcatel-ESAM 637 format=2,1
+
+BEGIN-VENDOR Alcatel-ESAM
+ATTRIBUTE A-ESAM-VRF-Name 0x0700 string
+ATTRIBUTE A-ESAM-Vlan-Id 0x0701 integer
+ATTRIBUTE A-ESAM-QOS-Profile-Name 0x0702 string
+ATTRIBUTE A-ESAM-QOS-Params 0x0703 string
+
+ATTRIBUTE A-ESAM-Termination-Cause 0x0704 integer
+
+#
+# Integer Translations
+#
+
+# A-ESAM-Termination-Cause Values
+
+VALUE A-ESAM-Termination-Cause Unknown-VRF 1
+VALUE A-ESAM-Termination-Cause No-VRF 2
+
+VALUE A-ESAM-Termination-Cause Unknown-Vlan 3
+VALUE A-ESAM-Termination-Cause No-Vlan 4
+VALUE A-ESAM-Termination-Cause Unknown-Pool-Id 5
+VALUE A-ESAM-Termination-Cause Pool-Admin-Locked 6
+VALUE A-ESAM-Termination-Cause No-Pool-Id 7
+
+VALUE A-ESAM-Termination-Cause Pool-VRF-Inconsistent 8
+VALUE A-ESAM-Termination-Cause Unknown-QOS-Profile 9
+VALUE A-ESAM-Termination-Cause QOS-Params-Syntax-Err 10
+VALUE A-ESAM-Termination-Cause IP-Addr-In-Use 11
+
+VALUE A-ESAM-Termination-Cause No-IP-Addr-Available 12
+VALUE A-ESAM-Termination-Cause No-User-IP-Addr 13
+VALUE A-ESAM-Termination-Cause Missing-Attributes 14
+
+# VSAs for Operator Authentication
+
+ATTRIBUTE A-AL-Maintenance 0x0600 integer
+ATTRIBUTE A-AL-Provisioning 0x0601 integer
+ATTRIBUTE A-AL-TL1-Security 0x0602 integer
+ATTRIBUTE A-AL-Test 0x0603 integer
+
+ATTRIBUTE A-AL-AAA 0x0709 integer
+ATTRIBUTE A-AL-ATM 0x070A integer
+ATTRIBUTE A-AL-Alarm 0x070B integer
+ATTRIBUTE A-AL-DHCP 0x070C integer
+
+ATTRIBUTE A-AL-EQP 0x070D integer
+ATTRIBUTE A-AL-IGMP 0x070E integer
+ATTRIBUTE A-AL-CPEProxy 0x070F integer
+ATTRIBUTE A-AL-IP 0x0710 integer
+
+ATTRIBUTE A-AL-PPPoE 0x0711 integer
+ATTRIBUTE A-AL-QoS 0x0712 integer
+ATTRIBUTE A-AL-SWMgt 0x0713 integer
+ATTRIBUTE A-AL-Transport 0x0714 integer
+
+ATTRIBUTE A-AL-VLAN 0x0715 integer
+ATTRIBUTE A-AL-XDSL 0x0716 integer
+ATTRIBUTE A-AL-Security 0x0717 integer
+ATTRIBUTE A-AL-Cluster 0x0718 integer
+
+ATTRIBUTE A-AL-Prompt 0x0719 string
+ATTRIBUTE A-AL-Pwd-Timeout 0x071A integer
+ATTRIBUTE A-AL-Description 0x071B string
+ATTRIBUTE A-AL-SLOT-NUMBERING 0x071C integer
+
+####FTTU TL1 values###############################################
+ATTRIBUTE A-AL-MAINTENANCE-BACKWARD 0x0705 integer
+ATTRIBUTE A-AL-PROVISIONING-BACKWARD 0x0706 integer
+
+ATTRIBUTE A-AL-TL1-SECURITY-BACKWARD 0x0707 integer
+ATTRIBUTE A-AL-TEST-BACKWARD 0x0708 integer
+###################################################################
+
+# A-AL-Maintenance Values
+VALUE A-AL-Maintenance Alcatel-No-Maint-Priv-Level 0
+VALUE A-AL-Maintenance Alcatel-Maint-Priv-Level-1 1
+VALUE A-AL-Maintenance Alcatel-Maint-Priv-Level-2 2
+
+VALUE A-AL-Maintenance Alcatel-Maint-Priv-Level-3 3
+VALUE A-AL-Maintenance Alcatel-Maint-Priv-Level-4 4
+VALUE A-AL-Maintenance Alcatel-Maint-Priv-Level-5 5
+VALUE A-AL-Maintenance Alcatel-Maint-Priv-Level-6 6
+
+VALUE A-AL-Maintenance Alcatel-Maint-Priv-Level-7 7
+
+# A-AL-Provisioning Values
+VALUE A-AL-Provisioning Alcatel-No-Maint-Priv-Level 0
+VALUE A-AL-Provisioning Alcatel-Maint-Priv-Level-1 1
+
+VALUE A-AL-Provisioning Alcatel-Maint-Priv-Level-2 2
+VALUE A-AL-Provisioning Alcatel-Maint-Priv-Level-3 3
+VALUE A-AL-Provisioning Alcatel-Maint-Priv-Level-4 4
+VALUE A-AL-Provisioning Alcatel-Maint-Priv-Level-5 5
+
+VALUE A-AL-Provisioning Alcatel-Maint-Priv-Level-6 6
+VALUE A-AL-Provisioning Alcatel-Maint-Priv-Level-7 7
+
+# A-AL-Security Values
+VALUE A-AL-Security Alcatel-No-Maint-Priv-Level 0
+
+VALUE A-AL-Security Alcatel-Maint-Priv-Level-1 1
+VALUE A-AL-Security Alcatel-Maint-Priv-Level-2 2
+VALUE A-AL-Security Alcatel-Maint-Priv-Level-3 3
+VALUE A-AL-Security Alcatel-Maint-Priv-Level-4 4
+
+VALUE A-AL-Security Alcatel-Maint-Priv-Level-5 5
+VALUE A-AL-Security Alcatel-Maint-Priv-Level-6 6
+VALUE A-AL-Security Alcatel-Maint-Priv-Level-7 7
+
+# A-AL-Test Values
+
+VALUE A-AL-Test Alcatel-No-Maint-Priv-Level 0
+VALUE A-AL-Test Alcatel-Maint-Priv-Level-1 1
+VALUE A-AL-Test Alcatel-Maint-Priv-Level-2 2
+VALUE A-AL-Test Alcatel-Maint-Priv-Level-3 3
+
+VALUE A-AL-Test Alcatel-Maint-Priv-Level-4 4
+VALUE A-AL-Test Alcatel-Maint-Priv-Level-5 5
+VALUE A-AL-Test Alcatel-Maint-Priv-Level-6 6
+VALUE A-AL-Test Alcatel-Maint-Priv-Level-7 7
+
+# A-AL-AAA Value
+VALUE A-AL-AAA Alcatel-No-Priv 0
+VALUE A-AL-AAA Alcatel-Read-Priv 1
+VALUE A-AL-AAA Alcatel-Write-Priv 2
+
+VALUE A-AL-AAA Alcatel-RW-Priv 3
+
+# A-AL-ATM Value
+VALUE A-AL-ATM Alcatel-No-Priv 0
+VALUE A-AL-ATM Alcatel-Read-Priv 1
+
+VALUE A-AL-ATM Alcatel-Write-Priv 2
+VALUE A-AL-ATM Alcatel-RW-Priv 3
+
+# A-AL-Alarm Value
+VALUE A-AL-Alarm Alcatel-No-Priv 0
+
+VALUE A-AL-Alarm Alcatel-Read-Priv 1
+VALUE A-AL-Alarm Alcatel-Write-Priv 2
+VALUE A-AL-Alarm Alcatel-RW-Priv 3
+
+# A-AL-DHCP Value
+
+VALUE A-AL-DHCP Alcatel-No-Priv 0
+VALUE A-AL-DHCP Alcatel-Read-Priv 1
+VALUE A-AL-DHCP Alcatel-Write-Priv 2
+VALUE A-AL-DHCP Alcatel-RW-Priv 3
+
+# A-AL-EQP Value
+VALUE A-AL-EQP Alcatel-No-Priv 0
+VALUE A-AL-EQP Alcatel-Read-Priv 1
+VALUE A-AL-EQP Alcatel-Write-Priv 2
+
+VALUE A-AL-EQP Alcatel-RW-Priv 3
+
+# A-AL-IGMP Value
+VALUE A-AL-IGMP Alcatel-No-Priv 0
+VALUE A-AL-IGMP Alcatel-Read-Priv 1
+
+VALUE A-AL-IGMP Alcatel-Write-Priv 2
+VALUE A-AL-IGMP Alcatel-RW-Priv 3
+
+# A-AL-CPEProxy Value
+VALUE A-AL-CPEProxy Alcatel-No-Priv 0
+
+VALUE A-AL-CPEProxy Alcatel-Read-Priv 1
+VALUE A-AL-CPEProxy Alcatel-Write-Priv 2
+VALUE A-AL-CPEProxy Alcatel-RW-Priv 3
+
+# A-AL-IP Value
+
+VALUE A-AL-IP Alcatel-No-Priv 0
+VALUE A-AL-IP Alcatel-Read-Priv 1
+VALUE A-AL-IP Alcatel-Write-Priv 2
+VALUE A-AL-IP Alcatel-RW-Priv 3
+
+# A-AL-PPPoE Value
+VALUE A-AL-PPPoE Alcatel-No-Priv 0
+VALUE A-AL-PPPoE Alcatel-Read-Priv 1
+VALUE A-AL-PPPoE Alcatel-Write-Priv 2
+
+VALUE A-AL-PPPoE Alcatel-RW-Priv 3
+
+# A-AL-QoS Value
+VALUE A-AL-QoS Alcatel-No-Priv 0
+VALUE A-AL-QoS Alcatel-Read-Priv 1
+
+VALUE A-AL-QoS Alcatel-Write-Priv 2
+VALUE A-AL-QoS Alcatel-RW-Priv 3
+
+# A-AL-SWMgt Value
+VALUE A-AL-SWMgt Alcatel-No-Priv 0
+
+VALUE A-AL-SWMgt Alcatel-Read-Priv 1
+VALUE A-AL-SWMgt Alcatel-Write-Priv 2
+VALUE A-AL-SWMgt Alcatel-RW-Priv 3
+
+# A-AL-Transport Value
+
+VALUE A-AL-Transport Alcatel-No-Priv 0
+VALUE A-AL-Transport Alcatel-Read-Priv 1
+VALUE A-AL-Transport Alcatel-Write-Priv 2
+VALUE A-AL-Transport Alcatel-RW-Priv 3
+
+# A-AL-VLAN Value
+VALUE A-AL-VLAN Alcatel-No-Priv 0
+VALUE A-AL-VLAN Alcatel-Read-Priv 1
+VALUE A-AL-VLAN Alcatel-Write-Priv 2
+
+VALUE A-AL-VLAN Alcatel-RW-Priv 3
+
+# A-AL-XDSL Value
+VALUE A-AL-XDSL Alcatel-No-Priv 0
+VALUE A-AL-XDSL Alcatel-Read-Priv 1
+
+VALUE A-AL-XDSL Alcatel-Write-Priv 2
+VALUE A-AL-XDSL Alcatel-RW-Priv 3
+
+# A-AL-Security Value
+VALUE A-AL-Security Alcatel-No-Priv 0
+
+VALUE A-AL-Security Alcatel-Read-Priv 1
+VALUE A-AL-Security Alcatel-Write-Priv 2
+VALUE A-AL-Security Alcatel-RW-Priv 3
+
+# A-AL-Cluster Value
+
+VALUE A-AL-Cluster Alcatel-No-Priv 0
+VALUE A-AL-Cluster Alcatel-Read-Priv 1
+VALUE A-AL-Cluster Alcatel-Write-Priv 2
+VALUE A-AL-Cluster Alcatel-RW-Priv 3
+
+# A-AL-Cluster Value
+VALUE A-AL-SLOT-NUMBERING SLOT-NUMBERING-TYPE 1
+VALUE A-AL-SLOT-NUMBERING SLOT-NUMBERING-POSITION 2
+VALUE A-AL-SLOT-NUMBERING SLOT-NUMBERING-LEGACY 3
+
+END-VENDOR Alcatel-ESAM
diff --git a/share/dictionary.alcatel.sr b/share/dictionary.alcatel.sr
new file mode 100644
index 0000000..0445316
--- /dev/null
+++ b/share/dictionary.alcatel.sr
@@ -0,0 +1,420 @@
+# -*- text -*-
+# Copyright (C) 2022 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Alcatel-Lucent Service Router dictionary.
+#
+# $Id$
+#
+# See "7750 Service Router - RADIUS Attributes Reference Guide".
+#
+# Latest edition may be found by searching "7750 RADIUS ATTRIBUTES REFERENCE
+# GUIDE" here: https://documentation.nokia.com/cgi-bin/doc_list.pl
+#
+##############################################################################
+
+VENDOR Alcatel-Lucent-Service-Router 6527
+
+BEGIN-VENDOR Alcatel-Lucent-Service-Router
+
+# Alcatel Timetra attributes
+ATTRIBUTE Timetra-Access 1 integer
+
+VALUE Timetra-Access ftp 1
+VALUE Timetra-Access console 2
+VALUE Timetra-Access both 3
+
+ATTRIBUTE Timetra-Home-Directory 2 string
+
+ATTRIBUTE Timetra-Restrict-To-Home 3 integer
+
+VALUE Timetra-Restrict-To-Home true 1
+VALUE Timetra-Restrict-To-Home false 2
+
+ATTRIBUTE Timetra-Profile 4 string
+
+ATTRIBUTE Timetra-Default-Action 5 integer
+
+VALUE Timetra-Default-Action permit-all 1
+VALUE Timetra-Default-Action deny-all 2
+VALUE Timetra-Default-Action none 3
+
+ATTRIBUTE Timetra-Cmd 6 string
+
+ATTRIBUTE Timetra-Action 7 integer
+
+VALUE Timetra-Action permit 1
+VALUE Timetra-Action deny 2
+
+ATTRIBUTE Timetra-Exec-File 8 string
+
+# RADIUS subscriber authorization and CoA VSAs
+ATTRIBUTE Alc-Primary-Dns 9 ipaddr
+ATTRIBUTE Alc-Secondary-Dns 10 ipaddr
+ATTRIBUTE Alc-Subsc-ID-Str 11 string
+ATTRIBUTE Alc-Subsc-Prof-Str 12 string
+ATTRIBUTE Alc-SLA-Prof-Str 13 string
+ATTRIBUTE Alc-Force-Renew 14 string
+ATTRIBUTE Alc-Create-Host 15 string # CoA
+ATTRIBUTE Alc-ANCP-Str 16 string # CoA
+ATTRIBUTE Alc-Retail-Serv-Id 17 integer
+ATTRIBUTE Alc-Default-Router 18 ipaddr
+
+# RADIUS subscriber accounting VSAs
+ATTRIBUTE Alc-Acct-I-Inprof-Octets-64 19 octets
+ATTRIBUTE Alc-Acct-I-Outprof-Octets-64 20 octets
+ATTRIBUTE Alc-Acct-O-Inprof-Octets-64 21 octets
+ATTRIBUTE Alc-Acct-O-Outprof-Octets-64 22 octets
+ATTRIBUTE Alc-Acct-I-Inprof-Pkts-64 23 octets
+ATTRIBUTE Alc-Acct-I-Outprof-Pkts-64 24 octets
+ATTRIBUTE Alc-Acct-O-Inprof-Pkts-64 25 octets
+ATTRIBUTE Alc-Acct-O-Outprof-Pkts-64 26 octets
+
+ATTRIBUTE Alc-Client-Hardware-Addr 27 string
+ATTRIBUTE Alc-Int-Dest-Id-Str 28 string
+ATTRIBUTE Alc-Primary-Nbns 29 ipaddr
+ATTRIBUTE Alc-Secondary-Nbns 30 ipaddr
+ATTRIBUTE Alc-MSAP-Serv-Id 31 integer
+ATTRIBUTE Alc-MSAP-Policy 32 string
+ATTRIBUTE Alc-MSAP-Interface 33 string
+ATTRIBUTE Alc-PPPoE-PADO-Delay 34 integer
+ATTRIBUTE Alc-PPPoE-Service-Name 35 string
+ATTRIBUTE Alc-DHCP-Vendor-Class-Id 36 string
+
+# RADIUS subscriber accounting VSAs (HSMDA override counters)
+#
+# In a stupid format. These attributes are 10 octets long, in the
+# following format:
+#
+# 2 octets - Queue ID
+# 8 octets - 64-bit counter.
+#
+ATTRIBUTE Alc-Acct-OC-I-Inprof-Octets-64 37 octets
+ATTRIBUTE Alc-Acct-OC-I-Outprof-Octets-64 38 octets
+ATTRIBUTE Alc-Acct-OC-O-Inprof-Octets-64 39 octets
+ATTRIBUTE Alc-Acct-OC-O-Outprof-Octets-64 40 octets
+ATTRIBUTE Alc-Acct-OC-I-Inprof-Pkts-64 41 octets
+ATTRIBUTE Alc-Acct-OC-I-Outprof-Pkts-64 42 octets
+ATTRIBUTE Alc-Acct-OC-O-Inprof-Pkts-64 43 octets
+ATTRIBUTE Alc-Acct-OC-O-Outprof-Pkts-64 44 octets
+
+ATTRIBUTE Alc-App-Prof-Str 45 string
+ATTRIBUTE Alc-Tunnel-Group 46 string
+
+ATTRIBUTE Alc-Tunnel-Algorithm 47 integer
+
+VALUE Alc-Tunnel-Algorithm weighted-access 1
+VALUE Alc-Tunnel-Algorithm existing-first 2
+
+ATTRIBUTE Alc-Tunnel-Max-Sessions 48 integer has_tag
+ATTRIBUTE Alc-Tunnel-Idle-Timeout 49 integer has_tag
+ATTRIBUTE Alc-Tunnel-Hello-Interval 50 integer has_tag
+ATTRIBUTE Alc-Tunnel-Destruct-Timeout 51 integer has_tag
+ATTRIBUTE Alc-Tunnel-Max-Retries-Estab 52 integer has_tag
+ATTRIBUTE Alc-Tunnel-Max-Retries-Not-Estab 53 integer has_tag
+
+ATTRIBUTE Alc-Tunnel-AVP-Hiding 54 integer has_tag
+
+VALUE Alc-Tunnel-AVP-Hiding nothing 1
+VALUE Alc-Tunnel-AVP-Hiding sensitive-only 2
+VALUE Alc-Tunnel-AVP-Hiding all 3
+
+ATTRIBUTE Alc-BGP-Policy 55 string
+ATTRIBUTE Alc-BGP-Auth-Keychain 56 string
+ATTRIBUTE Alc-BGP-Auth-Key 57 octets
+ATTRIBUTE Alc-BGP-Export-Policy 58 string
+ATTRIBUTE Alc-BGP-Import-Policy 59 string
+ATTRIBUTE Alc-BGP-PeerAS 60 integer
+ATTRIBUTE Alc-IPsec-Serv-Id 61 integer
+ATTRIBUTE Alc-IPsec-Interface 62 string
+ATTRIBUTE Alc-IPsec-Tunnel-Template-Id 63 integer
+ATTRIBUTE Alc-IPsec-SA-Lifetime 64 integer
+
+# Match TC TmnxIkePolicyDHGroup in TIMETRA-IPSEC-MIB
+ATTRIBUTE Alc-IPsec-SA-PFS-Group 65 integer
+
+VALUE Alc-IPsec-SA-PFS-Group group1 1
+VALUE Alc-IPsec-SA-PFS-Group group2 2
+VALUE Alc-IPsec-SA-PFS-Group group5 5
+
+# Match TC TmnxEncrAlgorithm in TIMETRA-IPSEC-MIB
+ATTRIBUTE Alc-IPsec-SA-Encr-Algorithm 66 integer
+
+VALUE Alc-IPsec-SA-Encr-Algorithm null 1
+VALUE Alc-IPsec-SA-Encr-Algorithm des 2
+VALUE Alc-IPsec-SA-Encr-Algorithm des3 3
+VALUE Alc-IPsec-SA-Encr-Algorithm aes128 4
+VALUE Alc-IPsec-SA-Encr-Algorithm aes192 5
+VALUE Alc-IPsec-SA-Encr-Algorithm aes256 6
+
+# Match TC TmnxAuthAlgorithm in TIMETRA-IPSEC-MIB
+ATTRIBUTE Alc-IPsec-SA-Auth-Algorithm 67 integer
+
+VALUE Alc-IPsec-SA-Auth-Algorithm null 1
+VALUE Alc-IPsec-SA-Auth-Algorithm md5 2
+VALUE Alc-IPsec-SA-Auth-Algorithm sha1 3
+
+ATTRIBUTE Alc-IPsec-SA-Replay-Window 68 integer
+
+# RADIUS subscriber accounting VSAs (custom records)
+ATTRIBUTE Alc-Acct-I-High-Octets-Drop_64 69 octets
+ATTRIBUTE Alc-Acct-I-Low-Octets-Drop_64 70 octets
+ATTRIBUTE Alc-Acct-I-High-Pack-Drop_64 71 octets
+ATTRIBUTE Alc-Acct-I-Low-Pack-Drop_64 72 octets
+ATTRIBUTE Alc-Acct-I-High-Octets-Offer_64 73 octets
+ATTRIBUTE Alc-Acct-I-Low-Octets-Offer_64 74 octets
+ATTRIBUTE Alc-Acct-I-High-Pack-Offer_64 75 octets
+ATTRIBUTE Alc-Acct-I-Low-Pack-Offer_64 76 octets
+ATTRIBUTE Alc-Acct-I-Unc-Octets-Offer_64 77 octets
+ATTRIBUTE Alc-Acct-I-Unc-Pack-Offer_64 78 octets
+ATTRIBUTE Alc-Acct-I-All-Octets-Offer_64 79 octets
+ATTRIBUTE Alc-Acct-I-All-Pack-Offer_64 80 octets
+ATTRIBUTE Alc-Acct-O-Inprof-Pack-Drop_64 81 octets
+ATTRIBUTE Alc-Acct-O-Outprof-Pack-Drop_64 82 octets
+ATTRIBUTE Alc-Acct-O-Inprof-Octs-Drop_64 83 octets
+ATTRIBUTE Alc-Acct-O-Outprof-Octs-Drop_64 84 octets
+
+# RADIUS subscriber accounting VSAs (custom records, HSMDA)
+ATTRIBUTE Alc-Acct-OC-I-All-Octs-Offer_64 85 octets
+ATTRIBUTE Alc-Acct-OC-I-All-Pack-Offer_64 86 octets
+ATTRIBUTE Alc-Acct-OC-I-Inpr-Octs-Drop_64 87 octets
+ATTRIBUTE Alc-Acct-OC-I-Outpr-Octs-Drop_64 88 octets
+ATTRIBUTE Alc-Acct-OC-I-Inpr-Pack-Drop_64 89 octets
+ATTRIBUTE Alc-Acct-OC-I-Outpr-Pack-Drop_64 90 octets
+ATTRIBUTE Alc-Acct-OC-O-Inpr-Pack-Drop_64 91 octets
+ATTRIBUTE Alc-Acct-OC-O-Outpr-Pack-Drop_64 92 octets
+ATTRIBUTE Alc-Acct-OC-O-Inpr-Octs-Drop_64 93 octets
+ATTRIBUTE Alc-Acct-OC-O-Outpr-Octs-Drop_64 94 octets
+
+# Credit control VSAs
+ATTRIBUTE Alc-Credit-Control-CategoryMap 95 string
+ATTRIBUTE Alc-Credit-Control-Quota 96 string
+
+ATTRIBUTE Alc-Tunnel-Challenge 97 integer has_tag
+
+VALUE Alc-Tunnel-Challenge never 1
+VALUE Alc-Tunnel-Challenge always 2
+
+ATTRIBUTE Alc-Force-Nak 98 string # CoA
+
+ATTRIBUTE Alc-Ipv6-Address 99 ipv6addr
+ATTRIBUTE Alc-Serv-Id 100 integer
+ATTRIBUTE Alc-Interface 101 string
+ATTRIBUTE Alc-ToServer-Dhcp-Options 102 octets
+ATTRIBUTE Alc-ToClient-Dhcp-Options 103 octets
+ATTRIBUTE Alc-Tunnel-Serv-Id 104 integer
+ATTRIBUTE Alc-Ipv6-Primary-Dns 105 ipv6addr
+ATTRIBUTE Alc-Ipv6-Secondary-Dns 106 ipv6addr
+
+# RADIUS subscriber accounting VSAs (Policers)
+ATTRIBUTE Alc-Acct-I-statmode 107 string
+ATTRIBUTE Alc-Acct-I-Hiprio-Octets_64 108 octets
+ATTRIBUTE Alc-Acct-I-Lowprio-Octets_64 109 octets
+ATTRIBUTE Alc-Acct-O-Hiprio-Octets_64 110 octets
+ATTRIBUTE Alc-Acct-O-Lowprio-Octets_64 111 octets
+ATTRIBUTE Alc-Acct-I-Hiprio-Packets_64 112 octets
+ATTRIBUTE Alc-Acct-I-Lowprio-Packets_64 113 octets
+ATTRIBUTE Alc-Acct-O-Hiprio-Packets_64 114 octets
+ATTRIBUTE Alc-Acct-O-Lowprio-Packets_64 115 octets
+ATTRIBUTE Alc-Acct-I-All-Octets_64 116 octets
+ATTRIBUTE Alc-Acct-O-All-Octets_64 117 octets
+ATTRIBUTE Alc-Acct-I-All-Packets_64 118 octets
+ATTRIBUTE Alc-Acct-O-All-Packets_64 119 octets
+
+ATTRIBUTE Alc-Tunnel-Rx-Window-Size 120 integer has_tag
+
+# NAT Subscriber
+ATTRIBUTE Alc-Nat-Port-Range 121 string
+
+# Lawful intercept VSAs
+ATTRIBUTE Alc-LI-Action 122 integer encrypt=2
+
+VALUE Alc-LI-Action no-action 1
+VALUE Alc-LI-Action enable 2
+VALUE Alc-LI-Action disable 3
+
+ATTRIBUTE Alc-LI-Destination 123 string encrypt=2
+
+# This VSA can occur multiple times (for each FC that must be intercepted)
+# If this VSA is not present, all FCs will be intercepted.
+ATTRIBUTE Alc-LI-FC 124 integer encrypt=2
+
+VALUE Alc-LI-FC be 0
+VALUE Alc-LI-FC l2 1
+VALUE Alc-LI-FC af 2
+VALUE Alc-LI-FC l1 3
+VALUE Alc-LI-FC h2 4
+VALUE Alc-LI-FC ef 5
+VALUE Alc-LI-FC h1 6
+VALUE Alc-LI-FC nc 7
+
+# If this VSA is not present, both directions will be intercepted.
+ATTRIBUTE Alc-LI-Direction 125 integer encrypt=2
+
+VALUE Alc-LI-Direction ingress 1
+VALUE Alc-LI-Direction egress 2
+
+# Subscriber QoS overrides
+ATTRIBUTE Alc-Subscriber-QoS-Override 126 string
+
+# RADIUS subscriber accounting VSAs (Policers)
+ATTRIBUTE Alc-Acct-O-statmode 127 string
+
+# ATM Traffic Descriptor Profiles
+ATTRIBUTE Alc-ATM-Ingress-TD-Profile 128 integer
+ATTRIBUTE Alc-ATM-Egress-TD-Profile 129 integer
+
+# Application-assurance transit ip (CoA)
+ATTRIBUTE Alc-AA-Transit-IP 130 integer # CoA
+
+VALUE Alc-AA-Transit-IP host 1
+VALUE Alc-AA-Transit-IP audit-start 2
+VALUE Alc-AA-Transit-IP audit-end 3
+
+# DHCPv6 Relay pool selection attributes
+ATTRIBUTE Alc-Delegated-IPv6-Pool 131 string
+
+ATTRIBUTE Alc-Access-Loop-Rate-Down 132 integer
+ATTRIBUTE Alc-Access-Loop-Encap-Offset 133 octets
+
+# Submgt SLA-profile filter overrrule
+ATTRIBUTE Alc-Subscriber-Filter 134 string
+
+ATTRIBUTE Alc-PPP-Force-IPv6CP 135 integer
+
+# One-Time HTTP Redirection
+ATTRIBUTE Alc-Onetime-Http-Redirection-Filter-Id 136 string
+
+# Used when clearing all radius li triggered sources from a mirror destination
+# via CoA. The value of this attribute is used to authenticate the coa.
+ATTRIBUTE Alc-Authentication-Policy-Name 137 string # CoA
+
+# Lawful intercept VSAs continued
+ATTRIBUTE Alc-LI-Intercept-Id 138 integer encrypt=2
+ATTRIBUTE Alc-LI-Session-Id 139 integer encrypt=2
+
+# NAT
+ATTRIBUTE Alc-Nat-Outside-Serv-Id 140 integer
+ATTRIBUTE Alc-Nat-Outside-Ip-Addr 141 ipaddr
+
+# Mobile-Gateway APN-Password VSA (password used for the next APN AccessReq)
+ATTRIBUTE Alc-APN-Password 142 string encrypt=2
+
+# Mobile-Gateway Next-APN-Name VSA (PGW-APN to be used for the session)
+ATTRIBUTE Alc-APN-Name 143 string
+
+ATTRIBUTE Alc-Tunnel-Acct-Policy 144 string has_tag
+
+# Wlan-Gateway
+ATTRIBUTE Alc-Mgw-Interface-Type 145 integer
+
+VALUE Alc-Mgw-Interface-Type gn 1
+VALUE Alc-Mgw-Interface-Type s2a 2
+VALUE Alc-Mgw-Interface-Type s2b 3
+
+ATTRIBUTE Alc-Wlan-APN-Name 146 string
+ATTRIBUTE Alc-MsIsdn 147 string
+
+# WIFI Received Signal Strength Indication
+ATTRIBUTE Alc-RSSI 148 integer
+
+# Number of attached WIFI UEs
+ATTRIBUTE Alc-Num-Attached-UEs 149 integer
+
+# Mobile-Gateway Charging-profile-ID VSA
+ATTRIBUTE Alc-Charging-Prof-ID 150 integer
+
+# 151-155 are currently unused
+
+# Application-Assurance Radius Accounting Attributes
+ATTRIBUTE Alc-AA-Group-Partition-Isa-Id 156 string
+
+# Application-Assurance Radius Peer Information
+ATTRIBUTE Alc-AA-Peer-Identifier 157 string
+
+# A local configured filter policy can be extended with shared dynamic filter entries
+ATTRIBUTE Alc-Nas-Filter-Rule-Shared 158 string
+
+# They represent a per host customization of a generic filter policy: only
+# traffic to/from the subscriber host will match against these entries
+ATTRIBUTE Alc-Ascend-Data-Filter-Host-Spec 159 abinary
+
+# Relative Session-Timeout
+ATTRIBUTE Alc-Relative-Session-Timeout 160 integer
+
+# 161-162 are currently unused
+
+# Accounting interim update trigger reason
+ATTRIBUTE Alc-Acct-Triggered-Reason 163 integer
+
+VALUE Alc-Acct-Triggered-Reason regular 1
+VALUE Alc-Acct-Triggered-Reason sla-start 2
+VALUE Alc-Acct-Triggered-Reason sla-stop 3
+VALUE Alc-Acct-Triggered-Reason Framed-IP-Address-up 4
+VALUE Alc-Acct-Triggered-Reason Framed-IP-Address-down 5
+VALUE Alc-Acct-Triggered-Reason Alc-Ipv6-Address-up 6
+VALUE Alc-Acct-Triggered-Reason Alc-Ipv6-Address-down 7
+VALUE Alc-Acct-Triggered-Reason Delegated-IPv6-Prefix-up 8
+VALUE Alc-Acct-Triggered-Reason Delegated-IPv6-Prefix-down 9
+VALUE Alc-Acct-Triggered-Reason Framed-IPv6-Prefix-up 10
+VALUE Alc-Acct-Triggered-Reason Framed-IPv6-Prefix-down 11
+
+# Used when authenticating migrant hosts
+ATTRIBUTE Alc-Wlan-Portal-Redirect 172 string
+
+# If a migrant host is redirected, specifies the URL
+ATTRIBUTE Alc-Wlan-Portal-Url 173 string
+
+# Defines the lease-time in seconds for RADIUS proxy and create-host-CoA
+# scenarios only.
+ATTRIBUTE Alc-Lease-Time 174 integer
+
+ATTRIBUTE Alc-DSL-Line-State 175 integer
+ATTRIBUTE Alc-DSL-Type 176 integer
+
+# The URL to which traffic matching the host IPv4 filter entry with http-redirect
+# action is redirected to
+ATTRIBUTE Alc-Portal-Url 177 string
+
+ATTRIBUTE Alc-Ipv6-Portal-Url 178 string
+ATTRIBUTE Alc-SAP-Session-Index 180 integer
+
+# names longer than the allowed maximum are treated as host setup failures
+ATTRIBUTE Alc-SLAAC-IPv6-Pool 181 string
+
+ATTRIBUTE Alc-WPP-ErrorCode 183 integer
+ATTRIBUTE Alc-Onetime-Http-Redirect-Reactivate 185 string
+
+# DHCP6 attributes
+ATTRIBUTE Alc-ToServer-Dhcp6-Options 191 octets
+ATTRIBUTE Alc-ToClient-Dhcp6-Options 192 octets
+
+#
+# MUST have renew time <= rebind time <= preferred lifetime <= valid lifetime
+#
+ATTRIBUTE Alc-v6-Preferred-Lifetime 200 integer
+ATTRIBUTE Alc-v6-Valid-Lifetime 201 integer
+ATTRIBUTE Alc-Dhcp6-Renew-Time 202 integer
+ATTRIBUTE Alc-Dhcp6-Rebind-Time 203 integer
+
+# The VLAN is transparently taken from the UE’s Ethernet layer and can be reflected
+# in both authentication and accounting
+ATTRIBUTE Alc-Wlan-SSID-VLAN 206 string
+
+ATTRIBUTE Alc-UPnP-Sub-Override-Policy 217 string
+
+ATTRIBUTE Alc-Trigger-Acct-Interim 228 string
+
+ATTRIBUTE Alc-Acct-Interim-Level 232 integer has_tag
+
+ATTRIBUTE Alc-DNAT-Override 234 string
+
+ATTRIBUTE Alc-Remove-Override 238 string
+
+ATTRIBUTE Alc-Radius-Py 242 octets
+
+ATTRIBUTE Alc-Force-DHCP-Relay 244 string
+
+END-VENDOR Alcatel-Lucent-Service-Router
diff --git a/share/dictionary.alteon b/share/dictionary.alteon
new file mode 100644
index 0000000..96f0b86
--- /dev/null
+++ b/share/dictionary.alteon
@@ -0,0 +1,32 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Alteon Webswitch
+#
+# $Id$
+#
+VENDOR Alteon 1872
+
+BEGIN-VENDOR Alteon
+
+ATTRIBUTE Alteon-Group-Mapping 1 string
+ATTRIBUTE Alteon-VPN-Id 3 integer
+ATTRIBUTE Alteon-Client-IP-Address 4 ipaddr
+ATTRIBUTE Alteon-Client-Netmask 5 ipaddr
+ATTRIBUTE Alteon-Primary-NBNS-Server 6 ipaddr
+ATTRIBUTE Alteon-Secondary-NBNS-Server 7 ipaddr
+ATTRIBUTE Alteon-Primary-DNS-Server 8 ipaddr
+ATTRIBUTE Alteon-Secondary-DNS-Server 9 ipaddr
+ATTRIBUTE Alteon-Domain-Name 10 string
+
+ATTRIBUTE Alteon-Service-Type 26 integer
+
+VALUE Alteon-Service-Type Alteon-L4admin 250
+VALUE Alteon-Service-Type Alteon-Slbadmin 251
+VALUE Alteon-Service-Type Alteon-Oper 252
+VALUE Alteon-Service-Type Alteon-L4oper 253
+VALUE Alteon-Service-Type Alteon-Slboper 254
+VALUE Alteon-Service-Type Alteon-User 255
+
+END-VENDOR Alteon
diff --git a/share/dictionary.altiga b/share/dictionary.altiga
new file mode 100644
index 0000000..7a42e77
--- /dev/null
+++ b/share/dictionary.altiga
@@ -0,0 +1,163 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Altiga vendor attributes
+#
+# Altiga networks was acquired by Cisco in 2000.
+#
+# $Id$
+#
+
+VENDOR Altiga 3076
+
+BEGIN-VENDOR Altiga
+ATTRIBUTE Altiga-Access-Hours-G/U 1 string
+ATTRIBUTE Altiga-Simultaneous-Logins-G/U 2 integer
+ATTRIBUTE Altiga-Min-Password-Length-G 3 integer
+ATTRIBUTE Altiga-Allow-Alpha-Only-Passwords-G 4 integer
+ATTRIBUTE Altiga-Primary-DNS-G 5 ipaddr
+ATTRIBUTE Altiga-Secondary-DNS-G 6 ipaddr
+ATTRIBUTE Altiga-Primary-WINS-G 7 ipaddr
+ATTRIBUTE Altiga-Secondary-WINS-G 8 ipaddr
+ATTRIBUTE Altiga-SEP-Card-Assignment-G/U 9 integer
+ATTRIBUTE Altiga-Priority-on-SEP-G/U 10 integer
+ATTRIBUTE Altiga-Tunneling-Protocols-G/U 11 integer
+ATTRIBUTE Altiga-IPSec-Sec-Association-G/U 12 string
+ATTRIBUTE Altiga-IPSec-Authentication-G 13 integer
+ATTRIBUTE Altiga-IPSec-Banner-G 15 string
+ATTRIBUTE Altiga-IPSec-Allow-Passwd-Store-G/U 16 integer
+ATTRIBUTE Altiga-Use-Client-Address-G/U 17 integer
+ATTRIBUTE Altiga-PPTP-Min-Authentication-G/U 18 integer
+ATTRIBUTE Altiga-L2TP-Min-Authentication-G/U 19 integer
+ATTRIBUTE Altiga-PPTP-Encryption-G 20 integer
+ATTRIBUTE Altiga-L2TP-Encryption-G 21 integer
+ATTRIBUTE Altiga-Argument-Authentication-Server-Type 22 integer
+ATTRIBUTE Altiga-IPSec-L2L-Keepalives-G 25 integer
+ATTRIBUTE Altiga-Argument-IPSec-Group-Name 26 integer
+ATTRIBUTE Altiga-IPSec-Split-Tunnel-List-G 27 string
+ATTRIBUTE Altiga-IPSec-Default-Domain-G 28 string
+ATTRIBUTE Altiga-IPSec-Secondary-Domains-G 29 string
+ATTRIBUTE Altiga-IPSec-Tunnel-Type-G 30 integer
+ATTRIBUTE Altiga-IPSec-Mode-Config-G 31 integer
+ATTRIBUTE Altiga-Argument-Authentication-Server-Priority 32 integer
+ATTRIBUTE Altiga-IPSec-User-Group-Lock-G 33 integer
+ATTRIBUTE Altiga-IPSec-Over-NAT-G 34 integer
+ATTRIBUTE Altiga-IPSec-Over-NAT-Port-Num-G 35 integer
+ATTRIBUTE Altiga-Partitioning-Primary-DHCP 128 ipaddr
+ATTRIBUTE Altiga-Partitioning-Secondary-DHCP 129 ipaddr
+ATTRIBUTE Altiga-Partitioning-Premise-Rout 131 ipaddr
+ATTRIBUTE Altiga-Partitioning-Partition-Max-Sessions 132 string
+ATTRIBUTE Altiga-Partitioning-Mobile-IP-Key 133 string
+ATTRIBUTE Altiga-Partitioning-Mobile-IP-Address 134 ipaddr
+ATTRIBUTE Altiga-Partitioning-Mobile-IP-SPI 135 ipaddr
+ATTRIBUTE Altiga-Partitioning-Strip-Realm 136 integer
+ATTRIBUTE Altiga-Partitioning-Group 137 integer
+ATTRIBUTE Altiga-Group-Name 250 string
+
+# Altiga value
+VALUE Altiga-Allow-Alpha-Only-Passwords-G Allow 1
+VALUE Altiga-Allow-Alpha-Only-Passwords-G Disallow 0
+
+VALUE Altiga-SEP-Card-Assignment-G/U SEP1 1
+VALUE Altiga-SEP-Card-Assignment-G/U SEP2 2
+VALUE Altiga-SEP-Card-Assignment-G/U SEP3 4
+VALUE Altiga-SEP-Card-Assignment-G/U SEP4 8
+VALUE Altiga-SEP-Card-Assignment-G/U Any-SEP 15
+
+VALUE Altiga-Priority-on-SEP-G/U High 1
+VALUE Altiga-Priority-on-SEP-G/U Med-High 2
+VALUE Altiga-Priority-on-SEP-G/U Medium 3
+VALUE Altiga-Priority-on-SEP-G/U Med-Low 4
+VALUE Altiga-Priority-on-SEP-G/U Low 5
+
+VALUE Altiga-Tunneling-Protocols-G/U PPTP 1
+VALUE Altiga-Tunneling-Protocols-G/U L2TP 2
+VALUE Altiga-Tunneling-Protocols-G/U IPSec 4
+VALUE Altiga-Tunneling-Protocols-G/U L2TP/IPSec 8
+VALUE Altiga-Tunneling-Protocols-G/U PPTP-and-IPSec 5
+VALUE Altiga-Tunneling-Protocols-G/U All 15
+
+VALUE Altiga-IPSec-Authentication-G None 0
+VALUE Altiga-IPSec-Authentication-G RADIUS 1
+VALUE Altiga-IPSec-Authentication-G LDAP 2
+VALUE Altiga-IPSec-Authentication-G NTDomain 3
+VALUE Altiga-IPSec-Authentication-G SDI 4
+VALUE Altiga-IPSec-Authentication-G Internal 5
+
+VALUE Altiga-IPSec-Allow-Passwd-Store-G/U Allow 1
+VALUE Altiga-IPSec-Allow-Passwd-Store-G/U Disallow 0
+
+VALUE Altiga-Use-Client-Address-G/U Allow 1
+VALUE Altiga-Use-Client-Address-G/U Disallow 0
+
+VALUE Altiga-PPTP-Min-Authentication-G/U PAP 1
+VALUE Altiga-PPTP-Min-Authentication-G/U CHAP 2
+VALUE Altiga-PPTP-Min-Authentication-G/U EAP-MD5 4
+VALUE Altiga-PPTP-Min-Authentication-G/U EAP-GTC 8
+VALUE Altiga-PPTP-Min-Authentication-G/U EAP-TLS 16
+VALUE Altiga-PPTP-Min-Authentication-G/U MSCHAPv1 32
+VALUE Altiga-PPTP-Min-Authentication-G/U MSCHAPv2 64
+VALUE Altiga-PPTP-Min-Authentication-G/U Default 102
+
+VALUE Altiga-L2TP-Min-Authentication-G/U PAP 1
+VALUE Altiga-L2TP-Min-Authentication-G/U CHAP 2
+VALUE Altiga-L2TP-Min-Authentication-G/U EAP-MD5 4
+VALUE Altiga-L2TP-Min-Authentication-G/U EAP-GTC 8
+VALUE Altiga-L2TP-Min-Authentication-G/U EAP-TLS 16
+VALUE Altiga-L2TP-Min-Authentication-G/U MSCHAPv1 32
+VALUE Altiga-L2TP-Min-Authentication-G/U MSCHAPv2 64
+VALUE Altiga-L2TP-Min-Authentication-G/U Default 102
+
+VALUE Altiga-PPTP-Encryption-G PPTP-40bit 2
+VALUE Altiga-PPTP-Encryption-G PPTP-40-Encryption-Req 3
+VALUE Altiga-PPTP-Encryption-G PPTP-128 4
+VALUE Altiga-PPTP-Encryption-G PPTP-128-Encryption-Req 5
+VALUE Altiga-PPTP-Encryption-G PPTP-40-or-128 6
+VALUE Altiga-PPTP-Encryption-G PPTP-40-or-128-Encry-Req 7
+VALUE Altiga-PPTP-Encryption-G PPTP-40-Stateless-Req 10
+VALUE Altiga-PPTP-Encryption-G PPTP-40-Enc/Stateless-Req 11
+VALUE Altiga-PPTP-Encryption-G PPTP-128-Stateless-Req 12
+VALUE Altiga-PPTP-Encryption-G PPTP-128-Enc/Stateless-Req 13
+VALUE Altiga-PPTP-Encryption-G PPTP-40/128-Stateless-Req 14
+VALUE Altiga-PPTP-Encryption-G PPTP-40/128-Enc/Statls-Req 15
+
+VALUE Altiga-L2TP-Encryption-G L2TP-40bit 2
+VALUE Altiga-L2TP-Encryption-G L2TP-40-Encryption-Req 3
+VALUE Altiga-L2TP-Encryption-G L2TP-128 4
+VALUE Altiga-L2TP-Encryption-G L2TP-128-Encryption-Req 5
+VALUE Altiga-L2TP-Encryption-G L2TP-40-or-128 6
+VALUE Altiga-L2TP-Encryption-G L2TP-40-or-128-Encry-Req 7
+VALUE Altiga-L2TP-Encryption-G L2TP-40-Stateless-Req 10
+VALUE Altiga-L2TP-Encryption-G L2TP-40-Enc/Stateless-Req 11
+VALUE Altiga-L2TP-Encryption-G L2TP-128-Stateless-Req 12
+VALUE Altiga-L2TP-Encryption-G L2TP-128-Enc/Stateless-Req 13
+VALUE Altiga-L2TP-Encryption-G L2TP-40/128-Stateless-Req 14
+VALUE Altiga-L2TP-Encryption-G L2TP-40/128-Enc/Statls-Req 15
+
+VALUE Altiga-Argument-Authentication-Server-Type FirstActiveServer 1
+VALUE Altiga-Argument-Authentication-Server-Type RADIUS 1
+VALUE Altiga-Argument-Authentication-Server-Type LDAP 2
+VALUE Altiga-Argument-Authentication-Server-Type NT 3
+VALUE Altiga-Argument-Authentication-Server-Type SDI 4
+VALUE Altiga-Argument-Authentication-Server-Type Internal 5
+
+VALUE Altiga-IPSec-L2L-Keepalives-G ON 1
+VALUE Altiga-IPSec-L2L-Keepalives-G OFF 0
+
+VALUE Altiga-IPSec-Tunnel-Type-G LAN-to-LAN 1
+VALUE Altiga-IPSec-Tunnel-Type-G Remote-Access 2
+
+VALUE Altiga-IPSec-Mode-Config-G ON 1
+VALUE Altiga-IPSec-Mode-Config-G OFF 0
+
+VALUE Altiga-IPSec-User-Group-Lock-G ON 1
+VALUE Altiga-IPSec-User-Group-Lock-G OFF 0
+
+VALUE Altiga-IPSec-Over-NAT-G ON 1
+VALUE Altiga-IPSec-Over-NAT-G OFF 0
+
+VALUE Altiga-Partitioning-Strip-Realm ON 1
+VALUE Altiga-Partitioning-Strip-Realm OFF 0
+
+END-VENDOR Altiga
diff --git a/share/dictionary.alvarion b/share/dictionary.alvarion
new file mode 100644
index 0000000..91589ec
--- /dev/null
+++ b/share/dictionary.alvarion
@@ -0,0 +1,313 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Alvarion VSAs, also known as Breezecom / Breezenet.
+#
+#
+# These are retarded beyond belief. The only VSA's it sends in
+# accounting packets are text strings for accounting. And, it
+# doesn't use the same VSA numbers consistently. WTF?
+#
+# Here's what it does, and we'll let you decide if this is:
+#
+# a) Sane
+# b) Easier than doing it the way everyone else does
+# c) none of the above.
+#
+# * The NAS sends up to 11 VSA's in each accounting packet.
+# * The VSA numbers start off at 1, 2, 3, ... 11. This part is
+# somewhat sane.
+# * The *next* packet has up to 11 VSA's, but the NAS remembers
+# that it sent the first packet, and starts the VSA numbers
+# off at 12, 13, 14, ... 22. Huh?
+# * This process continues with the next packet, at 23, 24,... 33.
+# * eventually the numbers space wraps at 256 modulo 11, and it
+# keeps going.
+#
+# Why anyone thought this was a good idea is beyond rational
+# understanding.
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR Alvarion 12394
+
+BEGIN-VENDOR Alvarion
+
+ATTRIBUTE Alvarion-VSA-1 1 string
+ATTRIBUTE Alvarion-VSA-2 2 string
+ATTRIBUTE Alvarion-VSA-3 3 string
+ATTRIBUTE Alvarion-VSA-4 4 string
+ATTRIBUTE Alvarion-VSA-5 5 string
+ATTRIBUTE Alvarion-VSA-6 6 string
+ATTRIBUTE Alvarion-VSA-7 7 string
+ATTRIBUTE Alvarion-VSA-8 8 string
+ATTRIBUTE Alvarion-VSA-9 9 string
+ATTRIBUTE Alvarion-VSA-10 10 string
+ATTRIBUTE Alvarion-VSA-11 11 string
+ATTRIBUTE Alvarion-VSA-12 12 string
+ATTRIBUTE Alvarion-VSA-13 13 string
+ATTRIBUTE Alvarion-VSA-14 14 string
+ATTRIBUTE Alvarion-VSA-15 15 string
+ATTRIBUTE Alvarion-VSA-16 16 string
+ATTRIBUTE Alvarion-VSA-17 17 string
+ATTRIBUTE Alvarion-VSA-18 18 string
+ATTRIBUTE Alvarion-VSA-19 19 string
+ATTRIBUTE Alvarion-VSA-20 20 string
+ATTRIBUTE Alvarion-VSA-21 21 string
+ATTRIBUTE Alvarion-VSA-22 22 string
+ATTRIBUTE Alvarion-VSA-23 23 string
+ATTRIBUTE Alvarion-VSA-24 24 string
+ATTRIBUTE Alvarion-VSA-25 25 string
+ATTRIBUTE Alvarion-VSA-26 26 string
+ATTRIBUTE Alvarion-VSA-27 27 string
+ATTRIBUTE Alvarion-VSA-28 28 string
+ATTRIBUTE Alvarion-VSA-29 29 string
+ATTRIBUTE Alvarion-VSA-30 30 string
+ATTRIBUTE Alvarion-VSA-31 31 string
+ATTRIBUTE Alvarion-VSA-32 32 string
+ATTRIBUTE Alvarion-VSA-33 33 string
+ATTRIBUTE Alvarion-VSA-34 34 string
+ATTRIBUTE Alvarion-VSA-35 35 string
+ATTRIBUTE Alvarion-VSA-36 36 string
+ATTRIBUTE Alvarion-VSA-37 37 string
+ATTRIBUTE Alvarion-VSA-38 38 string
+ATTRIBUTE Alvarion-VSA-39 39 string
+ATTRIBUTE Alvarion-VSA-40 40 string
+ATTRIBUTE Alvarion-VSA-41 41 string
+ATTRIBUTE Alvarion-VSA-42 42 string
+ATTRIBUTE Alvarion-VSA-43 43 string
+ATTRIBUTE Alvarion-VSA-44 44 string
+ATTRIBUTE Alvarion-VSA-45 45 string
+ATTRIBUTE Alvarion-VSA-46 46 string
+ATTRIBUTE Alvarion-VSA-47 47 string
+ATTRIBUTE Alvarion-VSA-48 48 string
+ATTRIBUTE Alvarion-VSA-49 49 string
+ATTRIBUTE Alvarion-VSA-50 50 string
+ATTRIBUTE Alvarion-VSA-51 51 string
+ATTRIBUTE Alvarion-VSA-52 52 string
+ATTRIBUTE Alvarion-VSA-53 53 string
+ATTRIBUTE Alvarion-VSA-54 54 string
+ATTRIBUTE Alvarion-VSA-55 55 string
+ATTRIBUTE Alvarion-VSA-56 56 string
+ATTRIBUTE Alvarion-VSA-57 57 string
+ATTRIBUTE Alvarion-VSA-58 58 string
+ATTRIBUTE Alvarion-VSA-59 59 string
+ATTRIBUTE Alvarion-VSA-60 60 string
+ATTRIBUTE Alvarion-VSA-61 61 string
+ATTRIBUTE Alvarion-VSA-62 62 string
+ATTRIBUTE Alvarion-VSA-63 63 string
+ATTRIBUTE Alvarion-VSA-64 64 string
+ATTRIBUTE Alvarion-VSA-65 65 string
+ATTRIBUTE Alvarion-VSA-66 66 string
+ATTRIBUTE Alvarion-VSA-67 67 string
+ATTRIBUTE Alvarion-VSA-68 68 string
+ATTRIBUTE Alvarion-VSA-69 69 string
+ATTRIBUTE Alvarion-VSA-70 70 string
+ATTRIBUTE Alvarion-VSA-71 71 string
+ATTRIBUTE Alvarion-VSA-72 72 string
+ATTRIBUTE Alvarion-VSA-73 73 string
+ATTRIBUTE Alvarion-VSA-74 74 string
+ATTRIBUTE Alvarion-VSA-75 75 string
+ATTRIBUTE Alvarion-VSA-76 76 string
+ATTRIBUTE Alvarion-VSA-77 77 string
+ATTRIBUTE Alvarion-VSA-78 78 string
+ATTRIBUTE Alvarion-VSA-79 79 string
+ATTRIBUTE Alvarion-VSA-80 80 string
+ATTRIBUTE Alvarion-VSA-81 81 string
+ATTRIBUTE Alvarion-VSA-82 82 string
+ATTRIBUTE Alvarion-VSA-83 83 string
+ATTRIBUTE Alvarion-VSA-84 84 string
+ATTRIBUTE Alvarion-VSA-85 85 string
+ATTRIBUTE Alvarion-VSA-86 86 string
+ATTRIBUTE Alvarion-VSA-87 87 string
+ATTRIBUTE Alvarion-VSA-88 88 string
+ATTRIBUTE Alvarion-VSA-89 89 string
+ATTRIBUTE Alvarion-VSA-90 90 string
+ATTRIBUTE Alvarion-VSA-91 91 string
+ATTRIBUTE Alvarion-VSA-92 92 string
+ATTRIBUTE Alvarion-VSA-93 93 string
+ATTRIBUTE Alvarion-VSA-94 94 string
+ATTRIBUTE Alvarion-VSA-95 95 string
+ATTRIBUTE Alvarion-VSA-96 96 string
+ATTRIBUTE Alvarion-VSA-97 97 string
+ATTRIBUTE Alvarion-VSA-98 98 string
+ATTRIBUTE Alvarion-VSA-99 99 string
+ATTRIBUTE Alvarion-VSA-100 100 string
+ATTRIBUTE Alvarion-VSA-101 101 string
+ATTRIBUTE Alvarion-VSA-102 102 string
+ATTRIBUTE Alvarion-VSA-103 103 string
+ATTRIBUTE Alvarion-VSA-104 104 string
+ATTRIBUTE Alvarion-VSA-105 105 string
+ATTRIBUTE Alvarion-VSA-106 106 string
+ATTRIBUTE Alvarion-VSA-107 107 string
+ATTRIBUTE Alvarion-VSA-108 108 string
+ATTRIBUTE Alvarion-VSA-109 109 string
+ATTRIBUTE Alvarion-VSA-110 110 string
+ATTRIBUTE Alvarion-VSA-111 111 string
+ATTRIBUTE Alvarion-VSA-112 112 string
+ATTRIBUTE Alvarion-VSA-113 113 string
+ATTRIBUTE Alvarion-VSA-114 114 string
+ATTRIBUTE Alvarion-VSA-115 115 string
+ATTRIBUTE Alvarion-VSA-116 116 string
+ATTRIBUTE Alvarion-VSA-117 117 string
+ATTRIBUTE Alvarion-VSA-118 118 string
+ATTRIBUTE Alvarion-VSA-119 119 string
+ATTRIBUTE Alvarion-VSA-120 120 string
+ATTRIBUTE Alvarion-VSA-121 121 string
+ATTRIBUTE Alvarion-VSA-122 122 string
+ATTRIBUTE Alvarion-VSA-123 123 string
+ATTRIBUTE Alvarion-VSA-124 124 string
+ATTRIBUTE Alvarion-VSA-125 125 string
+ATTRIBUTE Alvarion-VSA-126 126 string
+ATTRIBUTE Alvarion-VSA-127 127 string
+ATTRIBUTE Alvarion-VSA-128 128 string
+ATTRIBUTE Alvarion-VSA-129 129 string
+ATTRIBUTE Alvarion-VSA-130 130 string
+ATTRIBUTE Alvarion-VSA-131 131 string
+ATTRIBUTE Alvarion-VSA-132 132 string
+ATTRIBUTE Alvarion-VSA-133 133 string
+ATTRIBUTE Alvarion-VSA-134 134 string
+ATTRIBUTE Alvarion-VSA-135 135 string
+ATTRIBUTE Alvarion-VSA-136 136 string
+ATTRIBUTE Alvarion-VSA-137 137 string
+ATTRIBUTE Alvarion-VSA-138 138 string
+ATTRIBUTE Alvarion-VSA-139 139 string
+ATTRIBUTE Alvarion-VSA-140 140 string
+ATTRIBUTE Alvarion-VSA-141 141 string
+ATTRIBUTE Alvarion-VSA-142 142 string
+ATTRIBUTE Alvarion-VSA-143 143 string
+ATTRIBUTE Alvarion-VSA-144 144 string
+ATTRIBUTE Alvarion-VSA-145 145 string
+ATTRIBUTE Alvarion-VSA-146 146 string
+ATTRIBUTE Alvarion-VSA-147 147 string
+ATTRIBUTE Alvarion-VSA-148 148 string
+ATTRIBUTE Alvarion-VSA-149 149 string
+ATTRIBUTE Alvarion-VSA-150 150 string
+ATTRIBUTE Alvarion-VSA-151 151 string
+ATTRIBUTE Alvarion-VSA-152 152 string
+ATTRIBUTE Alvarion-VSA-153 153 string
+ATTRIBUTE Alvarion-VSA-154 154 string
+ATTRIBUTE Alvarion-VSA-155 155 string
+ATTRIBUTE Alvarion-VSA-156 156 string
+ATTRIBUTE Alvarion-VSA-157 157 string
+ATTRIBUTE Alvarion-VSA-158 158 string
+ATTRIBUTE Alvarion-VSA-159 159 string
+ATTRIBUTE Alvarion-VSA-160 160 string
+ATTRIBUTE Alvarion-VSA-161 161 string
+ATTRIBUTE Alvarion-VSA-162 162 string
+ATTRIBUTE Alvarion-VSA-163 163 string
+ATTRIBUTE Alvarion-VSA-164 164 string
+ATTRIBUTE Alvarion-VSA-165 165 string
+ATTRIBUTE Alvarion-VSA-166 166 string
+ATTRIBUTE Alvarion-VSA-167 167 string
+ATTRIBUTE Alvarion-VSA-168 168 string
+ATTRIBUTE Alvarion-VSA-169 169 string
+ATTRIBUTE Alvarion-VSA-170 170 string
+ATTRIBUTE Alvarion-VSA-171 171 string
+ATTRIBUTE Alvarion-VSA-172 172 string
+ATTRIBUTE Alvarion-VSA-173 173 string
+ATTRIBUTE Alvarion-VSA-174 174 string
+ATTRIBUTE Alvarion-VSA-175 175 string
+ATTRIBUTE Alvarion-VSA-176 176 string
+ATTRIBUTE Alvarion-VSA-177 177 string
+ATTRIBUTE Alvarion-VSA-178 178 string
+ATTRIBUTE Alvarion-VSA-179 179 string
+ATTRIBUTE Alvarion-VSA-180 180 string
+ATTRIBUTE Alvarion-VSA-181 181 string
+ATTRIBUTE Alvarion-VSA-182 182 string
+ATTRIBUTE Alvarion-VSA-183 183 string
+ATTRIBUTE Alvarion-VSA-184 184 string
+ATTRIBUTE Alvarion-VSA-185 185 string
+ATTRIBUTE Alvarion-VSA-186 186 string
+ATTRIBUTE Alvarion-VSA-187 187 string
+ATTRIBUTE Alvarion-VSA-188 188 string
+ATTRIBUTE Alvarion-VSA-189 189 string
+ATTRIBUTE Alvarion-VSA-190 190 string
+ATTRIBUTE Alvarion-VSA-191 191 string
+ATTRIBUTE Alvarion-VSA-192 192 string
+ATTRIBUTE Alvarion-VSA-193 193 string
+ATTRIBUTE Alvarion-VSA-194 194 string
+ATTRIBUTE Alvarion-VSA-195 195 string
+ATTRIBUTE Alvarion-VSA-196 196 string
+ATTRIBUTE Alvarion-VSA-197 197 string
+ATTRIBUTE Alvarion-VSA-198 198 string
+ATTRIBUTE Alvarion-VSA-199 199 string
+ATTRIBUTE Alvarion-VSA-200 200 string
+ATTRIBUTE Alvarion-VSA-201 201 string
+ATTRIBUTE Alvarion-VSA-202 202 string
+ATTRIBUTE Alvarion-VSA-203 203 string
+ATTRIBUTE Alvarion-VSA-204 204 string
+ATTRIBUTE Alvarion-VSA-205 205 string
+ATTRIBUTE Alvarion-VSA-206 206 string
+ATTRIBUTE Alvarion-VSA-207 207 string
+ATTRIBUTE Alvarion-VSA-208 208 string
+ATTRIBUTE Alvarion-VSA-209 209 string
+ATTRIBUTE Alvarion-VSA-210 210 string
+ATTRIBUTE Alvarion-VSA-211 211 string
+ATTRIBUTE Alvarion-VSA-212 212 string
+ATTRIBUTE Alvarion-VSA-213 213 string
+ATTRIBUTE Alvarion-VSA-214 214 string
+ATTRIBUTE Alvarion-VSA-215 215 string
+ATTRIBUTE Alvarion-VSA-216 216 string
+ATTRIBUTE Alvarion-VSA-217 217 string
+ATTRIBUTE Alvarion-VSA-218 218 string
+ATTRIBUTE Alvarion-VSA-219 219 string
+ATTRIBUTE Alvarion-VSA-220 220 string
+ATTRIBUTE Alvarion-VSA-221 221 string
+ATTRIBUTE Alvarion-VSA-222 222 string
+ATTRIBUTE Alvarion-VSA-223 223 string
+ATTRIBUTE Alvarion-VSA-224 224 string
+ATTRIBUTE Alvarion-VSA-225 225 string
+ATTRIBUTE Alvarion-VSA-226 226 string
+ATTRIBUTE Alvarion-VSA-227 227 string
+ATTRIBUTE Alvarion-VSA-228 228 string
+ATTRIBUTE Alvarion-VSA-229 229 string
+ATTRIBUTE Alvarion-VSA-230 230 string
+ATTRIBUTE Alvarion-VSA-231 231 string
+ATTRIBUTE Alvarion-VSA-232 232 string
+ATTRIBUTE Alvarion-VSA-233 233 string
+ATTRIBUTE Alvarion-VSA-234 234 string
+ATTRIBUTE Alvarion-VSA-235 235 string
+ATTRIBUTE Alvarion-VSA-236 236 string
+ATTRIBUTE Alvarion-VSA-237 237 string
+ATTRIBUTE Alvarion-VSA-238 238 string
+ATTRIBUTE Alvarion-VSA-239 239 string
+ATTRIBUTE Alvarion-VSA-240 240 string
+ATTRIBUTE Alvarion-VSA-241 241 string
+ATTRIBUTE Alvarion-VSA-242 242 string
+ATTRIBUTE Alvarion-VSA-243 243 string
+ATTRIBUTE Alvarion-VSA-244 244 string
+ATTRIBUTE Alvarion-VSA-245 245 string
+ATTRIBUTE Alvarion-VSA-246 246 string
+ATTRIBUTE Alvarion-VSA-247 247 string
+ATTRIBUTE Alvarion-VSA-248 248 string
+ATTRIBUTE Alvarion-VSA-249 249 string
+ATTRIBUTE Alvarion-VSA-250 250 string
+ATTRIBUTE Alvarion-VSA-251 251 string
+ATTRIBUTE Alvarion-VSA-252 252 string
+ATTRIBUTE Alvarion-VSA-253 253 string
+ATTRIBUTE Alvarion-VSA-254 254 string
+ATTRIBUTE Alvarion-VSA-255 255 string
+
+#
+# And these are what the above attributes should get mapped to,
+# once we get around to caring.
+#
+ATTRIBUTE Breezecom-Attr1 1 string
+ATTRIBUTE Breezecom-Attr2 2 string
+ATTRIBUTE Breezecom-Attr3 3 string
+ATTRIBUTE Breezecom-Attr4 4 string
+ATTRIBUTE Breezecom-Attr5 5 string
+ATTRIBUTE Breezecom-Attr6 6 string
+ATTRIBUTE Breezecom-Attr7 7 string
+ATTRIBUTE Breezecom-Attr8 8 string
+ATTRIBUTE Breezecom-Attr9 9 string
+ATTRIBUTE Breezecom-Attr10 10 string
+ATTRIBUTE Breezecom-Attr11 11 string
+
+END-VENDOR Alvarion
diff --git a/share/dictionary.alvarion.wimax.v2_2 b/share/dictionary.alvarion.wimax.v2_2
new file mode 100644
index 0000000..9431766
--- /dev/null
+++ b/share/dictionary.alvarion.wimax.v2_2
@@ -0,0 +1,36 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Alvarion VSAs for use with Alvarion WiMAX ASN-GW
+#
+# This does conflict with the default Alvarion dictionary file included
+# with FreeRADIUS and may break existing functionality if the current
+# dictionaries are used to support an existing Alvarion Breezecom or
+# Breezenet installation.
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR Alvarion 12394
+
+BEGIN-VENDOR Alvarion
+
+ATTRIBUTE Alvarion-R3-IF-Descriptor 1 tlv
+ATTRIBUTE Alvarion-R3-IF-Name 1.1 string
+ATTRIBUTE Alvarion-R3-IF-ID 1.2 integer
+ATTRIBUTE Alvarion-PDFID 1.3 short
+ATTRIBUTE Alvarion-IPv4-Address 1.4 ipaddr
+# IPv4 subnet mask plus bit-width mask
+ATTRIBUTE Alvarion-IPv4-Netmask 1.5 octets
+ATTRIBUTE Alvarion-DGW-IPv4-Address 1.6 ipaddr
+
+# Container for DHCP options delivery in DHCP Proxy mode.
+ATTRIBUTE Alvarion-DHCP-Option 2 tlv
+ATTRIBUTE Alvarion-Ref-R3-IF-Name 2.1 string
+ATTRIBUTE Alvarion-DHCP-Option-Container 2.2 string
+
+END-VENDOR Alvarion
diff --git a/share/dictionary.apc b/share/dictionary.apc
new file mode 100644
index 0000000..00efbab
--- /dev/null
+++ b/share/dictionary.apc
@@ -0,0 +1,39 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+#############################################################################
+#
+# http://nam-en.apc.com/cgi-bin/nam_en.cfg/php/enduser/std_adp.php?p_faqid=8012
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR APC 318
+
+BEGIN-VENDOR APC
+
+ATTRIBUTE APC-Service-Type 1 integer
+ATTRIBUTE APC-Outlets 2 string
+ATTRIBUTE APC-Perms 3 string
+ATTRIBUTE APC-Username 4 string
+ATTRIBUTE APC-Contact 5 string
+ATTRIBUTE APC-ACCPX-Doors 6 string
+ATTRIBUTE APC-ACCPX-Status 7 string
+ATTRIBUTE APC-ACCPX-Access1 8 string
+ATTRIBUTE APC-ACCPX-Access2 9 string
+ATTRIBUTE APC-ACCPX-Access3 10 string
+ATTRIBUTE APC-ACCPX-Access4 11 string
+ATTRIBUTE APC-ACCPX-Access5 12 string
+ATTRIBUTE APC-ACCPX-Access6 13 string
+ATTRIBUTE APC-ACCPX-Access7 14 string
+
+VALUE APC-Service-Type Admin 1
+VALUE APC-Service-Type Device 2
+VALUE APC-Service-Type ReadOnly 3
+VALUE APC-Service-Type Outlet 4
+VALUE APC-Service-Type Card 5
+VALUE APC-Service-Type NetworkOnly 6
+
+END-VENDOR APC
diff --git a/share/dictionary.aptilo b/share/dictionary.aptilo
new file mode 100644
index 0000000..017f107
--- /dev/null
+++ b/share/dictionary.aptilo
@@ -0,0 +1,154 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+# Aptilo Access Controllers - https://www.aptilo.com/aptilo-access-controller
+#
+# Version: 2.0
+#
+##############################################################################
+
+VENDOR Aptilo 13209
+
+BEGIN-VENDOR Aptilo
+
+ATTRIBUTE Aptilo-Subnet-Name 1 string
+ATTRIBUTE Aptilo-Octets-Limit 2 integer
+ATTRIBUTE Aptilo-Gigawords-Limit 3 integer
+ATTRIBUTE Aptilo-Input-Octets-Limit 4 integer
+ATTRIBUTE Aptilo-Input-Gigawords-Limit 5 integer
+ATTRIBUTE Aptilo-Output-Octets-Limit 6 integer
+ATTRIBUTE Aptilo-Output-Gigawords-Limit 7 integer
+ATTRIBUTE Aptilo-Limit-Mode 8 integer
+ATTRIBUTE Aptilo-Apc-ID 9 string
+ATTRIBUTE Aptilo-Opaque-Key 10 string
+ATTRIBUTE Aptilo-Denied-Cause 11 integer
+ATTRIBUTE Aptilo-Realm-ID 12 integer
+ATTRIBUTE Aptilo-Ap-ID 13 integer
+ATTRIBUTE Aptilo-User-ID 14 integer
+ATTRIBUTE Aptilo-Zone 15 string
+ATTRIBUTE Aptilo-First-Name 16 string
+ATTRIBUTE Aptilo-Last-Name 17 string
+ATTRIBUTE Aptilo-Phone 18 string
+ATTRIBUTE Aptilo-Email 19 string
+ATTRIBUTE Aptilo-Organization 20 string
+ATTRIBUTE Aptilo-Access-Profile 21 string
+ATTRIBUTE Aptilo-Realm-Concurrent-Login 22 integer
+ATTRIBUTE Aptilo-Auth-Result 23 integer
+ATTRIBUTE Aptilo-Hotline-Indicator 24 string
+ATTRIBUTE Aptilo-User-Type 25 integer
+ATTRIBUTE Aptilo-Exclusive-Count 26 integer
+ATTRIBUTE Aptilo-Duration-Quota 27 integer
+ATTRIBUTE Aptilo-Volume-Quota 28 string
+ATTRIBUTE Aptilo-RX-Volume-Quota 29 string
+ATTRIBUTE Aptilo-TX-Volume-Quota 30 string
+ATTRIBUTE Aptilo-Resource-Quota 31 integer
+ATTRIBUTE Aptilo-Quota-ID 32 string
+ATTRIBUTE Aptilo-RX-Limit 33 integer
+ATTRIBUTE Aptilo-TX-Limit 34 integer
+ATTRIBUTE Aptilo-TRX-Limit 35 integer
+ATTRIBUTE Aptilo-Bw-Min-Up 36 integer
+ATTRIBUTE Aptilo-Bw-Max-Up 37 integer
+ATTRIBUTE Aptilo-Bw-Min-Down 38 integer
+ATTRIBUTE Aptilo-Bw-Max-Down 39 integer
+ATTRIBUTE Aptilo-Service-Profile 40 string
+ATTRIBUTE Aptilo-Automatic-Service 41 string
+ATTRIBUTE Aptilo-Auth-Type 42 integer
+ATTRIBUTE Aptilo-NAS-Capabilities 43 integer
+ATTRIBUTE Aptilo-Service 44 string
+ATTRIBUTE Aptilo-Service-Profile-ID 45 integer
+ATTRIBUTE Aptilo-Auth-Param 50 integer
+ATTRIBUTE Aptilo-Access-Profile-ID 53 integer
+ATTRIBUTE Aptilo-NAS-Model 56 string
+ATTRIBUTE Aptilo-Debug-Option 57 integer
+ATTRIBUTE Aptilo-Session-Id 58 string
+ATTRIBUTE Aptilo-Prepaid-Capabilities 59 octets
+ATTRIBUTE Aptilo-Octets-Quota 60 octets
+ATTRIBUTE Aptilo-Octets-Threshold 61 octets
+ATTRIBUTE Aptilo-Resource-Threshold 62 integer
+ATTRIBUTE Aptilo-Duration-Threshold 63 integer
+ATTRIBUTE Aptilo-Octets-Balance 64 octets
+ATTRIBUTE Aptilo-Resource-Balance 65 integer
+ATTRIBUTE Aptilo-Duration-Balance 66 integer
+ATTRIBUTE Aptilo-Octets-Used 67 octets
+ATTRIBUTE Aptilo-Resource-Used 68 integer
+ATTRIBUTE Aptilo-Duration-Used 69 integer
+ATTRIBUTE Aptilo-Octets-Request 70 octets
+ATTRIBUTE Aptilo-Resource-Request 71 integer
+ATTRIBUTE Aptilo-Duration-Request 72 integer
+ATTRIBUTE Aptilo-QoS-Indicator 73 string
+ATTRIBUTE Aptilo-Circuit-ID 74 octets
+ATTRIBUTE Aptilo-Remote-ID 75 octets
+ATTRIBUTE Aptilo-Location-Name 76 string
+
+ATTRIBUTE Aptilo-Key-IPv6-1 231 ipv6addr
+ATTRIBUTE Aptilo-Key-IPv6-2 232 ipv6addr
+ATTRIBUTE Aptilo-Key-IPv6-3 233 ipv6addr
+ATTRIBUTE Aptilo-Key-IPv6-4 234 ipv6addr
+ATTRIBUTE Aptilo-Key-IPv6-5 235 ipv6addr
+ATTRIBUTE Aptilo-Key-Octets-1 236 octets
+ATTRIBUTE Aptilo-Key-Octets-2 237 octets
+ATTRIBUTE Aptilo-Key-Octets-3 238 octets
+ATTRIBUTE Aptilo-Key-Octets-4 239 octets
+ATTRIBUTE Aptilo-Key-Octets-5 240 octets
+ATTRIBUTE Aptilo-Key-String-1 241 string
+ATTRIBUTE Aptilo-Key-String-2 242 string
+ATTRIBUTE Aptilo-Key-String-3 243 string
+ATTRIBUTE Aptilo-Key-String-4 244 string
+ATTRIBUTE Aptilo-Key-String-5 245 string
+ATTRIBUTE Aptilo-Key-IP-1 246 ipaddr
+ATTRIBUTE Aptilo-Key-IP-2 247 ipaddr
+ATTRIBUTE Aptilo-Key-IP-3 248 ipaddr
+ATTRIBUTE Aptilo-Key-IP-4 249 ipaddr
+ATTRIBUTE Aptilo-Key-IP-5 250 ipaddr
+ATTRIBUTE Aptilo-Key-Integer-1 251 integer
+ATTRIBUTE Aptilo-Key-Integer-2 252 integer
+ATTRIBUTE Aptilo-Key-Integer-3 253 integer
+ATTRIBUTE Aptilo-Key-Integer-4 254 integer
+ATTRIBUTE Aptilo-Key-Integer-5 255 integer
+
+VALUE Aptilo-Limit-Mode Relative 0
+VALUE Aptilo-Limit-Mode Absolute 1
+
+VALUE Aptilo-Denied-Cause User-Not-Found 1
+VALUE Aptilo-Denied-Cause Wrong-Password 2
+VALUE Aptilo-Denied-Cause No-Zone-Access 3
+VALUE Aptilo-Denied-Cause Inactive-Access-Node 4
+VALUE Aptilo-Denied-Cause Inconsistent-Access-Node 5
+VALUE Aptilo-Denied-Cause Disabled-Account 6
+VALUE Aptilo-Denied-Cause No-Accessprofile 7
+VALUE Aptilo-Denied-Cause Internal-Error 8
+VALUE Aptilo-Denied-Cause Realm-Error 9
+VALUE Aptilo-Denied-Cause No-Credits 10
+VALUE Aptilo-Denied-Cause Max-Session 11
+VALUE Aptilo-Denied-Cause Remote-Server-Reject 12
+VALUE Aptilo-Denied-Cause Realm-Inactive 14
+VALUE Aptilo-Denied-Cause Opaque-Failed 15
+VALUE Aptilo-Denied-Cause Service-Closed 16
+VALUE Aptilo-Denied-Cause LDAP-Failed 17
+VALUE Aptilo-Denied-Cause Inactive-Account 18
+VALUE Aptilo-Denied-Cause Expired-Account 19
+VALUE Aptilo-Denied-Cause Incomplete-Account 20
+VALUE Aptilo-Denied-Cause License-Limit-Reached 21
+VALUE Aptilo-Denied-Cause Unsupported-Service 22
+VALUE Aptilo-Denied-Cause Ruleset-Reject 23
+VALUE Aptilo-Denied-Cause Ruleset-Failed 24
+
+#
+# Is sent by the AC to indicate what type of authentication
+# User - User initiated login, i.e. posting to /cgi-bin/login
+# Auto - Automatic login, e.g. "new station" based login or logins made
+# from /cgi-bin/auto
+# IP-Request - Request for a fixed IP address if available, as a result
+# of a client DHCP request.
+#
+VALUE Aptilo-Auth-Type User 0
+VALUE Aptilo-Auth-Type Auto 1
+VALUE Aptilo-Auth-Type IP-Request 2
+
+VALUE Aptilo-NAS-Capabilities CoA-Login 1
+
+VALUE Aptilo-Debug-Option Simulate-EAP-TLS 1
+
+END-VENDOR Aptilo
diff --git a/share/dictionary.aptis b/share/dictionary.aptis
new file mode 100644
index 0000000..26023bd
--- /dev/null
+++ b/share/dictionary.aptis
@@ -0,0 +1,184 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# $Id$
+#
+
+VENDOR Aptis 2637
+
+BEGIN-VENDOR Aptis
+ATTRIBUTE CVX-Identification 1 string
+ATTRIBUTE CVX-VPOP-ID 2 integer
+ATTRIBUTE CVX-SS7-Session-ID-Type 3 integer
+ATTRIBUTE CVX-Radius-Redirect 4 integer
+ATTRIBUTE CVX-IPSVC-AZNLVL 5 integer
+ATTRIBUTE CVX-IPSVC-Mask 6 integer
+ATTRIBUTE CVX-Multilink-Match-Info 7 integer
+ATTRIBUTE CVX-Multilink-Group-Number 8 integer
+ATTRIBUTE CVX-PPP-Log-Mask 9 integer
+
+ATTRIBUTE CVX-Modem-Begin-Modulation 10 string
+ATTRIBUTE CVX-Modem-End-Modulation 11 string
+ATTRIBUTE CVX-Modem-Error-Correction 12 string
+ATTRIBUTE CVX-Modem-Data-Compression 13 string
+ATTRIBUTE CVX-Modem-Tx-Packets 14 integer
+ATTRIBUTE CVX-Modem-ReTx-Packets 15 integer
+ATTRIBUTE CVX-Modem-SNR 16 integer
+ATTRIBUTE CVX-Modem-Local-Retrains 17 integer
+ATTRIBUTE CVX-Modem-Remote-Retrains 18 integer
+ATTRIBUTE CVX-Modem-Local-Rate-Negs 19 integer
+ATTRIBUTE CVX-Modem-Remote-Rate-Negs 20 integer
+ATTRIBUTE CVX-Modem-Begin-Recv-Line-Lvl 21 integer
+ATTRIBUTE CVX-Modem-End-Recv-Line-Lvl 22 integer
+ATTRIBUTE CVX-Terminate-Component 23 integer
+ATTRIBUTE CVX-Terminate-Cause 24 integer
+ATTRIBUTE CVX-Reject-Reason 25 integer
+
+#
+# These are similar to the Ascend attributes
+#
+ATTRIBUTE CVX-Primary-DNS 135 ipaddr
+ATTRIBUTE CVX-Secondary-DNS 136 ipaddr
+ATTRIBUTE CVX-Client-Assign-DNS 137 integer
+ATTRIBUTE CVX-Multicast-Rate-Limit 152 integer
+ATTRIBUTE CVX-Multicast-Client 155 integer
+ATTRIBUTE CVX-Disconnect-Cause 195 integer
+ATTRIBUTE CVX-Data-Rate 197 integer
+ATTRIBUTE CVX-PreSession-Time 198 integer
+ATTRIBUTE CVX-Assign-IP-Pool 218 integer
+ATTRIBUTE CVX-Maximum-Channels 235 integer
+ATTRIBUTE CVX-Data-Filter 242 string
+ATTRIBUTE CVX-Idle-Limit 244 integer
+ATTRIBUTE CVX-PPP-Address 253 ipaddr
+ATTRIBUTE CVX-Xmit-Rate 255 integer
+
+#
+# Aptis VSAs may have either one-octet or four-octet <type>
+# fields. One-octet types always have a type less than or equal
+# to 127 (i.e. the upper bit is set to 0); four-octet types
+# always have the upper bit set to 1.
+#
+# The 4-byte ones *appear* to also have a length, unlike the USR
+# attributes, but there's no way of knowing for sure.
+#
+# http://samuel.labs.nic.at/at43/dictionary
+# says a number of these are "boolean", which means what, exactly?
+#
+# These are commented out until we figure out how to parse them.
+#
+#ATTRIBUTE CVX-VPOP-DSByteEnabled 0x84c80001 integer
+#ATTRIBUTE CVX-VPOP-DSByteValue 0x84c80002 integer
+#ATTRIBUTE CVX-PPP-EstablishTimeLimit 0x85210065 integer
+#ATTRIBUTE CVX-PPP-ConnectLimit 0x85210066 integer
+#ATTRIBUTE CVX-PPP-InactivityLimit 0x85210067 integer
+#ATTRIBUTE CVX-PPP-MonitorTxActivity 0x85210068 integer
+#ATTRIBUTE CVX-PPP-MonitorRxActivity 0x85210069 integer
+#ATTRIBUTE CVX-PPP-CountRIP 0x8521006a integer
+#ATTRIBUTE CVX-PPP-CountPings 0x8521006b integer
+#ATTRIBUTE CVX-PPP-CountIGMP 0x8521006c integer
+#ATTRIBUTE CVX-PPP-UseEchoes 0x852100c9 integer
+#ATTRIBUTE CVX-PPP-SendID 0x852100ca integer
+#ATTRIBUTE CVX-PPP-SendTimeRemaining 0x852100cb integer
+#ATTRIBUTE CVX-PPP-SendMRU 0x8521012d integer
+#ATTRIBUTE CVX-PPP-SendACCM 0x8521012e integer
+#ATTRIBUTE CVX-PPP-SendMagic 0x8521012f integer
+#ATTRIBUTE CVX-PPP-SendPFC 0x85210130 integer
+#ATTRIBUTE CVX-PPP-SendACFC 0x85210131 integer
+#ATTRIBUTE CVX-PPP-SendShortSeq 0x85210132 integer
+#ATTRIBUTE CVX-PPP-SendEndpointDisc 0x85210133 integer
+#ATTRIBUTE CVX-PPP-AllowMRU 0x85210137 integer
+#ATTRIBUTE CVX-PPP-AllowACCM 0x85210138 integer
+#ATTRIBUTE CVX-PPP-AllowMagic 0x85210139 integer
+#ATTRIBUTE CVX-PPP-AllowPFC 0x8521013a integer
+#ATTRIBUTE CVX-PPP-AllowACFC 0x8521013b integer
+#ATTRIBUTE CVX-PPP-AllowShortSeq 0x8521013c integer
+#ATTRIBUTE CVX-PPP-AllowEndpointDisc 0x8521013d integer
+#ATTRIBUTE CVX-PPP-LCPMaxConfigure 0x85210191 integer
+#ATTRIBUTE CVX-PPP-LCPRestartTimer 0x85210192 integer
+#ATTRIBUTE CVX-PPP-PassiveLCP 0x85210193 integer
+#ATTRIBUTE CVX-PPP-PassiveLCPTimeout 0x85210194 integer
+#ATTRIBUTE CVX-PPP-MinRemoteMRU 0x852101f5 integer
+#ATTRIBUTE CVX-PPP-MinLocalMRU 0x852101f6 integer
+#ATTRIBUTE CVX-PPP-DesiredLocalMRU 0x852101f7 integer
+#ATTRIBUTE CVX-PPP-TransmitACCM 0x852101f8 integer
+#ATTRIBUTE CVX-PPP-ReceiveACCM 0x852101f9 integer
+#ATTRIBUTE CVX-PPP-MinRemoteMRRU 0x852101fa integer
+#ATTRIBUTE CVX-PPP-DesiredRemoteMRRU 0x852101fb integer
+#ATTRIBUTE CVX-PPP-MinLocalMRRU 0x852101fc integer
+#ATTRIBUTE CVX-PPP-DesiredLocalMRRU 0x852101fd integer
+#ATTRIBUTE CVX-PPP-LCPEchoRetries 0x852101fe integer
+#ATTRIBUTE CVX-PPP-LCPEchoTimeout 0x852101ff integer
+#ATTRIBUTE CVX-PPP-LCPEchoErrorTimeout 0x85210200 integer
+#ATTRIBUTE CVX-PPP-TimeRemainingInterval 0x85210201 integer
+#ATTRIBUTE CVX-PPP-IDText 0x85210202 string
+#ATTRIBUTE CVX-PPP-AuthRequire 0x85210259 integer
+#ATTRIBUTE CVX-PPP-AuthAllow 0x8521025a integer
+#ATTRIBUTE CVX-PPP-AuthServerProtocol1 0x85210262 integer
+#ATTRIBUTE CVX-PPP-AuthServerProtocol2 0x85210263 integer
+#ATTRIBUTE CVX-PPP-AuthServerProtocol3 0x85210264 integer
+#ATTRIBUTE CVX-PPP-AuthServerProtocol4 0x85210265 integer
+#ATTRIBUTE CVX-PPP-AuthClientProtocol1 0x8521026d integer
+#ATTRIBUTE CVX-PPP-AuthClientProtocol2 0x8521026e integer
+#ATTRIBUTE CVX-PPP-AuthClientProtocol3 0x8521026f integer
+#ATTRIBUTE CVX-PPP-AuthClientProtocol4 0x85210270 integer
+#ATTRIBUTE CVX-PPP-PAPClientRetries 0x85210277 integer
+#ATTRIBUTE CVX-PPP-PAPClientTimeout 0x85210278 integer
+#ATTRIBUTE CVX-PPP-PAPServerRetries 0x85210279 integer
+#ATTRIBUTE CVX-PPP-PAPServerTimeout 0x8521027a integer
+#ATTRIBUTE CVX-PPP-CHAPClientRetries 0x85210281 integer
+#ATTRIBUTE CVX-PPP-CHAPClientTimeout 0x85210282 integer
+#ATTRIBUTE CVX-PPP-CHAPServerRetries 0x85210283 integer
+#ATTRIBUTE CVX-PPP-CHAPServerChallenges 0x85210284 integer
+#ATTRIBUTE CVX-PPP-CHAPServerTimeout 0x85210285 integer
+#ATTRIBUTE CVX-PPP-CHAPValueLength 0x85210286 integer
+#ATTRIBUTE CVX-PPP-AuthFailureRenegotiatesLCP 0x85210287 integer
+#ATTRIBUTE CVX-PPP-UserName 0x8521028b string
+#ATTRIBUTE CVX-PPP-Password 0x8521028c string
+#ATTRIBUTE CVX-PPP-IPCPEnabled 0x852102bd integer
+#ATTRIBUTE CVX-PPP-LocalIPAddress 0x852102be ipaddr
+#ATTRIBUTE CVX-PPP-RemoteIPAddress 0x852102bf ipaddr
+#ATTRIBUTE CVX-PPP-AllowPeerIPAddress 0x852102c0 integer
+#ATTRIBUTE CVX-PPP-VJEnabled 0x852102c1 integer
+#ATTRIBUTE CVX-PPP-VJSlots 0x852102c2 integer
+#ATTRIBUTE CVX-PPP-SendDNS 0x852102c3 integer
+#ATTRIBUTE CVX-PPP-SendNBNS 0x852102c4 integer
+#ATTRIBUTE CVX-PPP-IPCPMaxConfigure 0x852102c5 integer
+#ATTRIBUTE CVX-PPP-IPCPRestartTimer 0x852102c6 integer
+#ATTRIBUTE CVX-PPP-PassiveIPCP 0x852102c7 integer
+#ATTRIBUTE CVX-PPP-PassiveIPCPTimeout 0x852102c8 integer
+#ATTRIBUTE CVX-PPP-DNS1 0x852102c9 ipaddr
+#ATTRIBUTE CVX-PPP-DNS2 0x852102ca ipaddr
+#ATTRIBUTE CVX-PPP-NBNS1 0x852102cb ipaddr
+#ATTRIBUTE CVX-PPP-NBNS2 0x852102cc ipaddr
+#ATTRIBUTE CVX-PPP-SendLocalIPAddress 0x852102cd integer
+#ATTRIBUTE CVX-PPP-RejectUnknownNS 0x852102ce integer
+#ATTRIBUTE CVX-PPP-PeerNSStrategy 0x852102cf integer
+#ATTRIBUTE CVX-PPP-MLPEnabled 0x85210321 integer
+#ATTRIBUTE CVX-PPP-MLPMaxLinks 0x85210322 integer
+#ATTRIBUTE CVX-PPP-MLPFragmentSize 0x85210323 integer
+#ATTRIBUTE CVX-PPP-MLPMaxFragments 0x85210324 integer
+#ATTRIBUTE CVX-PPP-MLPScaleFragments 0x85210325 integer
+#ATTRIBUTE CVX-PPP-MLPSendNullFragments 0x85210326 integer
+#ATTRIBUTE CVX-PPP-MLPNullFragmentTimeout 0x85210327 integer
+#ATTRIBUTE CVX-PPP-MLPEndpointDisc 0x85210328 integer
+#ATTRIBUTE CVX-PPP-MLPGroupNumber 0x85210329 integer
+#ATTRIBUTE CVX-PPP-LogEnabled 0x85210385 integer
+#ATTRIBUTE CVX-PPP-LogDump 0x85210386 integer
+#ATTRIBUTE CVX-PPP-LogSize 0x8521038e integer
+#ATTRIBUTE CVX-PPP-LogControlFrames 0x8521038f integer
+#ATTRIBUTE CVX-PPP-LogProtocolFrames 0x85210390 integer
+#ATTRIBUTE CVX-PPP-LogOptions 0x85210391 integer
+#ATTRIBUTE CVX-PPP-LogStates 0x85210392 integer
+#ATTRIBUTE CVX-PPP-LogCompression 0x85210393 integer
+#ATTRIBUTE CVX-PPP-LogMLP 0x85210394 integer
+#ATTRIBUTE CVX-PPP-LogVJ 0x85210395 integer
+#ATTRIBUTE CVX-PPP-CCPEnabled 0x852103e9 integer
+#ATTRIBUTE CVX-PPP-CompressFrames 0x852103ea integer
+#ATTRIBUTE CVX-PPP-Stac3Enabled 0x852103eb integer
+#ATTRIBUTE CVX-PPP-Stac4Enabled 0x852103ec integer
+#ATTRIBUTE CVX-PPP-MPPCEnabled 0x852103ed integer
+#ATTRIBUTE CVX-PPP-StacPerformance 0x852103ee integer
+#ATTRIBUTE CVX-PPP-StacMode 0x852103ef integer
+
+END-VENDOR Aptis
diff --git a/share/dictionary.arbor b/share/dictionary.arbor
new file mode 100644
index 0000000..8ac3a07
--- /dev/null
+++ b/share/dictionary.arbor
@@ -0,0 +1,21 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Arbor networks.
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR Arbor 9694
+
+BEGIN-VENDOR Arbor
+
+# Arbor-Privilege-Level = "system_admin or system_analyst or system_user"
+
+ATTRIBUTE Arbor-Privilege-Level 1 string
+
+END-VENDOR Arbor
diff --git a/share/dictionary.arista b/share/dictionary.arista
new file mode 100644
index 0000000..8dbea47
--- /dev/null
+++ b/share/dictionary.arista
@@ -0,0 +1,29 @@
+# -*- text -*-
+# Copyright (C) 2020 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+# Version $Id$
+##############################################################################
+#
+# Arista VSAs
+# https://eos.arista.com/common-aaa-requirements/
+#
+##############################################################################
+
+VENDOR Arista 30065
+BEGIN-VENDOR Arista
+
+ATTRIBUTE Arista-AVPair 1 string
+ATTRIBUTE Arista-User-Priv-Level 2 integer
+ATTRIBUTE Arista-User-Role 3 string
+ATTRIBUTE Arista-CVP-Role 4 string
+ATTRIBUTE Arista-Command 5 string
+ATTRIBUTE Arista-WebAuth 6 integer
+ATTRIBUTE Arista-BlockMac 7 string
+ATTRIBUTE Arista-UnblockMac 8 string
+ATTRIBUTE Arista-PortFlap 9 integer
+ATTRIBUTE Arista-Captive-Portal 10 string
+
+VALUE Arista-WebAuth start 1
+VALUE Arista-WebAuth complete 2
+
+END-VENDOR Arista
diff --git a/share/dictionary.aruba b/share/dictionary.aruba
new file mode 100644
index 0000000..f4a4a03
--- /dev/null
+++ b/share/dictionary.aruba
@@ -0,0 +1,101 @@
+# -*- text -*-
+# Copyright (C) 2020 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+# Version $Id$
+#
+# Version: $Id$
+#
+VENDOR Aruba 14823
+BEGIN-VENDOR Aruba
+
+ATTRIBUTE Aruba-User-Role 1 string
+ATTRIBUTE Aruba-User-Vlan 2 integer
+ATTRIBUTE Aruba-Priv-Admin-User 3 integer
+ATTRIBUTE Aruba-Admin-Role 4 string
+ATTRIBUTE Aruba-Essid-Name 5 string
+ATTRIBUTE Aruba-Location-Id 6 string
+ATTRIBUTE Aruba-Port-Identifier 7 string
+ATTRIBUTE Aruba-MMS-User-Template 8 string
+ATTRIBUTE Aruba-Named-User-Vlan 9 string
+ATTRIBUTE Aruba-AP-Group 10 string
+
+ATTRIBUTE Aruba-Framed-IPv6-Address 11 string
+ATTRIBUTE Aruba-Device-Type 12 string
+ATTRIBUTE Aruba-No-DHCP-Fingerprint 14 integer
+ATTRIBUTE Aruba-Mdps-Device-Udid 15 string
+ATTRIBUTE Aruba-Mdps-Device-Imei 16 string
+ATTRIBUTE Aruba-Mdps-Device-Iccid 17 string
+ATTRIBUTE Aruba-Mdps-Max-Devices 18 integer
+ATTRIBUTE Aruba-Mdps-Device-Name 19 string
+ATTRIBUTE Aruba-Mdps-Device-Product 20 string
+
+ATTRIBUTE Aruba-Mdps-Device-Version 21 string
+ATTRIBUTE Aruba-Mdps-Device-Serial 22 string
+ATTRIBUTE Aruba-CPPM-Role 23 string
+ATTRIBUTE Aruba-AirGroup-User-Name 24 string
+ATTRIBUTE Aruba-AirGroup-Shared-User 25 string
+ATTRIBUTE Aruba-AirGroup-Shared-Role 26 string
+ATTRIBUTE Aruba-AirGroup-Device-Type 27 integer
+ATTRIBUTE Aruba-Auth-Survivability 28 string
+ATTRIBUTE Aruba-AS-User-Name 29 string
+ATTRIBUTE Aruba-AS-Credential-Hash 30 string
+
+ATTRIBUTE Aruba-WorkSpace-App-Name 31 string
+ATTRIBUTE Aruba-Mdps-Provisioning-Settings 32 string
+ATTRIBUTE Aruba-Mdps-Device-Profile 33 string
+ATTRIBUTE Aruba-AP-IP-Address 34 ipaddr
+ATTRIBUTE Aruba-AirGroup-Shared-Group 35 string
+ATTRIBUTE Aruba-User-Group 36 string
+ATTRIBUTE Aruba-Network-SSO-Token 37 string
+ATTRIBUTE Aruba-AirGroup-Version 38 integer
+ATTRIBUTE Aruba-Auth-SurvMethod 39 integer
+ATTRIBUTE Aruba-Port-Bounce-Host 40 integer
+
+ATTRIBUTE Aruba-Calea-Server-Ip 41 ipaddr
+ATTRIBUTE Aruba-Admin-Path 42 string
+ATTRIBUTE Aruba-Captive-Portal-URL 43 string
+ATTRIBUTE Aruba-MPSK-Passphrase 44 octets encrypt=2
+ATTRIBUTE Aruba-ACL-Server-Query-Info 45 string
+ATTRIBUTE Aruba-Command-String 46 string
+ATTRIBUTE Aruba-Network-Profile 47 string
+ATTRIBUTE Aruba-Admin-Device-Group 48 string
+ATTRIBUTE Aruba-PoE-Priority 49 integer
+ATTRIBUTE Aruba-Port-Auth-Mode 50 integer
+
+ATTRIBUTE Aruba-NAS-Filter-Rule 51 string
+ATTRIBUTE Aruba-QoS-Trust-Mode 52 integer
+ATTRIBUTE Aruba-UBT-Gateway-Role 53 string
+ATTRIBUTE Aruba-Gateway-Zone 54 string
+
+ATTRIBUTE Aruba-STP-Admin-Edge-Port 58 integer
+
+ATTRIBUTE Aruba-UBT-Gateway-CPPM-Role 59 string
+
+ATTRIBUTE Aruba-AP-MAC-Address 60 string
+ATTRIBUTE Aruba-Device-MAC-Address 61 string
+ATTRIBUTE Aruba-Device-Traffic-Class 63 integer
+
+
+VALUE Aruba-AirGroup-Device-Type Personal-Device 1
+VALUE Aruba-AirGroup-Device-Type Shared-Device 2
+VALUE Aruba-AirGroup-Device-Type Deleted-Device 3
+
+VALUE Aruba-AirGroup-Version AirGroup-v1 1
+VALUE Aruba-AirGroup-Version AirGroup-v2 2
+
+VALUE Aruba-PoE-Priority Critical 0
+VALUE Aruba-PoE-Priority High 1
+VALUE Aruba-PoE-Priority Low 2
+
+VALUE Aruba-Port-Auth-Mode Infrastructure-Mode 1
+VALUE Aruba-Port-Auth-Mode Client-Mode 2
+VALUE Aruba-Port-Auth-Mode Multi-Domain-Mode 3
+
+VALUE Aruba-QoS-Trust-Mode DSCP 0
+VALUE Aruba-QoS-Trust-Mode QoS 1
+VALUE Aruba-QoS-Trust-Mode None 2
+
+VALUE Aruba-STP-Admin-Edge-Port Disable 0
+VALUE Aruba-STP-Admin-Edge-Port Enable 1
+
+END-VENDOR Aruba
diff --git a/share/dictionary.ascend b/share/dictionary.ascend
new file mode 100644
index 0000000..b34e884
--- /dev/null
+++ b/share/dictionary.ascend
@@ -0,0 +1,899 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Ascend dictionary.
+#
+# $Id$
+#
+##############################################################################
+
+#
+# For 16-bit Ascend VSA's, see dictionary.lucent. Those VSA's
+# are in the Lucent namespace, and belong in that file, rather
+# than here.
+#
+#
+# The Ascend-Data-Filter and Ascend-Call-Filter are case insensitive
+# strings, with the following format:
+#
+# IP FILTERS:
+#
+# 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.
+# where:
+#
+# ip: Keyword to designate an IP filter. Actually this
+# has been determined by parseFilter.
+#
+# dir: Filter direction. "IN" or "OUT"
+#
+# action: Filter action. "FORWARD" or "DROP"
+#
+# 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.
+#
+# IPX FILTERS
+#
+# ipx dir action [ srcipxnet nnnn srcipxnode mmmmm [srcipxsoc cmd value ]]
+# [ dstipxnet nnnn dstipxnode mmmmm [dstipxsoc cmd value ]]
+#
+# Fields in [...] are optional.
+# where:
+#
+# ipx: Keyword to designate an IPX filter. Actually this
+# has been determined by parseFilter.
+#
+# dir: Filter direction. "IN" or "OUT"
+#
+# action: Filter action. "FORWARD" or "DROP"
+#
+# 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 "!=".
+# (without the quotes)
+#
+# 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 vlid ipx node number should accompany ipx net number.
+#
+# dstipxsoc: Keyword for destination IPX socket address.
+#
+# cmd: One of ">" or "<" or "=" or "!=".
+# (without the quotes)
+#
+# value: Socket value to be compared against, in hex.
+#
+# GENERIC FILTERS
+#
+# generic dir action offset mask value [== or != ] [more]
+#
+# Fields in [...] are optional.
+# where:
+#
+# generic: Keyword to indicate a generic filter. This
+# has been determined by parseFilter.
+#
+# dir: Filter direction. "IN" or "OUT"
+#
+# action: Filter action. "FORWARD" or "DROP"
+#
+# 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.
+
+VENDOR Ascend 529
+
+#
+# Ascend vendor-specific attributes.
+#
+BEGIN-VENDOR Ascend
+ATTRIBUTE Ascend-Max-Shared-Users 2 integer
+ATTRIBUTE Ascend-UU-Info 7 string
+ATTRIBUTE Ascend-CIR-Timer 9 integer
+ATTRIBUTE Ascend-FR-08-Mode 10 integer
+ATTRIBUTE Ascend-Destination-Nas-Port 11 integer
+ATTRIBUTE Ascend-FR-SVC-Addr 12 string
+ATTRIBUTE Ascend-NAS-Port-Format 13 integer
+ATTRIBUTE Ascend-ATM-Fault-Management 14 integer
+ATTRIBUTE Ascend-ATM-Loopback-Cell-Loss 15 integer
+ATTRIBUTE Ascend-Ckt-Type 16 integer
+ATTRIBUTE Ascend-SVC-Enabled 17 integer
+ATTRIBUTE Ascend-Session-Type 18 integer
+ATTRIBUTE Ascend-H323-Gatekeeper 19 ipaddr
+ATTRIBUTE Ascend-Global-Call-Id 20 string
+ATTRIBUTE Ascend-H323-Conference-Id 21 integer
+ATTRIBUTE Ascend-H323-Fegw-Address 22 ipaddr
+ATTRIBUTE Ascend-H323-Dialed-Time 23 integer
+ATTRIBUTE Ascend-Dialed-Number 24 string
+ATTRIBUTE Ascend-Inter-Arrival-Jitter 25 integer
+ATTRIBUTE Ascend-Dropped-Octets 26 integer
+ATTRIBUTE Ascend-Dropped-Packets 27 integer
+ATTRIBUTE Ascend-Auth-Delay 28 integer
+ATTRIBUTE Ascend-X25-Pad-X3-Profile 29 integer
+ATTRIBUTE Ascend-X25-Pad-X3-Parameters 30 string
+ATTRIBUTE Ascend-Tunnel-VRouter-Name 31 string
+ATTRIBUTE Ascend-X25-Reverse-Charging 32 integer
+ATTRIBUTE Ascend-X25-Nui-Prompt 33 string
+ATTRIBUTE Ascend-X25-Nui-Password-Prompt 34 string
+ATTRIBUTE Ascend-X25-Cug 35 string
+ATTRIBUTE Ascend-X25-Pad-Alias-1 36 string
+ATTRIBUTE Ascend-X25-Pad-Alias-2 37 string
+ATTRIBUTE Ascend-X25-Pad-Alias-3 38 string
+ATTRIBUTE Ascend-X25-X121-Address 39 string
+ATTRIBUTE Ascend-X25-Nui 40 string
+ATTRIBUTE Ascend-X25-Rpoa 41 string
+ATTRIBUTE Ascend-X25-Pad-Prompt 42 string
+ATTRIBUTE Ascend-X25-Pad-Banner 43 string
+ATTRIBUTE Ascend-X25-Profile-Name 44 string
+ATTRIBUTE Ascend-Recv-Name 45 string
+ATTRIBUTE Ascend-Bi-Directional-Auth 46 integer
+ATTRIBUTE Ascend-MTU 47 integer
+ATTRIBUTE Ascend-Call-Direction 48 integer
+ATTRIBUTE Ascend-Service-Type 49 integer
+ATTRIBUTE Ascend-Filter-Required 50 integer
+ATTRIBUTE Ascend-Traffic-Shaper 51 integer
+ATTRIBUTE Ascend-Access-Intercept-LEA 52 string
+ATTRIBUTE Ascend-Access-Intercept-Log 53 string
+ATTRIBUTE Ascend-Private-Route-Table-ID 54 string
+ATTRIBUTE Ascend-Private-Route-Required 55 integer
+ATTRIBUTE Ascend-Cache-Refresh 56 integer
+ATTRIBUTE Ascend-Cache-Time 57 integer
+ATTRIBUTE Ascend-Egress-Enabled 58 integer
+ATTRIBUTE Ascend-QOS-Upstream 59 string
+ATTRIBUTE Ascend-QOS-Downstream 60 string
+ATTRIBUTE Ascend-ATM-Connect-Vpi 61 integer
+ATTRIBUTE Ascend-ATM-Connect-Vci 62 integer
+ATTRIBUTE Ascend-ATM-Connect-Group 63 integer
+ATTRIBUTE Ascend-ATM-Group 64 integer
+ATTRIBUTE Ascend-IPX-Header-Compression 65 integer
+ATTRIBUTE Ascend-Calling-Id-Type-Of-Num 66 integer
+ATTRIBUTE Ascend-Calling-Id-Number-Plan 67 integer
+ATTRIBUTE Ascend-Calling-Id-Presentatn 68 integer
+ATTRIBUTE Ascend-Calling-Id-Screening 69 integer
+ATTRIBUTE Ascend-BIR-Enable 70 integer
+ATTRIBUTE Ascend-BIR-Proxy 71 integer
+ATTRIBUTE Ascend-BIR-Bridge-Group 72 integer
+ATTRIBUTE Ascend-IPSEC-Profile 73 string
+ATTRIBUTE Ascend-PPPoE-Enable 74 integer
+ATTRIBUTE Ascend-Bridge-Non-PPPoE 75 integer
+ATTRIBUTE Ascend-ATM-Direct 76 integer
+ATTRIBUTE Ascend-ATM-Direct-Profile 77 string
+ATTRIBUTE Ascend-Client-Primary-WINS 78 ipaddr
+ATTRIBUTE Ascend-Client-Secondary-WINS 79 ipaddr
+ATTRIBUTE Ascend-Client-Assign-WINS 80 integer
+ATTRIBUTE Ascend-Auth-Type 81 integer
+ATTRIBUTE Ascend-Port-Redir-Protocol 82 integer
+ATTRIBUTE Ascend-Port-Redir-Portnum 83 integer
+ATTRIBUTE Ascend-Port-Redir-Server 84 ipaddr
+ATTRIBUTE Ascend-IP-Pool-Chaining 85 integer
+ATTRIBUTE Ascend-Owner-IP-Addr 86 ipaddr
+ATTRIBUTE Ascend-IP-TOS 87 integer
+ATTRIBUTE Ascend-IP-TOS-Precedence 88 integer
+ATTRIBUTE Ascend-IP-TOS-Apply-To 89 integer
+ATTRIBUTE Ascend-Filter 90 string
+ATTRIBUTE Ascend-Telnet-Profile 91 string
+ATTRIBUTE Ascend-Dsl-Rate-Type 92 integer
+ATTRIBUTE Ascend-Redirect-Number 93 string
+ATTRIBUTE Ascend-ATM-Vpi 94 integer
+ATTRIBUTE Ascend-ATM-Vci 95 integer
+ATTRIBUTE Ascend-Source-IP-Check 96 integer
+ATTRIBUTE Ascend-Dsl-Rate-Mode 97 integer
+ATTRIBUTE Ascend-Dsl-Upstream-Limit 98 integer
+ATTRIBUTE Ascend-Dsl-Downstream-Limit 99 integer
+ATTRIBUTE Ascend-Dsl-CIR-Recv-Limit 100 integer
+ATTRIBUTE Ascend-Dsl-CIR-Xmit-Limit 101 integer
+ATTRIBUTE Ascend-VRouter-Name 102 string
+ATTRIBUTE Ascend-Source-Auth 103 string
+ATTRIBUTE Ascend-Private-Route 104 string
+ATTRIBUTE Ascend-Numbering-Plan-ID 105 integer
+ATTRIBUTE Ascend-FR-Link-Status-DLCI 106 integer
+ATTRIBUTE Ascend-Calling-Subaddress 107 string
+ATTRIBUTE Ascend-Callback-Delay 108 integer
+ATTRIBUTE Ascend-Endpoint-Disc 109 string
+ATTRIBUTE Ascend-Remote-FW 110 string
+ATTRIBUTE Ascend-Multicast-GLeave-Delay 111 integer
+ATTRIBUTE Ascend-CBCP-Enable 112 integer
+ATTRIBUTE Ascend-CBCP-Mode 113 integer
+ATTRIBUTE Ascend-CBCP-Delay 114 integer
+ATTRIBUTE Ascend-CBCP-Trunk-Group 115 integer
+ATTRIBUTE Ascend-Appletalk-Route 116 string
+ATTRIBUTE Ascend-Appletalk-Peer-Mode 117 integer
+ATTRIBUTE Ascend-Route-Appletalk 118 integer
+ATTRIBUTE Ascend-FCP-Parameter 119 string
+ATTRIBUTE Ascend-Modem-PortNo 120 integer
+ATTRIBUTE Ascend-Modem-SlotNo 121 integer
+ATTRIBUTE Ascend-Modem-ShelfNo 122 integer
+ATTRIBUTE Ascend-Call-Attempt-Limit 123 integer
+ATTRIBUTE Ascend-Call-Block-Duration 124 integer
+ATTRIBUTE Ascend-Maximum-Call-Duration 125 integer
+ATTRIBUTE Ascend-Temporary-Rtes 126 integer
+ATTRIBUTE Ascend-Tunneling-Protocol 127 integer
+ATTRIBUTE Ascend-Shared-Profile-Enable 128 integer
+ATTRIBUTE Ascend-Primary-Home-Agent 129 string
+ATTRIBUTE Ascend-Secondary-Home-Agent 130 string
+ATTRIBUTE Ascend-Dialout-Allowed 131 integer
+ATTRIBUTE Ascend-Client-Gateway 132 ipaddr
+ATTRIBUTE Ascend-BACP-Enable 133 integer
+ATTRIBUTE Ascend-DHCP-Maximum-Leases 134 integer
+ATTRIBUTE Ascend-Client-Primary-DNS 135 ipaddr
+ATTRIBUTE Ascend-Client-Secondary-DNS 136 ipaddr
+ATTRIBUTE Ascend-Client-Assign-DNS 137 integer
+ATTRIBUTE Ascend-User-Acct-Type 138 integer
+ATTRIBUTE Ascend-User-Acct-Host 139 ipaddr
+ATTRIBUTE Ascend-User-Acct-Port 140 integer
+ATTRIBUTE Ascend-User-Acct-Key 141 string
+ATTRIBUTE Ascend-User-Acct-Base 142 integer
+ATTRIBUTE Ascend-User-Acct-Time 143 integer
+ATTRIBUTE Ascend-Assign-IP-Client 144 ipaddr
+ATTRIBUTE Ascend-Assign-IP-Server 145 ipaddr
+ATTRIBUTE Ascend-Assign-IP-Global-Pool 146 string
+ATTRIBUTE Ascend-DHCP-Reply 147 integer
+ATTRIBUTE Ascend-DHCP-Pool-Number 148 integer
+ATTRIBUTE Ascend-Expect-Callback 149 integer
+ATTRIBUTE Ascend-Event-Type 150 integer
+ATTRIBUTE Ascend-Session-Svr-Key 151 string
+ATTRIBUTE Ascend-Multicast-Rate-Limit 152 integer
+ATTRIBUTE Ascend-IF-Netmask 153 ipaddr
+ATTRIBUTE Ascend-Remote-Addr 154 ipaddr
+ATTRIBUTE Ascend-Multicast-Client 155 integer
+ATTRIBUTE Ascend-FR-Circuit-Name 156 string
+ATTRIBUTE Ascend-FR-LinkUp 157 integer
+ATTRIBUTE Ascend-FR-Nailed-Grp 158 integer
+ATTRIBUTE Ascend-FR-Type 159 integer
+ATTRIBUTE Ascend-FR-Link-Mgt 160 integer
+ATTRIBUTE Ascend-FR-N391 161 integer
+ATTRIBUTE Ascend-FR-DCE-N392 162 integer
+ATTRIBUTE Ascend-FR-DTE-N392 163 integer
+ATTRIBUTE Ascend-FR-DCE-N393 164 integer
+ATTRIBUTE Ascend-FR-DTE-N393 165 integer
+ATTRIBUTE Ascend-FR-T391 166 integer
+ATTRIBUTE Ascend-FR-T392 167 integer
+ATTRIBUTE Ascend-Bridge-Address 168 string
+ATTRIBUTE Ascend-TS-Idle-Limit 169 integer
+ATTRIBUTE Ascend-TS-Idle-Mode 170 integer
+ATTRIBUTE Ascend-DBA-Monitor 171 integer
+ATTRIBUTE Ascend-Base-Channel-Count 172 integer
+ATTRIBUTE Ascend-Minimum-Channels 173 integer
+ATTRIBUTE Ascend-IPX-Route 174 string
+ATTRIBUTE Ascend-FT1-Caller 175 integer
+ATTRIBUTE Ascend-Backup 176 string
+ATTRIBUTE Ascend-Call-Type 177 integer
+ATTRIBUTE Ascend-Group 178 string
+ATTRIBUTE Ascend-FR-DLCI 179 integer
+ATTRIBUTE Ascend-FR-Profile-Name 180 string
+ATTRIBUTE Ascend-Ara-PW 181 string
+ATTRIBUTE Ascend-IPX-Node-Addr 182 string
+ATTRIBUTE Ascend-Home-Agent-IP-Addr 183 ipaddr
+ATTRIBUTE Ascend-Home-Agent-Password 184 string
+ATTRIBUTE Ascend-Home-Network-Name 185 string
+ATTRIBUTE Ascend-Home-Agent-UDP-Port 186 integer
+ATTRIBUTE Ascend-Multilink-ID 187 integer
+ATTRIBUTE Ascend-Num-In-Multilink 188 integer
+ATTRIBUTE Ascend-First-Dest 189 ipaddr
+ATTRIBUTE Ascend-Pre-Input-Octets 190 integer
+ATTRIBUTE Ascend-Pre-Output-Octets 191 integer
+ATTRIBUTE Ascend-Pre-Input-Packets 192 integer
+ATTRIBUTE Ascend-Pre-Output-Packets 193 integer
+ATTRIBUTE Ascend-Maximum-Time 194 integer
+ATTRIBUTE Ascend-Disconnect-Cause 195 integer
+ATTRIBUTE Ascend-Connect-Progress 196 integer
+ATTRIBUTE Ascend-Data-Rate 197 integer
+ATTRIBUTE Ascend-PreSession-Time 198 integer
+ATTRIBUTE Ascend-Token-Idle 199 integer
+ATTRIBUTE Ascend-Token-Immediate 200 integer
+ATTRIBUTE Ascend-Require-Auth 201 integer
+ATTRIBUTE Ascend-Number-Sessions 202 string
+ATTRIBUTE Ascend-Authen-Alias 203 string
+ATTRIBUTE Ascend-Token-Expiry 204 integer
+ATTRIBUTE Ascend-Menu-Selector 205 string
+ATTRIBUTE Ascend-Menu-Item 206 string
+ATTRIBUTE Ascend-PW-Warntime 207 integer
+ATTRIBUTE Ascend-PW-Lifetime 208 integer
+ATTRIBUTE Ascend-IP-Direct 209 ipaddr
+ATTRIBUTE Ascend-PPP-VJ-Slot-Comp 210 integer
+ATTRIBUTE Ascend-PPP-VJ-1172 211 integer
+ATTRIBUTE Ascend-PPP-Async-Map 212 integer
+ATTRIBUTE Ascend-Third-Prompt 213 string
+ATTRIBUTE Ascend-Send-Secret 214 string encrypt=3
+ATTRIBUTE Ascend-Receive-Secret 215 string encrypt=3
+ATTRIBUTE Ascend-IPX-Peer-Mode 216 integer
+ATTRIBUTE Ascend-IP-Pool-Definition 217 string
+ATTRIBUTE Ascend-Assign-IP-Pool 218 integer
+ATTRIBUTE Ascend-FR-Direct 219 integer
+ATTRIBUTE Ascend-FR-Direct-Profile 220 string
+ATTRIBUTE Ascend-FR-Direct-DLCI 221 integer
+ATTRIBUTE Ascend-Handle-IPX 222 integer
+ATTRIBUTE Ascend-Netware-timeout 223 integer
+ATTRIBUTE Ascend-IPX-Alias 224 integer
+ATTRIBUTE Ascend-Metric 225 integer
+ATTRIBUTE Ascend-PRI-Number-Type 226 integer
+ATTRIBUTE Ascend-Dial-Number 227 string
+ATTRIBUTE Ascend-Route-IP 228 integer
+ATTRIBUTE Ascend-Route-IPX 229 integer
+ATTRIBUTE Ascend-Bridge 230 integer
+ATTRIBUTE Ascend-Send-Auth 231 integer
+ATTRIBUTE Ascend-Send-Passwd 232 string
+ATTRIBUTE Ascend-Link-Compression 233 integer
+ATTRIBUTE Ascend-Target-Util 234 integer
+ATTRIBUTE Ascend-Maximum-Channels 235 integer
+ATTRIBUTE Ascend-Inc-Channel-Count 236 integer
+ATTRIBUTE Ascend-Dec-Channel-Count 237 integer
+ATTRIBUTE Ascend-Seconds-Of-History 238 integer
+ATTRIBUTE Ascend-History-Weigh-Type 239 integer
+ATTRIBUTE Ascend-Add-Seconds 240 integer
+ATTRIBUTE Ascend-Remove-Seconds 241 integer
+ATTRIBUTE Ascend-Data-Filter 242 abinary
+ATTRIBUTE Ascend-Call-Filter 243 abinary
+ATTRIBUTE Ascend-Idle-Limit 244 integer
+ATTRIBUTE Ascend-Preempt-Limit 245 integer
+ATTRIBUTE Ascend-Callback 246 integer
+ATTRIBUTE Ascend-Data-Svc 247 integer
+ATTRIBUTE Ascend-Force-56 248 integer
+ATTRIBUTE Ascend-Billing-Number 249 string
+ATTRIBUTE Ascend-Call-By-Call 250 integer
+ATTRIBUTE Ascend-Transit-Number 251 string
+ATTRIBUTE Ascend-Host-Info 252 string
+ATTRIBUTE Ascend-PPP-Address 253 ipaddr
+ATTRIBUTE Ascend-MPP-Idle-Percent 254 integer
+ATTRIBUTE Ascend-Xmit-Rate 255 integer
+
+# Ascend protocols
+VALUE Framed-Protocol Ascend-ARA 255
+VALUE Framed-Protocol Ascend-MPP 256
+VALUE Framed-Protocol Ascend-EURAW 257
+VALUE Framed-Protocol Ascend-EUUI 258
+VALUE Framed-Protocol Ascend-X25 259
+VALUE Framed-Protocol Ascend-COMB 260
+VALUE Framed-Protocol Ascend-FR 261
+VALUE Framed-Protocol Ascend-MP 262
+VALUE Framed-Protocol Ascend-FR-CIR 263
+
+#
+# Ascend specific extensions
+# Used by ASCEND MAX/Pipeline products (see above)
+#
+
+VALUE Ascend-Source-IP-Check Source-IP-Check-No 0
+VALUE Ascend-Source-IP-Check Source-IP-Check-Yes 1
+VALUE Ascend-CBCP-Enable CBCP-Not-Enabled 0
+VALUE Ascend-CBCP-Enable CBCP-Enabled 1
+VALUE Ascend-CBCP-Mode CBCP-No-Callback 1
+VALUE Ascend-CBCP-Mode CBCP-User-Callback 2
+VALUE Ascend-CBCP-Mode CBCP-Profile-Callback 3
+VALUE Ascend-CBCP-Mode CBCP-Any-Or-No 7
+VALUE Ascend-CBCP-Mode CBCP-Off 8
+VALUE Ascend-FR-Direct FR-Direct-No 0
+VALUE Ascend-FR-Direct FR-Direct-Yes 1
+VALUE Ascend-Handle-IPX Handle-IPX-None 0
+VALUE Ascend-Handle-IPX Handle-IPX-Client 1
+VALUE Ascend-Handle-IPX Handle-IPX-Server 2
+VALUE Ascend-IPX-Peer-Mode IPX-Peer-Router 0
+VALUE Ascend-IPX-Peer-Mode IPX-Peer-Dialin 1
+VALUE Ascend-Call-Type Switched 0
+VALUE Ascend-Call-Type Nailed 1
+VALUE Ascend-Call-Type Nailed/Mpp 2
+VALUE Ascend-Call-Type Perm/Switched 3
+VALUE Ascend-Call-Type AO/DI 6
+VALUE Ascend-Call-Type MegaMax 7
+VALUE Ascend-FT1-Caller FT1-No 0
+VALUE Ascend-FT1-Caller FT1-Yes 1
+VALUE Ascend-PRI-Number-Type Unknown-Number 0
+VALUE Ascend-PRI-Number-Type Intl-Number 1
+VALUE Ascend-PRI-Number-Type National-Number 2
+VALUE Ascend-PRI-Number-Type Net-Specific-Number 3
+VALUE Ascend-PRI-Number-Type Local-Number 4
+VALUE Ascend-PRI-Number-Type Abbrev-Number 5
+
+VALUE Ascend-Route-IP Route-IP-No 0
+VALUE Ascend-Route-IP Route-IP-Yes 1
+VALUE Ascend-Route-IPX Route-IPX-No 0
+VALUE Ascend-Route-IPX Route-IPX-Yes 1
+VALUE Ascend-Bridge Bridge-No 0
+VALUE Ascend-Bridge Bridge-Yes 1
+VALUE Ascend-TS-Idle-Mode TS-Idle-None 0
+VALUE Ascend-TS-Idle-Mode TS-Idle-Input 1
+VALUE Ascend-TS-Idle-Mode TS-Idle-Input-Output 2
+
+VALUE Ascend-Send-Auth Send-Auth-None 0
+VALUE Ascend-Send-Auth Send-Auth-PAP 1
+VALUE Ascend-Send-Auth Send-Auth-CHAP 2
+VALUE Ascend-Send-Auth Send-Auth-MS-CHAP 3
+
+VALUE Ascend-Link-Compression Link-Comp-None 0
+VALUE Ascend-Link-Compression Link-Comp-Stac 1
+VALUE Ascend-Link-Compression Link-Comp-Stac-Draft-9 2
+VALUE Ascend-Link-Compression Link-Comp-MS-Stac 3
+VALUE Ascend-History-Weigh-Type History-Constant 0
+VALUE Ascend-History-Weigh-Type History-Linear 1
+VALUE Ascend-History-Weigh-Type History-Quadratic 2
+VALUE Ascend-Callback Callback-No 0
+VALUE Ascend-Callback Callback-Yes 1
+VALUE Ascend-Expect-Callback Expect-Callback-No 0
+VALUE Ascend-Expect-Callback Expect-Callback-Yes 1
+VALUE Ascend-Data-Svc Switched-Voice-Bearer 0
+VALUE Ascend-Data-Svc Nailed-56KR 1
+VALUE Ascend-Data-Svc Nailed-64K 2
+VALUE Ascend-Data-Svc Switched-64KR 3
+VALUE Ascend-Data-Svc Switched-56K 4
+VALUE Ascend-Data-Svc Switched-384KR 5
+VALUE Ascend-Data-Svc Switched-384K 6
+VALUE Ascend-Data-Svc Switched-1536K 7
+VALUE Ascend-Data-Svc Switched-1536KR 8
+VALUE Ascend-Data-Svc Switched-128K 9
+VALUE Ascend-Data-Svc Switched-192K 10
+VALUE Ascend-Data-Svc Switched-256K 11
+VALUE Ascend-Data-Svc Switched-320K 12
+VALUE Ascend-Data-Svc Switched-384K-MR 13
+VALUE Ascend-Data-Svc Switched-448K 14
+VALUE Ascend-Data-Svc Switched-512K 15
+VALUE Ascend-Data-Svc Switched-576K 16
+VALUE Ascend-Data-Svc Switched-640K 17
+VALUE Ascend-Data-Svc Switched-704K 18
+VALUE Ascend-Data-Svc Switched-768K 19
+VALUE Ascend-Data-Svc Switched-832K 20
+VALUE Ascend-Data-Svc Switched-896K 21
+VALUE Ascend-Data-Svc Switched-960K 22
+VALUE Ascend-Data-Svc Switched-1024K 23
+VALUE Ascend-Data-Svc Switched-1088K 24
+VALUE Ascend-Data-Svc Switched-1152K 25
+VALUE Ascend-Data-Svc Switched-1216K 26
+VALUE Ascend-Data-Svc Switched-1280K 27
+VALUE Ascend-Data-Svc Switched-1344K 28
+VALUE Ascend-Data-Svc Switched-1408K 29
+VALUE Ascend-Data-Svc Switched-1472K 30
+VALUE Ascend-Data-Svc Switched-1600K 31
+VALUE Ascend-Data-Svc Switched-1664K 32
+VALUE Ascend-Data-Svc Switched-1728K 33
+VALUE Ascend-Data-Svc Switched-1792K 34
+VALUE Ascend-Data-Svc Switched-1856K 35
+VALUE Ascend-Data-Svc Switched-1920K 36
+VALUE Ascend-Data-Svc Switched-inherited 37
+VALUE Ascend-Data-Svc Switched-restricted-bearer-x30 38
+VALUE Ascend-Data-Svc Switched-clear-bearer-v110 39
+VALUE Ascend-Data-Svc Switched-restricted-64-x30 40
+VALUE Ascend-Data-Svc Switched-clear-56-v110 41
+VALUE Ascend-Data-Svc Switched-modem 42
+VALUE Ascend-Data-Svc Switched-atmodem 43
+VALUE Ascend-Data-Svc Switched-V110-24-56 45
+VALUE Ascend-Data-Svc Switched-V110-48-56 46
+VALUE Ascend-Data-Svc Switched-V110-96-56 47
+VALUE Ascend-Data-Svc Switched-V110-192-56 48
+VALUE Ascend-Data-Svc Switched-V110-384-56 49
+VALUE Ascend-Data-Svc Switched-V110-24-56R 50
+VALUE Ascend-Data-Svc Switched-V110-48-56R 51
+VALUE Ascend-Data-Svc Switched-V110-96-56R 52
+VALUE Ascend-Data-Svc Switched-V110-192-56R 53
+VALUE Ascend-Data-Svc Switched-V110-384-56R 54
+VALUE Ascend-Data-Svc Switched-V110-24-64 55
+VALUE Ascend-Data-Svc Switched-V110-48-64 56
+VALUE Ascend-Data-Svc Switched-V110-96-64 57
+VALUE Ascend-Data-Svc Switched-V110-192-64 58
+VALUE Ascend-Data-Svc Switched-V110-384-64 59
+VALUE Ascend-Data-Svc Switched-V110-24-64R 60
+VALUE Ascend-Data-Svc Switched-V110-48-64R 61
+VALUE Ascend-Data-Svc Switched-V110-96-64R 62
+VALUE Ascend-Data-Svc Switched-V110-384-64R 64
+VALUE Ascend-Data-Svc Switched-V110-192-64R 63
+
+VALUE Ascend-Data-Svc Switched-Pots 68
+VALUE Ascend-Data-Svc Switched-ATM 69
+VALUE Ascend-Data-Svc Switched-FR 70
+
+VALUE Ascend-Force-56 Force-56-No 0
+VALUE Ascend-Force-56 Force-56-Yes 1
+VALUE Ascend-PW-Lifetime Lifetime-In-Days 0
+VALUE Ascend-PW-Warntime Days-Of-Warning 0
+VALUE Ascend-PPP-VJ-1172 PPP-VJ-1172 1
+VALUE Ascend-PPP-VJ-Slot-Comp VJ-Slot-Comp-No 1
+VALUE Ascend-Require-Auth Not-Require-Auth 0
+VALUE Ascend-Require-Auth Require-Auth 1
+VALUE Ascend-Token-Immediate Tok-Imm-No 0
+VALUE Ascend-Token-Immediate Tok-Imm-Yes 1
+VALUE Ascend-DBA-Monitor DBA-Transmit 0
+VALUE Ascend-DBA-Monitor DBA-Transmit-Recv 1
+VALUE Ascend-DBA-Monitor DBA-None 2
+VALUE Ascend-FR-Type Ascend-FR-DTE 0
+VALUE Ascend-FR-Type Ascend-FR-DCE 1
+VALUE Ascend-FR-Type Ascend-FR-NNI 2
+VALUE Ascend-FR-Link-Mgt Ascend-FR-No-Link-Mgt 0
+VALUE Ascend-FR-Link-Mgt Ascend-FR-T1-617D 1
+VALUE Ascend-FR-Link-Mgt Ascend-FR-Q-933A 2
+VALUE Ascend-FR-LinkUp Ascend-LinkUp-Default 0
+VALUE Ascend-FR-LinkUp Ascend-LinkUp-AlwaysUp 1
+VALUE Ascend-Multicast-Client Multicast-No 0
+VALUE Ascend-Multicast-Client Multicast-Yes 1
+VALUE Ascend-User-Acct-Type Ascend-User-Acct-None 0
+VALUE Ascend-User-Acct-Type Ascend-User-Acct-User 1
+VALUE Ascend-User-Acct-Type Ascend-User-Acct-User-Default 2
+VALUE Ascend-User-Acct-Base Base-10 0
+VALUE Ascend-User-Acct-Base Base-16 1
+VALUE Ascend-DHCP-Reply DHCP-Reply-No 0
+VALUE Ascend-DHCP-Reply DHCP-Reply-Yes 1
+VALUE Ascend-Client-Assign-DNS DNS-Assign-No 0
+VALUE Ascend-Client-Assign-DNS DNS-Assign-Yes 1
+VALUE Ascend-Event-Type Ascend-ColdStart 1
+VALUE Ascend-Event-Type Ascend-Session-Event 2
+VALUE Ascend-BACP-Enable BACP-No 0
+VALUE Ascend-BACP-Enable BACP-Yes 1
+
+VALUE Ascend-Dialout-Allowed Dialout-Not-Allowed 0
+VALUE Ascend-Dialout-Allowed Dialout-Allowed 1
+
+VALUE Ascend-Shared-Profile-Enable Shared-Profile-No 0
+VALUE Ascend-Shared-Profile-Enable Shared-Profile-Yes 1
+
+VALUE Ascend-Temporary-Rtes Temp-Rtes-No 0
+VALUE Ascend-Temporary-Rtes Temp-Rtes-Yes 1
+
+# Ascend Disconnect Cause Values
+
+VALUE Ascend-Disconnect-Cause No-Reason 0
+VALUE Ascend-Disconnect-Cause Not-Applicable 1
+VALUE Ascend-Disconnect-Cause Unknown 2
+VALUE Ascend-Disconnect-Cause Call-Disconnected 3
+VALUE Ascend-Disconnect-Cause CLID-Authentication-Failed 4
+VALUE Ascend-Disconnect-Cause CLID-RADIUS-Timeout 5
+
+VALUE Ascend-Disconnect-Cause Modem-No-DCD 10
+VALUE Ascend-Disconnect-Cause DCD-Detected-Then-Inactive 11
+VALUE Ascend-Disconnect-Cause Modem-Invalid-Result-Codes 12
+
+VALUE Ascend-Disconnect-Cause TermSrv-User-Quit 20
+VALUE Ascend-Disconnect-Cause TermSrv-Idle-Timeout 21
+VALUE Ascend-Disconnect-Cause TermSrv-Exit-Telnet 22
+VALUE Ascend-Disconnect-Cause TermSrv-No-IPaddr 23
+VALUE Ascend-Disconnect-Cause TermSrv-Exit-Raw-TCP 24
+VALUE Ascend-Disconnect-Cause TermSrv-Exit-Login-Failed 25
+VALUE Ascend-Disconnect-Cause TermSrv-Exit-Raw-TCP-Disabled 26
+VALUE Ascend-Disconnect-Cause TermSrv-CTRL-C-In-Login 27
+VALUE Ascend-Disconnect-Cause TermSrv-Destroyed 28
+VALUE Ascend-Disconnect-Cause TermSrv-User-Closed-VCon 29
+
+VALUE Ascend-Disconnect-Cause TermSrv-VCon-Destroyed 30
+VALUE Ascend-Disconnect-Cause TermSrv-Exit-Rlogin 31
+VALUE Ascend-Disconnect-Cause TermSrv-Bad-Rlogin-Option 32
+VALUE Ascend-Disconnect-Cause TermSrv-Not-Enough-Resources 33
+
+VALUE Ascend-Disconnect-Cause MPP-No-NULL-Msg-Timeout 35
+
+VALUE Ascend-Disconnect-Cause PPP-LCP-Timeout 40
+VALUE Ascend-Disconnect-Cause PPP-LCP-Negotion-Failed 41
+VALUE Ascend-Disconnect-Cause PPP-PAP-Auth-Failed 42
+VALUE Ascend-Disconnect-Cause PPP-CHAP-Auth-Failed 43
+VALUE Ascend-Disconnect-Cause PPP-Rmt-Auth-Failed 44
+VALUE Ascend-Disconnect-Cause PPP-Rcv-Terminate-Req 45
+VALUE Ascend-Disconnect-Cause PPP-Rcv-Close-Event 46
+VALUE Ascend-Disconnect-Cause PPP-No-NCPs-Open 47
+VALUE Ascend-Disconnect-Cause PPP-MP-Bundle-Unknown 48
+VALUE Ascend-Disconnect-Cause PPP-LCP-Close-MP-Add-Fail 49
+
+VALUE Ascend-Disconnect-Cause Session-Table-Full 50
+VALUE Ascend-Disconnect-Cause Out-Of-Resources 51
+VALUE Ascend-Disconnect-Cause Invalid-IP-Address 52
+VALUE Ascend-Disconnect-Cause Hostname-Resolution-Failed 53
+VALUE Ascend-Disconnect-Cause Bad-Or-Missing-Port-Number 54
+
+VALUE Ascend-Disconnect-Cause Host-Reset 60
+VALUE Ascend-Disconnect-Cause Connection-Refused 61
+VALUE Ascend-Disconnect-Cause Connection-Timeout 62
+VALUE Ascend-Disconnect-Cause Connection-Closed 63
+VALUE Ascend-Disconnect-Cause Network-Unreachable 64
+VALUE Ascend-Disconnect-Cause Host-Unreachable 65
+VALUE Ascend-Disconnect-Cause Network-Unreachable-Admin 66
+VALUE Ascend-Disconnect-Cause Host-Unreachable-Admin 67
+VALUE Ascend-Disconnect-Cause Port-Unreachable 68
+
+VALUE Ascend-Disconnect-Cause Session-Timeout 100
+VALUE Ascend-Disconnect-Cause Invalid-Incoming-User 101
+VALUE Ascend-Disconnect-Cause Disconnect-Due-To-Callback 102
+
+VALUE Ascend-Disconnect-Cause Proto-Disabled-Or-Unsupported 120
+
+VALUE Ascend-Disconnect-Cause Disconnect-Req-By-RADIUS 150
+VALUE Ascend-Disconnect-Cause Disconnect-Req-By-Local-Admin 151
+
+VALUE Ascend-Disconnect-Cause V110-Timeout-Sync-Retry-Exceed 160
+
+VALUE Ascend-Disconnect-Cause PPP-Auth-Timeout-Exceeded 170
+VALUE Ascend-Disconnect-Cause User-Executed-Do-Hangup 180
+VALUE Ascend-Disconnect-Cause Remote-End-Hung-Up 185
+VALUE Ascend-Disconnect-Cause Resource-Has-Been-Quiesced 190
+VALUE Ascend-Disconnect-Cause Max-Call-Duration-Reached 195
+
+# ascend connect progress codes
+VALUE Ascend-Connect-Progress No-Progress 0
+VALUE Ascend-Connect-Progress Call-Up 10
+VALUE Ascend-Connect-Progress Modem-Up 30
+VALUE Ascend-Connect-Progress Modem-Awaiting-DCD 31
+VALUE Ascend-Connect-Progress Modem-Awaiting-Codes 32
+VALUE Ascend-Connect-Progress TermSrv-Started 40
+VALUE Ascend-Connect-Progress TermSrv-Raw-TCP-Started 41
+VALUE Ascend-Connect-Progress TermSrv-Telnet-Started 42
+VALUE Ascend-Connect-Progress TermSrv-Raw-TCP-Connected 43
+VALUE Ascend-Connect-Progress TermSrv-Telnet-Connected 44
+VALUE Ascend-Connect-Progress TermSrv-Rlogin-Started 45
+VALUE Ascend-Connect-Progress TermSrv-Rlogin-Connected 46
+VALUE Ascend-Connect-Progress Modem-Outdial-Call-Up 50
+VALUE Ascend-Connect-Progress LAN-Session-Up 60
+VALUE Ascend-Connect-Progress LCP-Opening 61
+VALUE Ascend-Connect-Progress CCP-Opening 62
+VALUE Ascend-Connect-Progress IPNCP-Opening 63
+VALUE Ascend-Connect-Progress BNCP-Opening 64
+VALUE Ascend-Connect-Progress LCP-Opened 65
+VALUE Ascend-Connect-Progress CCP-Opened 66
+VALUE Ascend-Connect-Progress IPNCP-Opened 67
+VALUE Ascend-Connect-Progress BNCP-Opened 68
+VALUE Ascend-Connect-Progress LCP-State-Initial 69
+VALUE Ascend-Connect-Progress LCP-State-Starting 70
+VALUE Ascend-Connect-Progress LCP-State-Closed 71
+VALUE Ascend-Connect-Progress LCP-State-Stopped 72
+VALUE Ascend-Connect-Progress LCP-State-Closing 73
+VALUE Ascend-Connect-Progress LCP-State-Stopping 74
+VALUE Ascend-Connect-Progress LCP-State-Request-Sent 75
+VALUE Ascend-Connect-Progress LCP-State-Ack-Received 76
+VALUE Ascend-Connect-Progress LCP-State-Ack-Sent 77
+VALUE Ascend-Connect-Progress IPXNCP-Opened 80
+VALUE Ascend-Connect-Progress ATNCP-Opened 81
+VALUE Ascend-Connect-Progress BACP-Opening 82
+VALUE Ascend-Connect-Progress BACP-Opened 83
+VALUE Ascend-Connect-Progress V110-Up 90
+VALUE Ascend-Connect-Progress V110-State-Opened 91
+VALUE Ascend-Connect-Progress V110-State-Carrier 92
+VALUE Ascend-Connect-Progress V110-State-Reset 93
+VALUE Ascend-Connect-Progress V110-State-Closed 94
+VALUE Ascend-ATM-Direct ATM-Direct-No 0
+VALUE Ascend-ATM-Direct ATM-Direct-Yes 1
+VALUE Ascend-ATM-Fault-Management VC-End-To-End-Loopback 2
+VALUE Ascend-ATM-Fault-Management VC-No-Loopback 0
+VALUE Ascend-ATM-Fault-Management VC-Segment-Loopback 1
+VALUE Ascend-Appletalk-Peer-Mode Appletalk-Peer-Dialin 1
+VALUE Ascend-Appletalk-Peer-Mode Appletalk-Peer-Router 0
+VALUE Ascend-Auth-Type Auth-Any 2
+VALUE Ascend-Auth-Type Auth-CHAP 4
+VALUE Ascend-Auth-Type Auth-Default 1
+VALUE Ascend-Auth-Type Auth-MS-CHAP 5
+VALUE Ascend-Auth-Type Auth-None 0
+VALUE Ascend-Auth-Type Auth-PAP 3
+VALUE Ascend-BIR-Enable BIR-Enable-No 0
+VALUE Ascend-BIR-Enable BIR-Enable-Yes 1
+VALUE Ascend-BIR-Proxy BIR-Proxy-No 0
+VALUE Ascend-BIR-Proxy BIR-Proxy-Yes 1
+VALUE Ascend-Bi-Directional-Auth Bi-Directional-Auth-Allowed 1
+VALUE Ascend-Bi-Directional-Auth Bi-Directional-Auth-None 0
+VALUE Ascend-Bi-Directional-Auth Bi-Directional-Auth-Required 2
+VALUE Ascend-Bridge-Non-PPPoE Bridge-Non-PPPoE-No 0
+VALUE Ascend-Bridge-Non-PPPoE Bridge-Non-PPPoE-Yes 1
+VALUE Ascend-Cache-Refresh Refresh-No 0
+VALUE Ascend-Cache-Refresh Refresh-Yes 1
+VALUE Ascend-Call-Direction Ascend-Call-Direction-Incoming 0
+VALUE Ascend-Call-Direction Ascend-Call-Direction-Outgoing 1
+VALUE Ascend-Calling-Id-Number-Plan Data 3
+VALUE Ascend-Calling-Id-Number-Plan ISDN-Telephony 1
+VALUE Ascend-Calling-Id-Number-Plan National 8
+VALUE Ascend-Calling-Id-Number-Plan Private 9
+VALUE Ascend-Calling-Id-Number-Plan Telex 4
+VALUE Ascend-Calling-Id-Number-Plan Unknown 0
+VALUE Ascend-Calling-Id-Presentatn Allowed 0
+VALUE Ascend-Calling-Id-Presentatn Number-Not-Available 2
+VALUE Ascend-Calling-Id-Presentatn Restricted 1
+VALUE Ascend-Calling-Id-Screening Network-Provided 3
+VALUE Ascend-Calling-Id-Screening User-Not-Screened 0
+VALUE Ascend-Calling-Id-Screening User-Provided-Failed 2
+VALUE Ascend-Calling-Id-Screening User-Provided-Passed 1
+VALUE Ascend-Calling-Id-Type-Of-Num Abbreviated-Number 6
+VALUE Ascend-Calling-Id-Type-Of-Num International-Number 1
+VALUE Ascend-Calling-Id-Type-Of-Num National-Number 2
+VALUE Ascend-Calling-Id-Type-Of-Num Network-Specific 3
+VALUE Ascend-Calling-Id-Type-Of-Num Subscriber-Number 4
+VALUE Ascend-Calling-Id-Type-Of-Num Unknown 0
+VALUE Ascend-Ckt-Type Ascend-PVC 0
+VALUE Ascend-Ckt-Type Ascend-SVC 1
+VALUE Ascend-Client-Assign-WINS WINS-Assign-No 0
+VALUE Ascend-Client-Assign-WINS WINS-Assign-Yes 1
+
+VALUE Ascend-Dsl-Downstream-Limit adslcap-dn-1280000 10
+VALUE Ascend-Dsl-Downstream-Limit adslcap-dn-1600000 9
+VALUE Ascend-Dsl-Downstream-Limit adslcap-dn-1920000 8
+VALUE Ascend-Dsl-Downstream-Limit adslcap-dn-2240000 7
+VALUE Ascend-Dsl-Downstream-Limit adslcap-dn-2560000 6
+VALUE Ascend-Dsl-Downstream-Limit adslcap-dn-2688000 5
+VALUE Ascend-Dsl-Downstream-Limit adslcap-dn-3200000 4
+VALUE Ascend-Dsl-Downstream-Limit adslcap-dn-4480000 3
+VALUE Ascend-Dsl-Downstream-Limit adslcap-dn-5120000 2
+VALUE Ascend-Dsl-Downstream-Limit adslcap-dn-6272000 1
+VALUE Ascend-Dsl-Downstream-Limit adslcap-dn-640000 12
+VALUE Ascend-Dsl-Downstream-Limit adslcap-dn-7168000 0
+VALUE Ascend-Dsl-Downstream-Limit adslcap-dn-960000 11
+VALUE Ascend-Dsl-Downstream-Limit adsldmt-dn-128000 121
+VALUE Ascend-Dsl-Downstream-Limit adsldmt-dn-1280000 114
+VALUE Ascend-Dsl-Downstream-Limit adsldmt-dn-1600000 113
+VALUE Ascend-Dsl-Downstream-Limit adsldmt-dn-1920000 112
+VALUE Ascend-Dsl-Downstream-Limit adsldmt-dn-2240000 111
+VALUE Ascend-Dsl-Downstream-Limit adsldmt-dn-256000 120
+VALUE Ascend-Dsl-Downstream-Limit adsldmt-dn-2560000 110
+VALUE Ascend-Dsl-Downstream-Limit adsldmt-dn-2688000 109
+VALUE Ascend-Dsl-Downstream-Limit adsldmt-dn-3200000 108
+VALUE Ascend-Dsl-Downstream-Limit adsldmt-dn-384000 119
+VALUE Ascend-Dsl-Downstream-Limit adsldmt-dn-4480000 107
+VALUE Ascend-Dsl-Downstream-Limit adsldmt-dn-512000 118
+VALUE Ascend-Dsl-Downstream-Limit adsldmt-dn-5120000 106
+VALUE Ascend-Dsl-Downstream-Limit adsldmt-dn-6272000 105
+VALUE Ascend-Dsl-Downstream-Limit adsldmt-dn-640000 117
+VALUE Ascend-Dsl-Downstream-Limit adsldmt-dn-7168000 104
+VALUE Ascend-Dsl-Downstream-Limit adsldmt-dn-768000 116
+VALUE Ascend-Dsl-Downstream-Limit adsldmt-dn-8000000 103
+VALUE Ascend-Dsl-Downstream-Limit adsldmt-dn-8960000 102
+VALUE Ascend-Dsl-Downstream-Limit adsldmt-dn-9504000 101
+VALUE Ascend-Dsl-Downstream-Limit adsldmt-dn-960000 115
+VALUE Ascend-Dsl-Downstream-Limit adsldmt-dn-auto 100
+VALUE Ascend-Dsl-Rate-Mode Rate-Mode-AutoBaud 1
+VALUE Ascend-Dsl-Rate-Mode Rate-Mode-Single 2
+VALUE Ascend-Dsl-Rate-Type Rate-Type-AdslCap 2
+VALUE Ascend-Dsl-Rate-Type Rate-Type-AdslDmt 4
+VALUE Ascend-Dsl-Rate-Type Rate-Type-AdslDmtCell 3
+VALUE Ascend-Dsl-Rate-Type Rate-Type-Disabled 0
+VALUE Ascend-Dsl-Rate-Type Rate-Type-Sdsl 1
+VALUE Ascend-Dsl-Upstream-Limit adsldmt-up-896000 153
+VALUE Ascend-Dsl-Upstream-Limit adslcap-up-1088000 50
+VALUE Ascend-Dsl-Upstream-Limit adslcap-up-272000 56
+VALUE Ascend-Dsl-Upstream-Limit adslcap-up-408000 55
+VALUE Ascend-Dsl-Upstream-Limit adslcap-up-544000 54
+VALUE Ascend-Dsl-Upstream-Limit adslcap-up-680000 53
+VALUE Ascend-Dsl-Upstream-Limit adslcap-up-816000 52
+VALUE Ascend-Dsl-Upstream-Limit adslcap-up-952000 51
+VALUE Ascend-Dsl-Upstream-Limit adsldmt-up-1088000 151
+VALUE Ascend-Dsl-Upstream-Limit adsldmt-up-128000 160
+VALUE Ascend-Dsl-Upstream-Limit adsldmt-up-256000 159
+VALUE Ascend-Dsl-Upstream-Limit adsldmt-up-384000 158
+VALUE Ascend-Dsl-Upstream-Limit adsldmt-up-512000 157
+VALUE Ascend-Dsl-Upstream-Limit adsldmt-up-640000 156
+VALUE Ascend-Dsl-Upstream-Limit adsldmt-up-768000 155
+VALUE Ascend-Dsl-Upstream-Limit adsldmt-up-800000 154
+VALUE Ascend-Dsl-Upstream-Limit adsldmt-up-928000 152
+VALUE Ascend-Dsl-Upstream-Limit adsldmt-up-auto 150
+VALUE Ascend-Dsl-Upstream-Limit sdsl-1168000 5
+VALUE Ascend-Dsl-Upstream-Limit sdsl-144000 0
+VALUE Ascend-Dsl-Upstream-Limit sdsl-1552000 6
+VALUE Ascend-Dsl-Upstream-Limit sdsl-2320000 7
+VALUE Ascend-Dsl-Upstream-Limit sdsl-272000 1
+VALUE Ascend-Dsl-Upstream-Limit sdsl-400000 2
+VALUE Ascend-Dsl-Upstream-Limit sdsl-528000 3
+VALUE Ascend-Dsl-Upstream-Limit sdsl-784000 4
+VALUE Ascend-FR-Link-Status-DLCI Ascend-FR-LMI-Dlci-0 0
+VALUE Ascend-FR-Link-Status-DLCI Ascend-FR-LMI-Dlci-1023 1023
+VALUE Ascend-Filter-Required Required-No 0
+VALUE Ascend-Filter-Required Required-Yes 1
+VALUE Ascend-IP-Pool-Chaining IP-Pool-Chaining-No 0
+VALUE Ascend-IP-Pool-Chaining IP-Pool-Chaining-Yes 1
+VALUE Ascend-IP-TOS IP-TOS-Cost 2
+VALUE Ascend-IP-TOS IP-TOS-Disabled 1
+VALUE Ascend-IP-TOS IP-TOS-Latency 16
+VALUE Ascend-IP-TOS IP-TOS-Normal 0
+VALUE Ascend-IP-TOS IP-TOS-Reliability 4
+VALUE Ascend-IP-TOS IP-TOS-Throughput 8
+VALUE Ascend-IP-TOS-Apply-To IP-TOS-Apply-To-Both 3072
+VALUE Ascend-IP-TOS-Apply-To IP-TOS-Apply-To-Incoming 1024
+VALUE Ascend-IP-TOS-Apply-To IP-TOS-Apply-To-Outgoing 2048
+VALUE Ascend-IP-TOS-Precedence IP-TOS-Precedence-Pri-Five 160
+VALUE Ascend-IP-TOS-Precedence IP-TOS-Precedence-Pri-Four 128
+VALUE Ascend-IP-TOS-Precedence IP-TOS-Precedence-Pri-Normal 0
+VALUE Ascend-IP-TOS-Precedence IP-TOS-Precedence-Pri-One 32
+VALUE Ascend-IP-TOS-Precedence IP-TOS-Precedence-Pri-Seven 224
+VALUE Ascend-IP-TOS-Precedence IP-TOS-Precedence-Pri-Six 192
+VALUE Ascend-IP-TOS-Precedence IP-TOS-Precedence-Pri-Three 96
+VALUE Ascend-IP-TOS-Precedence IP-TOS-Precedence-Pri-Two 64
+VALUE Ascend-IPX-Header-Compression IPX-Header-Compression-No 0
+VALUE Ascend-IPX-Header-Compression IPX-Header-Compression-Yes 1
+VALUE Ascend-NAS-Port-Format 1_2_2 3
+VALUE Ascend-NAS-Port-Format 2_4_5_5 2
+VALUE Ascend-NAS-Port-Format 2_4_6_4 1
+VALUE Ascend-NAS-Port-Format Unknown 0
+VALUE Ascend-Numbering-Plan-ID ISDN-Numbering-Plan 1
+VALUE Ascend-Numbering-Plan-ID Private-Numbering-Plan 9
+VALUE Ascend-Numbering-Plan-ID Unknown-Numbering-Plan 0
+VALUE Ascend-PPPoE-Enable PPPoE-No 0
+VALUE Ascend-PPPoE-Enable PPPoE-Yes 1
+VALUE Ascend-Port-Redir-Protocol Ascend-Proto-TCP 6
+VALUE Ascend-Port-Redir-Protocol Ascend-Proto-UDP 17
+VALUE Ascend-Private-Route-Required Required-No 0
+VALUE Ascend-Private-Route-Required Required-Yes 1
+VALUE Ascend-Route-Appletalk Route-Appletalk-No 0
+VALUE Ascend-Route-Appletalk Route-Appletalk-Yes 1
+VALUE Ascend-SVC-Enabled Ascend-SVC-Enabled-No 0
+VALUE Ascend-SVC-Enabled Ascend-SVC-Enabled-Yes 1
+
+VALUE Ascend-Service-Type Ascend-Service-Type-ATM 20
+VALUE Ascend-Service-Type Ascend-Service-Type-Combinet 7
+VALUE Ascend-Service-Type Ascend-Service-Type-EuRaw 9
+VALUE Ascend-Service-Type Ascend-Service-Type-EuUi 10
+VALUE Ascend-Service-Type Ascend-Service-Type-FR 8
+VALUE Ascend-Service-Type Ascend-Service-Type-HdlcNrm 21
+VALUE Ascend-Service-Type Ascend-Service-Type-IpFax 19
+VALUE Ascend-Service-Type Ascend-Service-Type-MP 15
+VALUE Ascend-Service-Type Ascend-Service-Type-MPP 5
+VALUE Ascend-Service-Type Ascend-Service-Type-NetToNet 25
+VALUE Ascend-Service-Type Ascend-Service-Type-None 1
+VALUE Ascend-Service-Type Ascend-Service-Type-NotUsed 0
+VALUE Ascend-Service-Type Ascend-Service-Type-Other 2
+VALUE Ascend-Service-Type Ascend-Service-Type-PPP 3
+VALUE Ascend-Service-Type Ascend-Service-Type-PseuTunPPP 18
+VALUE Ascend-Service-Type Ascend-Service-Type-RawTcp 13
+VALUE Ascend-Service-Type Ascend-Service-Type-Slip 4
+VALUE Ascend-Service-Type Ascend-Service-Type-Telnet 11
+VALUE Ascend-Service-Type Ascend-Service-Type-TelnetBin 12
+VALUE Ascend-Service-Type Ascend-Service-Type-TermServer 14
+VALUE Ascend-Service-Type Ascend-Service-Type-VirtualConn 16
+VALUE Ascend-Service-Type Ascend-Service-Type-Visa2 23
+VALUE Ascend-Service-Type Ascend-Service-Type-VoIp 22
+VALUE Ascend-Service-Type Ascend-Service-Type-X25 6
+VALUE Ascend-Service-Type Ascend-Service-Type-X25DChan 17
+VALUE Ascend-Session-Type Ascend-Session-G711-Alaw 3
+VALUE Ascend-Session-Type Ascend-Session-G711-Ulaw 2
+VALUE Ascend-Session-Type Ascend-Session-G723 4
+VALUE Ascend-Session-Type Ascend-Session-G723-64KPS 6
+VALUE Ascend-Session-Type Ascend-Session-G728 7
+VALUE Ascend-Session-Type Ascend-Session-G729 5
+VALUE Ascend-Session-Type Ascend-Session-RT24 8
+VALUE Ascend-Session-Type Ascend-Session-Unknown 1
+VALUE Ascend-Session-Type Ascend-Session-Unused 0
+
+VALUE Ascend-Tunneling-Protocol ATMP-Tunnel 0
+VALUE Ascend-Tunneling-Protocol VTP-Tunnel 1
+
+VALUE Ascend-X25-Pad-X3-Profile CC_SSP 4
+VALUE Ascend-X25-Pad-X3-Profile CC_TSP 5
+VALUE Ascend-X25-Pad-X3-Profile CRT 0
+VALUE Ascend-X25-Pad-X3-Profile CUSTOM 11
+VALUE Ascend-X25-Pad-X3-Profile DEFAULT 2
+VALUE Ascend-X25-Pad-X3-Profile HARDCOPY 6
+VALUE Ascend-X25-Pad-X3-Profile HDX 7
+VALUE Ascend-X25-Pad-X3-Profile INFONET 1
+VALUE Ascend-X25-Pad-X3-Profile NULL 10
+VALUE Ascend-X25-Pad-X3-Profile POS 9
+VALUE Ascend-X25-Pad-X3-Profile SCEN 3
+VALUE Ascend-X25-Pad-X3-Profile SHARK 8
+VALUE Ascend-X25-Reverse-Charging Reverse-Charging-No 0
+VALUE Ascend-X25-Reverse-Charging Reverse-Charging-Yes 1
+END-VENDOR Ascend
diff --git a/share/dictionary.ascend.illegal b/share/dictionary.ascend.illegal
new file mode 100644
index 0000000..b741c1f
--- /dev/null
+++ b/share/dictionary.ascend.illegal
@@ -0,0 +1,432 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Ascend dictionary that illegally uses the RFC space.
+#
+# $Id$
+#
+##############################################################################
+#
+# Ascend specific extensions
+# Used by ASCEND MAX/Pipeline products
+#
+# This next block is renamed because they share the same
+# names as the vendor-specific attributes, BUT they occur
+# in the lower (1-255) RADIUS attribute space.
+#
+# Older Ascend software will send these, rather than the
+# vendor specific attributes.
+#
+ATTRIBUTE X-Ascend-FCP-Parameter 119 string
+ATTRIBUTE X-Ascend-Modem-PortNo 120 integer
+ATTRIBUTE X-Ascend-Modem-SlotNo 121 integer
+ATTRIBUTE X-Ascend-Modem-ShelfNo 122 integer
+ATTRIBUTE X-Ascend-Call-Attempt-Limit 123 integer
+ATTRIBUTE X-Ascend-Call-Block-Duration 124 integer
+ATTRIBUTE X-Ascend-Maximum-Call-Duration 125 integer
+ATTRIBUTE X-Ascend-Temporary-Rtes 126 integer
+ATTRIBUTE X-Ascend-Tunneling-Protocol 127 integer
+ATTRIBUTE X-Ascend-Shared-Profile-Enable 128 integer
+ATTRIBUTE X-Ascend-Primary-Home-Agent 129 string
+ATTRIBUTE X-Ascend-Secondary-Home-Agent 130 string
+ATTRIBUTE X-Ascend-Dialout-Allowed 131 integer
+ATTRIBUTE X-Ascend-Client-Gateway 132 ipaddr
+ATTRIBUTE X-Ascend-BACP-Enable 133 integer
+ATTRIBUTE X-Ascend-DHCP-Maximum-Leases 134 integer
+ATTRIBUTE X-Ascend-Client-Primary-DNS 135 ipaddr
+ATTRIBUTE X-Ascend-Client-Secondary-DNS 136 ipaddr
+ATTRIBUTE X-Ascend-Client-Assign-DNS 137 integer
+ATTRIBUTE X-Ascend-User-Acct-Type 138 integer
+ATTRIBUTE X-Ascend-User-Acct-Host 139 ipaddr
+ATTRIBUTE X-Ascend-User-Acct-Port 140 integer
+ATTRIBUTE X-Ascend-User-Acct-Key 141 string
+ATTRIBUTE X-Ascend-User-Acct-Base 142 integer
+ATTRIBUTE X-Ascend-User-Acct-Time 143 integer
+ATTRIBUTE X-Ascend-Assign-IP-Client 144 ipaddr
+ATTRIBUTE X-Ascend-Assign-IP-Server 145 ipaddr
+ATTRIBUTE X-Ascend-Assign-IP-Global-Pool 146 string
+ATTRIBUTE X-Ascend-DHCP-Reply 147 integer
+ATTRIBUTE X-Ascend-DHCP-Pool-Number 148 integer
+ATTRIBUTE X-Ascend-Expect-Callback 149 integer
+ATTRIBUTE X-Ascend-Event-Type 150 integer
+ATTRIBUTE X-Ascend-Session-Svr-Key 151 string
+ATTRIBUTE X-Ascend-Multicast-Rate-Limit 152 integer
+ATTRIBUTE X-Ascend-IF-Netmask 153 ipaddr
+ATTRIBUTE X-Ascend-Remote-Addr 154 ipaddr
+ATTRIBUTE X-Ascend-Multicast-Client 155 integer
+ATTRIBUTE X-Ascend-FR-Circuit-Name 156 string
+ATTRIBUTE X-Ascend-FR-LinkUp 157 integer
+ATTRIBUTE X-Ascend-FR-Nailed-Grp 158 integer
+ATTRIBUTE X-Ascend-FR-Type 159 integer
+ATTRIBUTE X-Ascend-FR-Link-Mgt 160 integer
+ATTRIBUTE X-Ascend-FR-N391 161 integer
+ATTRIBUTE X-Ascend-FR-DCE-N392 162 integer
+ATTRIBUTE X-Ascend-FR-DTE-N392 163 integer
+ATTRIBUTE X-Ascend-FR-DCE-N393 164 integer
+ATTRIBUTE X-Ascend-FR-DTE-N393 165 integer
+ATTRIBUTE X-Ascend-FR-T391 166 integer
+ATTRIBUTE X-Ascend-FR-T392 167 integer
+ATTRIBUTE X-Ascend-Bridge-Address 168 string
+ATTRIBUTE X-Ascend-TS-Idle-Limit 169 integer
+ATTRIBUTE X-Ascend-TS-Idle-Mode 170 integer
+ATTRIBUTE X-Ascend-DBA-Monitor 171 integer
+ATTRIBUTE X-Ascend-Base-Channel-Count 172 integer
+ATTRIBUTE X-Ascend-Minimum-Channels 173 integer
+ATTRIBUTE X-Ascend-IPX-Route 174 string
+ATTRIBUTE X-Ascend-FT1-Caller 175 integer
+ATTRIBUTE X-Ascend-Backup 176 string
+ATTRIBUTE X-Ascend-Call-Type 177 integer
+ATTRIBUTE X-Ascend-Group 178 string
+ATTRIBUTE X-Ascend-FR-DLCI 179 integer
+ATTRIBUTE X-Ascend-FR-Profile-Name 180 string
+ATTRIBUTE X-Ascend-Ara-PW 181 string
+ATTRIBUTE X-Ascend-IPX-Node-Addr 182 string
+ATTRIBUTE X-Ascend-Home-Agent-IP-Addr 183 ipaddr
+ATTRIBUTE X-Ascend-Home-Agent-Password 184 string
+ATTRIBUTE X-Ascend-Home-Network-Name 185 string
+ATTRIBUTE X-Ascend-Home-Agent-UDP-Port 186 integer
+ATTRIBUTE X-Ascend-Multilink-ID 187 integer
+ATTRIBUTE X-Ascend-Num-In-Multilink 188 integer
+ATTRIBUTE X-Ascend-First-Dest 189 ipaddr
+ATTRIBUTE X-Ascend-Pre-Input-Octets 190 integer
+ATTRIBUTE X-Ascend-Pre-Output-Octets 191 integer
+ATTRIBUTE X-Ascend-Pre-Input-Packets 192 integer
+ATTRIBUTE X-Ascend-Pre-Output-Packets 193 integer
+ATTRIBUTE X-Ascend-Maximum-Time 194 integer
+ATTRIBUTE X-Ascend-Disconnect-Cause 195 integer
+ATTRIBUTE X-Ascend-Connect-Progress 196 integer
+ATTRIBUTE X-Ascend-Data-Rate 197 integer
+ATTRIBUTE X-Ascend-PreSession-Time 198 integer
+ATTRIBUTE X-Ascend-Token-Idle 199 integer
+ATTRIBUTE X-Ascend-Token-Immediate 200 integer
+ATTRIBUTE X-Ascend-Require-Auth 201 integer
+ATTRIBUTE X-Ascend-Number-Sessions 202 string
+ATTRIBUTE X-Ascend-Authen-Alias 203 string
+ATTRIBUTE X-Ascend-Token-Expiry 204 integer
+ATTRIBUTE X-Ascend-Menu-Selector 205 string
+
+#
+# These next two attributes conflict with the Digest attributes!
+#
+ATTRIBUTE X-Ascend-Menu-Item 206 string
+ATTRIBUTE X-Ascend-PW-Warntime 207 integer
+
+ATTRIBUTE X-Ascend-PW-Lifetime 208 integer
+ATTRIBUTE X-Ascend-IP-Direct 209 ipaddr
+ATTRIBUTE X-Ascend-PPP-VJ-Slot-Comp 210 integer
+ATTRIBUTE X-Ascend-PPP-VJ-1172 211 integer
+ATTRIBUTE X-Ascend-PPP-Async-Map 212 integer
+ATTRIBUTE X-Ascend-Third-Prompt 213 string
+ATTRIBUTE X-Ascend-Send-Secret 214 string encrypt=3
+ATTRIBUTE X-Ascend-Receive-Secret 215 string encrypt=3
+ATTRIBUTE X-Ascend-IPX-Peer-Mode 216 integer
+ATTRIBUTE X-Ascend-IP-Pool-Definition 217 string
+ATTRIBUTE X-Ascend-Assign-IP-Pool 218 integer
+ATTRIBUTE X-Ascend-FR-Direct 219 integer
+ATTRIBUTE X-Ascend-FR-Direct-Profile 220 string
+ATTRIBUTE X-Ascend-FR-Direct-DLCI 221 integer
+ATTRIBUTE X-Ascend-Handle-IPX 222 integer
+ATTRIBUTE X-Ascend-Netware-timeout 223 integer
+ATTRIBUTE X-Ascend-IPX-Alias 224 integer
+ATTRIBUTE X-Ascend-Metric 225 integer
+ATTRIBUTE X-Ascend-PRI-Number-Type 226 integer
+ATTRIBUTE X-Ascend-Dial-Number 227 string
+ATTRIBUTE X-Ascend-Route-IP 228 integer
+ATTRIBUTE X-Ascend-Route-IPX 229 integer
+ATTRIBUTE X-Ascend-Bridge 230 integer
+ATTRIBUTE X-Ascend-Send-Auth 231 integer
+ATTRIBUTE X-Ascend-Send-Passwd 232 string
+ATTRIBUTE X-Ascend-Link-Compression 233 integer
+ATTRIBUTE X-Ascend-Target-Util 234 integer
+ATTRIBUTE X-Ascend-Maximum-Channels 235 integer
+ATTRIBUTE X-Ascend-Inc-Channel-Count 236 integer
+ATTRIBUTE X-Ascend-Dec-Channel-Count 237 integer
+ATTRIBUTE X-Ascend-Seconds-Of-History 238 integer
+ATTRIBUTE X-Ascend-History-Weigh-Type 239 integer
+ATTRIBUTE X-Ascend-Add-Seconds 240 integer
+ATTRIBUTE X-Ascend-Remove-Seconds 241 integer
+ATTRIBUTE X-Ascend-Data-Filter 242 abinary
+ATTRIBUTE X-Ascend-Call-Filter 243 abinary
+ATTRIBUTE X-Ascend-Idle-Limit 244 integer
+ATTRIBUTE X-Ascend-Preempt-Limit 245 integer
+ATTRIBUTE X-Ascend-Callback 246 integer
+ATTRIBUTE X-Ascend-Data-Svc 247 integer
+ATTRIBUTE X-Ascend-Force-56 248 integer
+ATTRIBUTE X-Ascend-Billing-Number 249 string
+ATTRIBUTE X-Ascend-Call-By-Call 250 integer
+ATTRIBUTE X-Ascend-Transit-Number 251 string
+ATTRIBUTE X-Ascend-Host-Info 252 string
+ATTRIBUTE X-Ascend-PPP-Address 253 ipaddr
+ATTRIBUTE X-Ascend-MPP-Idle-Percent 254 integer
+ATTRIBUTE X-Ascend-Xmit-Rate 255 integer
+
+#
+# VALUEs for X-Ascend-* attributes, copied verbatim from the
+# VALUEs above, for the VSA versions of Ascend-*.
+#
+# Do NOT edit the following VALUEs! Instead, re-generate them via:
+#
+# (for x in `egrep ^ATTRIBUTE dictionary.ascend | egrep 'X-Ascend-' | awk '{print $2}' | uniq`;do y=`echo $x | sed 's/X-//'`;egrep VALUE dictionary.ascend | egrep $y[^-] | sed "s/$y/X-$y/" ; done) > new-value
+#
+#
+VALUE X-Ascend-Temporary-Rtes Temp-Rtes-No 0
+VALUE X-Ascend-Temporary-Rtes Temp-Rtes-Yes 1
+VALUE X-Ascend-Tunneling-Protocol ATMP-Tunnel 0
+VALUE X-Ascend-Tunneling-Protocol VTP-Tunnel 1
+VALUE X-Ascend-Shared-Profile-Enable Shared-Profile-No 0
+VALUE X-Ascend-Shared-Profile-Enable Shared-Profile-Yes 1
+VALUE X-Ascend-Dialout-Allowed Dialout-Not-Allowed 0
+VALUE X-Ascend-Dialout-Allowed Dialout-Allowed 1
+VALUE X-Ascend-BACP-Enable BACP-No 0
+VALUE X-Ascend-BACP-Enable BACP-Yes 1
+VALUE X-Ascend-Client-Assign-DNS DNS-Assign-No 0
+VALUE X-Ascend-Client-Assign-DNS DNS-Assign-Yes 1
+VALUE X-Ascend-User-Acct-Type Ascend-User-Acct-None 0
+VALUE X-Ascend-User-Acct-Type Ascend-User-Acct-User 1
+VALUE X-Ascend-User-Acct-Type Ascend-User-Acct-User-Default 2
+VALUE X-Ascend-User-Acct-Base Base-10 0
+VALUE X-Ascend-User-Acct-Base Base-16 1
+VALUE X-Ascend-DHCP-Reply DHCP-Reply-No 0
+VALUE X-Ascend-DHCP-Reply DHCP-Reply-Yes 1
+VALUE X-Ascend-Expect-Callback Expect-Callback-No 0
+VALUE X-Ascend-Expect-Callback Expect-Callback-Yes 1
+VALUE X-Ascend-Event-Type Ascend-ColdStart 1
+VALUE X-Ascend-Event-Type Ascend-Session-Event 2
+VALUE X-Ascend-Multicast-Client Multicast-No 0
+VALUE X-Ascend-Multicast-Client Multicast-Yes 1
+VALUE X-Ascend-FR-LinkUp Ascend-LinkUp-Default 0
+VALUE X-Ascend-FR-LinkUp Ascend-LinkUp-AlwaysUp 1
+VALUE X-Ascend-FR-Type Ascend-FR-DTE 0
+VALUE X-Ascend-FR-Type Ascend-FR-DCE 1
+VALUE X-Ascend-FR-Type Ascend-FR-NNI 2
+VALUE X-Ascend-FR-Link-Mgt Ascend-FR-No-Link-Mgt 0
+VALUE X-Ascend-FR-Link-Mgt Ascend-FR-T1-617D 1
+VALUE X-Ascend-FR-Link-Mgt Ascend-FR-Q-933A 2
+VALUE X-Ascend-TS-Idle-Mode TS-Idle-None 0
+VALUE X-Ascend-TS-Idle-Mode TS-Idle-Input 1
+VALUE X-Ascend-TS-Idle-Mode TS-Idle-Input-Output 2
+VALUE X-Ascend-DBA-Monitor DBA-Transmit 0
+VALUE X-Ascend-DBA-Monitor DBA-Transmit-Recv 1
+VALUE X-Ascend-DBA-Monitor DBA-None 2
+VALUE X-Ascend-FT1-Caller FT1-No 0
+VALUE X-Ascend-FT1-Caller FT1-Yes 1
+VALUE X-Ascend-Call-Type Switched 0
+VALUE X-Ascend-Call-Type Nailed 1
+VALUE X-Ascend-Call-Type Nailed/Mpp 2
+VALUE X-Ascend-Call-Type Perm/Switched 3
+VALUE X-Ascend-Call-Type AO/DI 6
+VALUE X-Ascend-Call-Type MegaMax 7
+VALUE X-Ascend-Disconnect-Cause No-Reason 0
+VALUE X-Ascend-Disconnect-Cause Not-Applicable 1
+VALUE X-Ascend-Disconnect-Cause Unknown 2
+VALUE X-Ascend-Disconnect-Cause Call-Disconnected 3
+VALUE X-Ascend-Disconnect-Cause CLID-Authentication-Failed 4
+VALUE X-Ascend-Disconnect-Cause CLID-RADIUS-Timeout 5
+VALUE X-Ascend-Disconnect-Cause Modem-No-DCD 10
+VALUE X-Ascend-Disconnect-Cause DCD-Detected-Then-Inactive 11
+VALUE X-Ascend-Disconnect-Cause Modem-Invalid-Result-Codes 12
+VALUE X-Ascend-Disconnect-Cause TermSrv-User-Quit 20
+VALUE X-Ascend-Disconnect-Cause TermSrv-Idle-Timeout 21
+VALUE X-Ascend-Disconnect-Cause TermSrv-Exit-Telnet 22
+VALUE X-Ascend-Disconnect-Cause TermSrv-No-IPaddr 23
+VALUE X-Ascend-Disconnect-Cause TermSrv-Exit-Raw-TCP 24
+VALUE X-Ascend-Disconnect-Cause TermSrv-Exit-Login-Failed 25
+VALUE X-Ascend-Disconnect-Cause TermSrv-Exit-Raw-TCP-Disabled 26
+VALUE X-Ascend-Disconnect-Cause TermSrv-CTRL-C-In-Login 27
+VALUE X-Ascend-Disconnect-Cause TermSrv-Destroyed 28
+VALUE X-Ascend-Disconnect-Cause TermSrv-User-Closed-VCon 29
+VALUE X-Ascend-Disconnect-Cause TermSrv-VCon-Destroyed 30
+VALUE X-Ascend-Disconnect-Cause TermSrv-Exit-Rlogin 31
+VALUE X-Ascend-Disconnect-Cause TermSrv-Bad-Rlogin-Option 32
+VALUE X-Ascend-Disconnect-Cause TermSrv-Not-Enough-Resources 33
+VALUE X-Ascend-Disconnect-Cause MPP-No-NULL-Msg-Timeout 35
+VALUE X-Ascend-Disconnect-Cause PPP-LCP-Timeout 40
+VALUE X-Ascend-Disconnect-Cause PPP-LCP-Negotion-Failed 41
+VALUE X-Ascend-Disconnect-Cause PPP-PAP-Auth-Failed 42
+VALUE X-Ascend-Disconnect-Cause PPP-CHAP-Auth-Failed 43
+VALUE X-Ascend-Disconnect-Cause PPP-Rmt-Auth-Failed 44
+VALUE X-Ascend-Disconnect-Cause PPP-Rcv-Terminate-Req 45
+VALUE X-Ascend-Disconnect-Cause PPP-Rcv-Close-Event 46
+VALUE X-Ascend-Disconnect-Cause PPP-No-NCPs-Open 47
+VALUE X-Ascend-Disconnect-Cause PPP-MP-Bundle-Unknown 48
+VALUE X-Ascend-Disconnect-Cause PPP-LCP-Close-MP-Add-Fail 49
+VALUE X-Ascend-Disconnect-Cause Session-Table-Full 50
+VALUE X-Ascend-Disconnect-Cause Out-Of-Resources 51
+VALUE X-Ascend-Disconnect-Cause Invalid-IP-Address 52
+VALUE X-Ascend-Disconnect-Cause Hostname-Resolution-Failed 53
+VALUE X-Ascend-Disconnect-Cause Bad-Or-Missing-Port-Number 54
+VALUE X-Ascend-Disconnect-Cause Host-Reset 60
+VALUE X-Ascend-Disconnect-Cause Connection-Refused 61
+VALUE X-Ascend-Disconnect-Cause Connection-Timeout 62
+VALUE X-Ascend-Disconnect-Cause Connection-Closed 63
+VALUE X-Ascend-Disconnect-Cause Network-Unreachable 64
+VALUE X-Ascend-Disconnect-Cause Host-Unreachable 65
+VALUE X-Ascend-Disconnect-Cause Network-Unreachable-Admin 66
+VALUE X-Ascend-Disconnect-Cause Host-Unreachable-Admin 67
+VALUE X-Ascend-Disconnect-Cause Port-Unreachable 68
+VALUE X-Ascend-Disconnect-Cause Session-Timeout 100
+VALUE X-Ascend-Disconnect-Cause Invalid-Incoming-User 101
+VALUE X-Ascend-Disconnect-Cause Disconnect-Due-To-Callback 102
+VALUE X-Ascend-Disconnect-Cause Proto-Disabled-Or-Unsupported 120
+VALUE X-Ascend-Disconnect-Cause Disconnect-Req-By-RADIUS 150
+VALUE X-Ascend-Disconnect-Cause Disconnect-Req-By-Local-Admin 151
+VALUE X-Ascend-Disconnect-Cause V110-Timeout-Sync-Retry-Exceed 160
+VALUE X-Ascend-Disconnect-Cause PPP-Auth-Timeout-Exceeded 170
+VALUE X-Ascend-Disconnect-Cause User-Executed-Do-Hangup 180
+VALUE X-Ascend-Disconnect-Cause Remote-End-Hung-Up 185
+VALUE X-Ascend-Disconnect-Cause Resource-Has-Been-Quiesced 190
+VALUE X-Ascend-Disconnect-Cause Max-Call-Duration-Reached 195
+VALUE X-Ascend-Connect-Progress No-Progress 0
+VALUE X-Ascend-Connect-Progress Call-Up 10
+VALUE X-Ascend-Connect-Progress Modem-Up 30
+VALUE X-Ascend-Connect-Progress Modem-Awaiting-DCD 31
+VALUE X-Ascend-Connect-Progress Modem-Awaiting-Codes 32
+VALUE X-Ascend-Connect-Progress TermSrv-Started 40
+VALUE X-Ascend-Connect-Progress TermSrv-Raw-TCP-Started 41
+VALUE X-Ascend-Connect-Progress TermSrv-Telnet-Started 42
+VALUE X-Ascend-Connect-Progress TermSrv-Raw-TCP-Connected 43
+VALUE X-Ascend-Connect-Progress TermSrv-Telnet-Connected 44
+VALUE X-Ascend-Connect-Progress TermSrv-Rlogin-Started 45
+VALUE X-Ascend-Connect-Progress TermSrv-Rlogin-Connected 46
+VALUE X-Ascend-Connect-Progress Modem-Outdial-Call-Up 50
+VALUE X-Ascend-Connect-Progress LAN-Session-Up 60
+VALUE X-Ascend-Connect-Progress LCP-Opening 61
+VALUE X-Ascend-Connect-Progress CCP-Opening 62
+VALUE X-Ascend-Connect-Progress IPNCP-Opening 63
+VALUE X-Ascend-Connect-Progress BNCP-Opening 64
+VALUE X-Ascend-Connect-Progress LCP-Opened 65
+VALUE X-Ascend-Connect-Progress CCP-Opened 66
+VALUE X-Ascend-Connect-Progress IPNCP-Opened 67
+VALUE X-Ascend-Connect-Progress BNCP-Opened 68
+VALUE X-Ascend-Connect-Progress LCP-State-Initial 69
+VALUE X-Ascend-Connect-Progress LCP-State-Starting 70
+VALUE X-Ascend-Connect-Progress LCP-State-Closed 71
+VALUE X-Ascend-Connect-Progress LCP-State-Stopped 72
+VALUE X-Ascend-Connect-Progress LCP-State-Closing 73
+VALUE X-Ascend-Connect-Progress LCP-State-Stopping 74
+VALUE X-Ascend-Connect-Progress LCP-State-Request-Sent 75
+VALUE X-Ascend-Connect-Progress LCP-State-Ack-Received 76
+VALUE X-Ascend-Connect-Progress LCP-State-Ack-Sent 77
+VALUE X-Ascend-Connect-Progress IPXNCP-Opened 80
+VALUE X-Ascend-Connect-Progress ATNCP-Opened 81
+VALUE X-Ascend-Connect-Progress BACP-Opening 82
+VALUE X-Ascend-Connect-Progress BACP-Opened 83
+VALUE X-Ascend-Connect-Progress V110-Up 90
+VALUE X-Ascend-Connect-Progress V110-State-Opened 91
+VALUE X-Ascend-Connect-Progress V110-State-Carrier 92
+VALUE X-Ascend-Connect-Progress V110-State-Reset 93
+VALUE X-Ascend-Connect-Progress V110-State-Closed 94
+VALUE X-Ascend-Token-Immediate Tok-Imm-No 0
+VALUE X-Ascend-Token-Immediate Tok-Imm-Yes 1
+VALUE X-Ascend-Require-Auth Not-Require-Auth 0
+VALUE X-Ascend-Require-Auth Require-Auth 1
+VALUE X-Ascend-PW-Warntime Days-Of-Warning 0
+VALUE X-Ascend-PW-Lifetime Lifetime-In-Days 0
+VALUE X-Ascend-PPP-VJ-Slot-Comp VJ-Slot-Comp-No 1
+VALUE X-Ascend-PPP-VJ-1172 PPP-VJ-1172 1
+VALUE X-Ascend-IPX-Peer-Mode IPX-Peer-Router 0
+VALUE X-Ascend-IPX-Peer-Mode IPX-Peer-Dialin 1
+VALUE X-Ascend-FR-Direct FR-Direct-No 0
+VALUE X-Ascend-FR-Direct FR-Direct-Yes 1
+VALUE X-Ascend-Handle-IPX Handle-IPX-None 0
+VALUE X-Ascend-Handle-IPX Handle-IPX-Client 1
+VALUE X-Ascend-Handle-IPX Handle-IPX-Server 2
+VALUE X-Ascend-PRI-Number-Type Unknown-Number 0
+VALUE X-Ascend-PRI-Number-Type Intl-Number 1
+VALUE X-Ascend-PRI-Number-Type National-Number 2
+VALUE X-Ascend-PRI-Number-Type Net-Specific-Number 3
+VALUE X-Ascend-PRI-Number-Type Local-Number 4
+VALUE X-Ascend-PRI-Number-Type Abbrev-Number 5
+VALUE X-Ascend-Route-IP Route-IP-No 0
+VALUE X-Ascend-Route-IP Route-IP-Yes 1
+VALUE X-Ascend-Route-IPX Route-IPX-No 0
+VALUE X-Ascend-Route-IPX Route-IPX-Yes 1
+VALUE X-Ascend-Route-IPX Route-IPX-No 0
+VALUE X-Ascend-Route-IPX Route-IPX-Yes 1
+VALUE X-Ascend-Bridge Bridge-No 0
+VALUE X-Ascend-Bridge Bridge-Yes 1
+VALUE X-Ascend-Send-Auth Send-Auth-None 0
+VALUE X-Ascend-Send-Auth Send-Auth-PAP 1
+VALUE X-Ascend-Send-Auth Send-Auth-CHAP 2
+VALUE X-Ascend-Send-Auth Send-Auth-MS-CHAP 3
+VALUE X-Ascend-Link-Compression Link-Comp-None 0
+VALUE X-Ascend-Link-Compression Link-Comp-Stac 1
+VALUE X-Ascend-Link-Compression Link-Comp-Stac-Draft-9 2
+VALUE X-Ascend-Link-Compression Link-Comp-MS-Stac 3
+VALUE X-Ascend-History-Weigh-Type History-Constant 0
+VALUE X-Ascend-History-Weigh-Type History-Linear 1
+VALUE X-Ascend-History-Weigh-Type History-Quadratic 2
+VALUE X-Ascend-Callback Callback-No 0
+VALUE X-Ascend-Callback Callback-Yes 1
+VALUE X-Ascend-Data-Svc Switched-Voice-Bearer 0
+VALUE X-Ascend-Data-Svc Nailed-56KR 1
+VALUE X-Ascend-Data-Svc Nailed-64K 2
+VALUE X-Ascend-Data-Svc Switched-64KR 3
+VALUE X-Ascend-Data-Svc Switched-56K 4
+VALUE X-Ascend-Data-Svc Switched-384KR 5
+VALUE X-Ascend-Data-Svc Switched-384K 6
+VALUE X-Ascend-Data-Svc Switched-1536K 7
+VALUE X-Ascend-Data-Svc Switched-1536KR 8
+VALUE X-Ascend-Data-Svc Switched-128K 9
+VALUE X-Ascend-Data-Svc Switched-192K 10
+VALUE X-Ascend-Data-Svc Switched-256K 11
+VALUE X-Ascend-Data-Svc Switched-320K 12
+VALUE X-Ascend-Data-Svc Switched-384K-MR 13
+VALUE X-Ascend-Data-Svc Switched-448K 14
+VALUE X-Ascend-Data-Svc Switched-512K 15
+VALUE X-Ascend-Data-Svc Switched-576K 16
+VALUE X-Ascend-Data-Svc Switched-640K 17
+VALUE X-Ascend-Data-Svc Switched-704K 18
+VALUE X-Ascend-Data-Svc Switched-768K 19
+VALUE X-Ascend-Data-Svc Switched-832K 20
+VALUE X-Ascend-Data-Svc Switched-896K 21
+VALUE X-Ascend-Data-Svc Switched-960K 22
+VALUE X-Ascend-Data-Svc Switched-1024K 23
+VALUE X-Ascend-Data-Svc Switched-1088K 24
+VALUE X-Ascend-Data-Svc Switched-1152K 25
+VALUE X-Ascend-Data-Svc Switched-1216K 26
+VALUE X-Ascend-Data-Svc Switched-1280K 27
+VALUE X-Ascend-Data-Svc Switched-1344K 28
+VALUE X-Ascend-Data-Svc Switched-1408K 29
+VALUE X-Ascend-Data-Svc Switched-1472K 30
+VALUE X-Ascend-Data-Svc Switched-1600K 31
+VALUE X-Ascend-Data-Svc Switched-1664K 32
+VALUE X-Ascend-Data-Svc Switched-1728K 33
+VALUE X-Ascend-Data-Svc Switched-1792K 34
+VALUE X-Ascend-Data-Svc Switched-1856K 35
+VALUE X-Ascend-Data-Svc Switched-1920K 36
+VALUE X-Ascend-Data-Svc Switched-inherited 37
+VALUE X-Ascend-Data-Svc Switched-restricted-bearer-x30 38
+VALUE X-Ascend-Data-Svc Switched-clear-bearer-v110 39
+VALUE X-Ascend-Data-Svc Switched-restricted-64-x30 40
+VALUE X-Ascend-Data-Svc Switched-clear-56-v110 41
+VALUE X-Ascend-Data-Svc Switched-modem 42
+VALUE X-Ascend-Data-Svc Switched-atmodem 43
+VALUE X-Ascend-Data-Svc Switched-V110-24-56 45
+VALUE X-Ascend-Data-Svc Switched-V110-48-56 46
+VALUE X-Ascend-Data-Svc Switched-V110-96-56 47
+VALUE X-Ascend-Data-Svc Switched-V110-192-56 48
+VALUE X-Ascend-Data-Svc Switched-V110-384-56 49
+VALUE X-Ascend-Data-Svc Switched-V110-24-56R 50
+VALUE X-Ascend-Data-Svc Switched-V110-48-56R 51
+VALUE X-Ascend-Data-Svc Switched-V110-96-56R 52
+VALUE X-Ascend-Data-Svc Switched-V110-192-56R 53
+VALUE X-Ascend-Data-Svc Switched-V110-384-56R 54
+VALUE X-Ascend-Data-Svc Switched-V110-24-64 55
+VALUE X-Ascend-Data-Svc Switched-V110-48-64 56
+VALUE X-Ascend-Data-Svc Switched-V110-96-64 57
+VALUE X-Ascend-Data-Svc Switched-V110-192-64 58
+VALUE X-Ascend-Data-Svc Switched-V110-384-64 59
+VALUE X-Ascend-Data-Svc Switched-V110-24-64R 60
+VALUE X-Ascend-Data-Svc Switched-V110-48-64R 61
+VALUE X-Ascend-Data-Svc Switched-V110-96-64R 62
+VALUE X-Ascend-Data-Svc Switched-V110-384-64R 64
+VALUE X-Ascend-Data-Svc Switched-V110-192-64R 63
+VALUE X-Ascend-Data-Svc Switched-Pots 68
+VALUE X-Ascend-Data-Svc Switched-ATM 69
+VALUE X-Ascend-Data-Svc Switched-FR 70
+VALUE X-Ascend-Force-56 Force-56-No 0
+VALUE X-Ascend-Force-56 Force-56-Yes 1
diff --git a/share/dictionary.asn b/share/dictionary.asn
new file mode 100644
index 0000000..cebb30a
--- /dev/null
+++ b/share/dictionary.asn
@@ -0,0 +1,96 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# ASN Attributes.
+#
+# Taken from http://svn.asn.pl/misc/freeradius/dictionary.asn
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR ASN 23782
+
+BEGIN-VENDOR ASN
+
+## Server-side extensions
+# dynamic IP pool name
+ATTRIBUTE ASN-IP-Pool-Name 1 string
+
+### 2-99: free ###
+
+## limits
+ATTRIBUTE ASN-Kbps-Down 100 integer
+ATTRIBUTE ASN-Kbps-Down-Localmedia 112 integer
+ATTRIBUTE ASN-Kbps-Up 101 integer
+ATTRIBUTE ASN-Pps-Down 102 integer
+ATTRIBUTE ASN-Pps-Up 103 integer
+ATTRIBUTE ASN-TCP-Connlimit 104 integer
+
+## firewall
+ATTRIBUTE ASN-Firewall-Available 110 integer
+VALUE ASN-Firewall-Available Yes 1
+VALUE ASN-Firewall-Available No 2
+
+ATTRIBUTE ASN-Firewall-State 105 integer
+VALUE ASN-Firewall-State Enabled 1
+VALUE ASN-Firewall-State Disabled 2
+
+ATTRIBUTE ASN-Firewall-Block-Ping 107 integer
+VALUE ASN-Firewall-Block-Ping Enabled 1
+VALUE ASN-Firewall-Block-Ping Disabled 2
+
+# hosts to allow "<tcp/udp/sctp> <host> <port1,port2,...>"
+ATTRIBUTE ASN-Firewall-Open 106 string
+
+## QoS
+ATTRIBUTE ASN-QoS-Available 111 integer
+VALUE ASN-QoS-Available Yes 1
+VALUE ASN-QoS-Available No 2
+
+ATTRIBUTE ASN-QoS-State 108 integer
+VALUE ASN-QoS-State Enabled 1
+VALUE ASN-QoS-State Disabled 2
+
+# IP redirection, with optional randomness
+# "<tcp/udp/sctp> src/dst [<dsthost[/mask]>:]<port1,port2,...> <host>:<port> [<random%>]"
+# where src/dst decides whether to match source or destination ports
+# random is an integer number from 1 to 99, or null - no randomness
+ATTRIBUTE ASN-IP-Redirect 109 string
+
+## web filtering
+# decides whether to deny or to allow only the specified web topics
+ATTRIBUTE ASN-Webfilter-Mode 113 integer
+VALUE ASN-Webfilter-Mode Deny 1
+VALUE ASN-Webfilter-Mode Allow 2
+
+# where to redirect blocked request
+# "[301:302]<new url>"
+# 301/302 - redirect permanently (301) or temporarily (302) (default 302)
+# <new url> - an URL address, with following possible substitutions:
+# %a - IP address of the client
+# %i - user ID (RFC931) or "unknown"
+# %n - domainname of the client or "unknown"
+# %p - REQUEST_URI, ie. the path and the optional
+# query string of %u, but note for convenience
+# without the leading "/".
+# %t - matched destination group or "unknown"
+# %u - requested URL
+# %% - single '%'
+#
+ATTRIBUTE ASN-Webfilter-Redirect 114 string
+
+# squidGuard destination group to match
+# destinations available by default: sglists-<tag> - tags:
+# ads adult audioandvideo banks blogs chatandforum finance freemail games
+# home jobsearch keylogger news onlineGames phishing proxies recreation
+# reference science searchengine
+ATTRIBUTE ASN-Webfilter-Destination 115 string
+
+# web domain to match (will match all subdomains, too)
+ATTRIBUTE ASN-Webfilter-Domain 116 string
+
+END-VENDOR ASN
diff --git a/share/dictionary.audiocodes b/share/dictionary.audiocodes
new file mode 100644
index 0000000..1ce23b3
--- /dev/null
+++ b/share/dictionary.audiocodes
@@ -0,0 +1,23 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Audiocodes
+#
+# http://www.audiocodes.com/filehandler.ashx?fileid=36358
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR AudioCodes 5003
+BEGIN-VENDOR AudioCodes
+
+ATTRIBUTE ACL-Auth-Level 35 integer
+VALUE ACL-Auth-Level ACL-Auth-UserLevel 50
+VALUE ACL-Auth-Level ACL-Auth-AdminLevel 100
+VALUE ACL-Auth-Level ACL-Auth-SecurityAdminLevel 200
+
+END-VENDOR AudioCodes
diff --git a/share/dictionary.avaya b/share/dictionary.avaya
new file mode 100644
index 0000000..f51664b
--- /dev/null
+++ b/share/dictionary.avaya
@@ -0,0 +1,32 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Avaya P330 dictionary file
+# $Id$
+#
+# http://support.avaya.com/elmodocs2/p330/P330/Configuring%20FreeRadius.pdf
+#
+
+VENDOR Cajun_p330 2167
+BEGIN-VENDOR Cajun_p330
+
+ATTRIBUTE Cajun-Service-Type 1 integer
+
+VALUE Cajun-Service-Type Cajun-Read-Only-User 1
+VALUE Cajun-Service-Type Cajun-Read-Write-User 2
+VALUE Cajun-Service-Type Cajun-Admin-User 3
+
+ATTRIBUTE Avaya-StaticVlan-Type 12 string
+ATTRIBUTE Avaya-PortPriority-Type 13 integer
+
+VALUE Avaya-PortPriority-Type Type-0 0
+VALUE Avaya-PortPriority-Type Type-1 1
+VALUE Avaya-PortPriority-Type Type-2 2
+VALUE Avaya-PortPriority-Type Type-3 3
+VALUE Avaya-PortPriority-Type Type-4 4
+VALUE Avaya-PortPriority-Type Type-5 5
+VALUE Avaya-PortPriority-Type Type-6 6
+VALUE Avaya-PortPriority-Type Type-7 7
+
+END-VENDOR Cajun_p330
diff --git a/share/dictionary.azaire b/share/dictionary.azaire
new file mode 100644
index 0000000..304797f
--- /dev/null
+++ b/share/dictionary.azaire
@@ -0,0 +1,53 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Azaire VSAs
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR Azaire 7751
+
+BEGIN-VENDOR Azaire
+
+ATTRIBUTE Azaire-Triplets 1 octets
+ATTRIBUTE Azaire-IMSI 2 octets
+ATTRIBUTE Azaire-MSISDN 3 octets
+ATTRIBUTE Azaire-APN 4 string
+ATTRIBUTE Azaire-QoS 5 octets
+ATTRIBUTE Azaire-Selection-Mode 6 integer
+ATTRIBUTE Azaire-APN-Resolution-Req 7 integer
+ATTRIBUTE Azaire-Start-Time 8 octets
+ATTRIBUTE Azaire-NAS-Type 9 integer
+ATTRIBUTE Azaire-Status 10 integer
+ATTRIBUTE Azaire-APN-OI 11 string
+ATTRIBUTE Azaire-Auth-Type 12 integer
+ATTRIBUTE Azaire-Gn-User-Name 13 string
+ATTRIBUTE Azaire-Brand-Code 14 string
+ATTRIBUTE Azaire-Policy-Name 15 string
+ATTRIBUTE Azaire-Client-Local-IP 16 ipaddr
+
+VALUE Azaire-Selection-Mode Subscribed 0
+VALUE Azaire-Selection-Mode Sent-By-MS 1
+VALUE Azaire-Selection-Mode Chosen-By-SGSN 2
+
+VALUE Azaire-APN-Resolution-Req Not-Required 0
+VALUE Azaire-APN-Resolution-Req Required 1
+
+VALUE Azaire-Status Success 0
+VALUE Azaire-Status Failure 1
+
+VALUE Azaire-Auth-Type PPP-SIM 1
+VALUE Azaire-Auth-Type Dummy-IMSI 2
+VALUE Azaire-Auth-Type Soft-SIM 3
+VALUE Azaire-Auth-Type Radius-SIM 4
+VALUE Azaire-Auth-Type Post-paid 5
+VALUE Azaire-Auth-Type Pre-paid 6
+VALUE Azaire-Auth-Type Local-Radius 7
+VALUE Azaire-Auth-Type Proxy-Radius 8
+
+END-VENDOR Azaire
diff --git a/share/dictionary.bay b/share/dictionary.bay
new file mode 100644
index 0000000..30c854d
--- /dev/null
+++ b/share/dictionary.bay
@@ -0,0 +1,295 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Bay Networks
+# http://www.baynetworks.com/
+#
+# From MegaZone <megazone@megazone.org>, as posted to the bay-isp list.
+# Modified for Freeradius by Alan DeKok <aland@freeradius.org>
+#
+# Bay Networks was acquired by Nortel in 1998. Some Avaya products continue
+# to use attributes from this dictionary as result of the Nortel acquisitions.
+#
+
+VENDOR Bay-Networks 1584
+
+BEGIN-VENDOR Bay-Networks
+# Bay Networks Extensions
+
+ATTRIBUTE Annex-Filter 28 string
+ATTRIBUTE Annex-CLI-Command 29 string
+ATTRIBUTE Annex-CLI-Filter 30 string
+ATTRIBUTE Annex-Host-Restrict 31 string
+ATTRIBUTE Annex-Host-Allow 32 string
+ATTRIBUTE Annex-Product-Name 33 string
+ATTRIBUTE Annex-SW-Version 34 string
+ATTRIBUTE Annex-Local-IP-Address 35 ipaddr
+ATTRIBUTE Annex-Callback-Portlist 36 integer
+ATTRIBUTE Annex-Sec-Profile-Index 37 integer
+ATTRIBUTE Annex-Tunnel-Authen-Type 38 integer
+ATTRIBUTE Annex-Tunnel-Authen-Mode 39 integer
+ATTRIBUTE Annex-Authen-Servers 40 string
+ATTRIBUTE Annex-Acct-Servers 41 string
+ATTRIBUTE Annex-User-Server-Location 42 integer
+ATTRIBUTE Annex-Local-Username 43 string
+ATTRIBUTE Annex-System-Disc-Reason 44 integer
+ATTRIBUTE Annex-Modem-Disc-Reason 45 integer
+ATTRIBUTE Annex-Disconnect-Reason 46 integer
+ATTRIBUTE Annex-Addr-Resolution-Protocol 47 integer
+ATTRIBUTE Annex-Addr-Resolution-Servers 48 string
+ATTRIBUTE Annex-Domain-Name 49 string
+ATTRIBUTE Annex-Transmit-Speed 50 integer
+ATTRIBUTE Annex-Receive-Speed 51 integer
+ATTRIBUTE Annex-Input-Filter 52 string
+ATTRIBUTE Annex-Output-Filter 53 string
+ATTRIBUTE Annex-Primary-DNS-Server 54 ipaddr
+ATTRIBUTE Annex-Secondary-DNS-Server 55 ipaddr
+ATTRIBUTE Annex-Primary-NBNS-Server 56 ipaddr
+ATTRIBUTE Annex-Secondary-NBNS-Server 57 ipaddr
+ATTRIBUTE Annex-Syslog-Tap 58 integer
+ATTRIBUTE Annex-Keypress-Timeout 59 integer
+ATTRIBUTE Annex-Unauthenticated-Time 60 integer
+ATTRIBUTE Annex-Re-CHAP-Timeout 61 integer
+ATTRIBUTE Annex-MRRU 62 integer
+ATTRIBUTE Annex-EDO 63 string
+# Annex R18.0 software
+ATTRIBUTE Annex-PPP-Trace-Level 64 integer
+ATTRIBUTE Annex-Pre-Input-Octets 65 integer
+ATTRIBUTE Annex-Pre-Output-Octets 66 integer
+ATTRIBUTE Annex-Pre-Input-Packets 67 integer
+ATTRIBUTE Annex-Pre-Output-Packets 68 integer
+ATTRIBUTE Annex-Connect-Progress 69 integer
+ATTRIBUTE Annex-Multicast-Rate-Limit 73 integer
+ATTRIBUTE Annex-Maximum-Call-Duration 74 integer
+ATTRIBUTE Annex-Multilink-Id 75 integer
+ATTRIBUTE Annex-Num-In-Multilink 76 integer
+ATTRIBUTE Annex-Secondary-Srv-Endpoint 79 string
+ATTRIBUTE Annex-Gwy-Selection-Mode 80 integer
+ATTRIBUTE Annex-Logical-Channel-Number 81 integer
+ATTRIBUTE Annex-Wan-Number 82 integer
+ATTRIBUTE Annex-Port 83 integer
+ATTRIBUTE Annex-Pool-Id 85 integer
+ATTRIBUTE Annex-Compression-Protocol 86 string
+ATTRIBUTE Annex-Transmitted-Packets 87 integer
+ATTRIBUTE Annex-Retransmitted-Packets 88 integer
+ATTRIBUTE Annex-Signal-to-Noise-Ratio 89 integer
+ATTRIBUTE Annex-Retrain-Requests-Sent 90 integer
+ATTRIBUTE Annex-Retrain-Requests-Rcvd 91 integer
+ATTRIBUTE Annex-Rate-Reneg-Req-Sent 92 integer
+ATTRIBUTE Annex-Rate-Reneg-Req-Rcvd 93 integer
+ATTRIBUTE Annex-Begin-Receive-Line-Level 94 integer
+ATTRIBUTE Annex-End-Receive-Line-Level 95 integer
+ATTRIBUTE Annex-Begin-Modulation 96 string
+ATTRIBUTE Annex-Error-Correction-Prot 97 string
+ATTRIBUTE Annex-End-Modulation 98 string
+
+# Bay Router Specific Attributes
+#
+ATTRIBUTE Annex-User-Level 100 integer
+ATTRIBUTE Annex-Audit-Level 101 integer
+
+# Contivity
+ATTRIBUTE CES-Group 102 string
+
+# Passport 8000 Series Specific Attributes
+#
+ATTRIBUTE Passport-Access-Priority 192 integer
+
+VALUE Passport-Access-Priority None-Access 0
+VALUE Passport-Access-Priority Read-Only-Access 1
+VALUE Passport-Access-Priority L1-Read-Write-Access 2
+VALUE Passport-Access-Priority L2-Read-Write-Access 3
+VALUE Passport-Access-Priority L3-Read-Write-Access 4
+VALUE Passport-Access-Priority Read-Write-Access 5
+VALUE Passport-Access-Priority Read-Write-All-Access 6
+
+ATTRIBUTE Annex-Cli-Commands 193 string
+ATTRIBUTE Annex-Command-Access 194 integer
+
+VALUE Annex-Command-Access False 0
+VALUE Annex-Command-Access True 1
+
+ATTRIBUTE Commands 195 string
+
+# Annex Tunnel Authen Type Values
+
+VALUE Annex-Tunnel-Authen-Type none 0
+VALUE Annex-Tunnel-Authen-Type kmd5-128 1
+
+# Annex Tunnel Authen Mode Values
+
+VALUE Annex-Tunnel-Authen-Mode none 0
+VALUE Annex-Tunnel-Authen-Mode prefix-suffix 1
+
+# Annex User Server Location Values
+
+VALUE Annex-User-Server-Location local 1
+VALUE Annex-User-Server-Location remote 2
+
+# Annex Addr Resolution Protocol Values
+
+VALUE Annex-Addr-Resolution-Protocol none 0
+VALUE Annex-Addr-Resolution-Protocol DHCP 1
+
+# Annex System Disconnect Reason Values
+
+VALUE Annex-System-Disc-Reason Unknown 0
+VALUE Annex-System-Disc-Reason Line-disconnected 1
+VALUE Annex-System-Disc-Reason Dial-failed 2
+VALUE Annex-System-Disc-Reason WAN-manager-error 3
+VALUE Annex-System-Disc-Reason Disconnect-reset 4
+VALUE Annex-System-Disc-Reason Error-from-adm_notify 5
+VALUE Annex-System-Disc-Reason Modem-down-adm_notify 6
+VALUE Annex-System-Disc-Reason PPP-protocol-disconnect 7
+VALUE Annex-System-Disc-Reason Inactivity-timer 8
+VALUE Annex-System-Disc-Reason CLI-Hangup-command 9
+VALUE Annex-System-Disc-Reason CLI-last-job 10
+VALUE Annex-System-Disc-Reason Session-timeout 11
+VALUE Annex-System-Disc-Reason Slave-termination 12
+VALUE Annex-System-Disc-Reason Abnormal-termination 13
+VALUE Annex-System-Disc-Reason DCD-wait-failed 14
+VALUE Annex-System-Disc-Reason CLI-inactivity 15
+VALUE Annex-System-Disc-Reason Admin-port-reset 16
+VALUE Annex-System-Disc-Reason CLI-auth-failed 17
+VALUE Annex-System-Disc-Reason Slave-auth-failed 18
+VALUE Annex-System-Disc-Reason PAP-auth-failed 19
+VALUE Annex-System-Disc-Reason CHAP-auth-failed 20
+VALUE Annex-System-Disc-Reason Local-modem-reset 21
+VALUE Annex-System-Disc-Reason Modem-dead 22
+VALUE Annex-System-Disc-Reason PPP-LCP-failure 23
+VALUE Annex-System-Disc-Reason PPP-IPCP-failure 24
+VALUE Annex-System-Disc-Reason PPP-IPXCP-failure 25
+VALUE Annex-System-Disc-Reason PPP-ATCP-failure 26
+VALUE Annex-System-Disc-Reason PPP-CCP-failure 27
+VALUE Annex-System-Disc-Reason PPP-MP-failure 28
+VALUE Annex-System-Disc-Reason PPP-IPCP-timeout 29
+VALUE Annex-System-Disc-Reason PPP-IPXCP-timeout 30
+VALUE Annex-System-Disc-Reason PPP-ATCP-timeout 31
+VALUE Annex-System-Disc-Reason PPP-CCP-timeout 32
+VALUE Annex-System-Disc-Reason PPP-MP-timeout 33
+VALUE Annex-System-Disc-Reason PPP-init-failure 34
+VALUE Annex-System-Disc-Reason PPP-Unknown 35
+VALUE Annex-System-Disc-Reason PPP-Dialback-failed 36
+VALUE Annex-System-Disc-Reason PPP-Address-In-Use 37
+VALUE Annex-System-Disc-Reason PPP-No-device 38
+VALUE Annex-System-Disc-Reason PPP-Modem-hangup-rcvd 39
+VALUE Annex-System-Disc-Reason PPP-Hangup-rcvd 40
+VALUE Annex-System-Disc-Reason PPP-Termination-rcvd 41
+VALUE Annex-System-Disc-Reason PPP-Kill-rcvd 42
+VALUE Annex-System-Disc-Reason PPP-Time-rcvd 43
+VALUE Annex-System-Disc-Reason PPP-No-memory 44
+VALUE Annex-System-Disc-Reason PPP-Connection-Abort 45
+VALUE Annex-System-Disc-Reason PPP-VPN-LCP-failure 46
+VALUE Annex-System-Disc-Reason PPP-VPN-Auth-failure 47
+VALUE Annex-System-Disc-Reason PPP-MP-invalid-port 48
+VALUE Annex-System-Disc-Reason PPP-Invalid-device 49
+VALUE Annex-System-Disc-Reason PPP-MMP-bundle-failure 50
+VALUE Annex-System-Disc-Reason DVS-Registration-failure 51
+VALUE Annex-System-Disc-Reason DVS-Home-agent-dereg 52
+VALUE Annex-System-Disc-Reason DVS-Tunnel-no-renew 53
+VALUE Annex-System-Disc-Reason DVS-Tunnel-expired 54
+
+# Annex Modem Disconnect Reason Values
+
+VALUE Annex-Modem-Disc-Reason Unknown 0
+VALUE Annex-Modem-Disc-Reason Local-disconnect 1
+VALUE Annex-Modem-Disc-Reason CD-Timer-Expired 2
+VALUE Annex-Modem-Disc-Reason Remote-protocol-disc 4
+VALUE Annex-Modem-Disc-Reason Clear-down 5
+VALUE Annex-Modem-Disc-Reason Long-Space-disconnect 6
+VALUE Annex-Modem-Disc-Reason Carrier-Lost 7
+VALUE Annex-Modem-Disc-Reason Modem-Retrain-Timeout 8
+
+# Annex Connection Progress Values
+
+#VALUE Annex-Connect-Progress Progress-Unknown 2
+#VALUE Annex-Connect-Progress Call-Is-Up 10
+#VALUE Annex-Connect-Progress CLI-Started 40
+#VALUE Annex-Connect-Progress LAN-Session-Is-Up 60
+#VALUE Annex-Connect-Progress LCP-Negotiations-Allowed 61
+#VALUE Annex-Connect-Progress CCP-Negotiations-Allowed 62
+#VALUE Annex-Connect-Progress IPCP-Negotiations-Allowed 63
+#VALUE Annex-Connect-Progress LCP-Is-In-Open-State 65
+#VALUE Annex-Connect-Progress CCP-Is-In-Open-State 66
+#VALUE Annex-Connect-Progress IPCP-Is-In-Open-State 67
+#VALUE Annex-Connect-Progress LCP-Is-In-Closed-State 71
+#VALUE Annex-Connect-Progress LCP-Is-In-Stopped-State 72
+#VALUE Annex-Connect-Progress LCP-Is-In-Closing-State 73
+#VALUE Annex-Connect-Progress LCP-Is-In-Request-Sent-State 75
+#VALUE Annex-Connect-Progress LCP-Is-In-Ack-Recvd-State 76
+#VALUE Annex-Connect-Progress LCP-Is-In-Ack-Sent-State 77
+#VALUE Annex-Connect-Progress IPXCP-Is-In-Open-State 80
+
+#VALUE Annex-Multicast-Client Multicast-No 0
+#VALUE Annex-Multicast-Client Multicast-Yes 1
+
+#VALUE Annex-Inbound-Precedence Routine 0
+#VALUE Annex-Inbound-Precedence Priority 1
+#VALUE Annex-Inbound-Precedence Immediate 2
+#VALUE Annex-Inbound-Precedence Flash 3
+#VALUE Annex-Inbound-Precedence Flash-Override 4
+#VALUE Annex-Inbound-Precedence CRITIC/ECP 5
+#VALUE Annex-Inbound-Precedence Internetwork-Control 6
+#VALUE Annex-Inbound-Precedence Network-Control 7
+
+#VALUE Annex-Outbound-Precedence Routine 0
+#VALUE Annex-Outbound-Precedence Priority 1
+#VALUE Annex-Outbound-Precedence Immediate 2
+#VALUE Annex-Outbound-Precedence Flash 3
+#VALUE Annex-Outbound-Precedence Flash-Override 4
+#VALUE Annex-Outbound-Precedence CRITIC/ECP 5
+#VALUE Annex-Outbound-Precedence Internetwork-Control 6
+#VALUE Annex-Outbound-Precedence Network-Control 7
+
+#VALUE Annex-Gwy-Selection-Mode Normal 0
+#VALUE Annex-Gwy-Selection-Mode Backup 1
+#VALUE Annex-Gwy-Selection-Mode Distribution 2
+
+#VALUE Annex-Pool-Id Pool-One 1
+#VALUE Annex-Pool-Id Pool-Two 2
+#VALUE Annex-Pool-Id Pool-Three 3
+#VALUE Annex-Pool-Id Pool-Four 4
+#VALUE Annex-Pool-Id Pool-Five 5
+#VALUE Annex-Pool-Id Pool-Six 6
+
+VALUE Annex-User-Level Manager 2
+VALUE Annex-User-Level User 4
+VALUE Annex-User-Level Operator 8
+
+VALUE Annex-Audit-Level Manager 2
+VALUE Annex-Audit-Level User 4
+VALUE Annex-Audit-Level Operator 8
+
+END-VENDOR Bay-Networks
+
+#
+# Define additional Bay Networks specific values for the main
+# RADIUS dictionary
+#
+# Note that '0x0630' == 1584, which is the Vendor-ID for Bay Networks.
+# Nice design, and probably the best way of adding vendor-specific
+# VALUE extensions to the standard RADIUS attributes.
+#
+
+VALUE Service-Type Annex-Authorize-Only 0x06300001
+VALUE Service-Type Annex-Framed-Tunnel 0x06300002
+
+VALUE Acct-Status-Type Annex-User-Reject 0x06300001
+VALUE Acct-Status-Type Annex-Call-Reject 0x06300002
+VALUE Acct-Status-Type Annex-IPCP-Start 0x06300003
+VALUE Acct-Status-Type Annex-IPXCP-Start 0x06300004
+VALUE Acct-Status-Type Annex-ATCP-Start 0x06300005
+VALUE Acct-Status-Type Annex-Accounting-Restart 0x06300006
+VALUE Acct-Status-Type Annex-Accounting-Shutoff 0x06300007
+VALUE Acct-Status-Type Annex-Tunnel-Start 0x06300008
+VALUE Acct-Status-Type Annex-Tunnel-Stop 0x06300009
+VALUE Acct-Status-Type Annex-Tunnel-Reject 0x0630000a
+VALUE Acct-Status-Type Annex-Tunnel-Link-Start 0x0630000b
+VALUE Acct-Status-Type Annex-Tunnel-Link-Stop 0x0630000c
+VALUE Acct-Status-Type Annex-MP-Start 0x0630000d
+VALUE Acct-Status-Type Annex-MP-Stop 0x0630000e
+VALUE Acct-Status-Type Annex-Line-Seizure 0x0630000f
+VALUE Acct-Status-Type Annex-Rlogin-Start 0x06300010
+VALUE Acct-Status-Type Annex-Rlogin-Stop 0x06300011
+
diff --git a/share/dictionary.bigswitch b/share/dictionary.bigswitch
new file mode 100644
index 0000000..e6c4ccd
--- /dev/null
+++ b/share/dictionary.bigswitch
@@ -0,0 +1,17 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+######################################################################
+# Big Switch Networks (BSN) Dictionary
+# Author: Nitin Madhok <nmadhok@g.clemson.edu>
+# Version: $Id$
+######################################################################
+
+VENDOR Big-Switch-Networks 37538
+BEGIN-VENDOR Big-Switch-Networks
+
+ATTRIBUTE BSN-User-Role 1 string
+ATTRIBUTE BSN-AVPair 2 string
+
+END-VENDOR Big-Switch-Networks
diff --git a/share/dictionary.bintec b/share/dictionary.bintec
new file mode 100644
index 0000000..20c3499
--- /dev/null
+++ b/share/dictionary.bintec
@@ -0,0 +1,49 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Bintec dictionary
+# $Id$
+#
+#
+#
+VENDOR BinTec 272
+
+# (272 << 16) | N
+#
+VALUE Framed-Protocol Bintec-X25 0x01100002
+VALUE Framed-Protocol Bintec-X25-PPP 0x01100003
+VALUE Framed-Protocol Bintec-IP-LAPB 0x01100004
+VALUE Framed-Protocol Bintec-IP-HDLC 0x01100006
+VALUE Framed-Protocol Bintec-MPR-LAPB 0x01100007
+VALUE Framed-Protocol Bintec-MPR-HDLC 0x01100008
+VALUE Framed-Protocol Bintec-FRAME-RELAY 0x01100009
+VALUE Framed-Protocol Bintec-X31-BCHAN 0x0110000a
+VALUE Framed-Protocol Bintec-X75-PPP 0x0110000b
+VALUE Framed-Protocol Bintec-X75BTX-PPP 0x0110000c
+VALUE Framed-Protocol Bintec-X25-NOSIG 0x0110000d
+VALUE Framed-Protocol Bintec-X25-PPP-OPT 0x0110000e
+
+#
+#
+BEGIN-VENDOR BinTec
+
+ATTRIBUTE BinTec-biboPPPTable 224 string
+ATTRIBUTE BinTec-biboDialTable 225 string
+ATTRIBUTE BinTec-ipExtIfTable 226 string
+ATTRIBUTE BinTec-ipRouteTable 227 string
+ATTRIBUTE BinTec-ipExtRtTable 228 string
+ATTRIBUTE BinTec-ipNatPresetTable 229 string
+ATTRIBUTE BinTec-ipxCircTable 230 string
+ATTRIBUTE BinTec-ripCircTable 231 string
+ATTRIBUTE BinTec-sapCircTable 232 string
+ATTRIBUTE BinTec-ipxStaticRouteTable 233 string
+ATTRIBUTE BinTec-ipxStaticServTable 234 string
+ATTRIBUTE BinTec-ospfIfTable 235 string
+ATTRIBUTE BinTec-pppExtIfTable 236 string
+ATTRIBUTE BinTec-ipFilterTable 237 string
+ATTRIBUTE BinTec-ipQoSTable 238 string
+ATTRIBUTE BinTec-qosIfTable 239 string
+ATTRIBUTE BinTec-qosPolicyTable 240 string
+
+END-VENDOR BinTec
diff --git a/share/dictionary.bluecoat b/share/dictionary.bluecoat
new file mode 100644
index 0000000..0af3c51
--- /dev/null
+++ b/share/dictionary.bluecoat
@@ -0,0 +1,27 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# BlueCoat VSAs
+#
+# See also dictionary.packeteer for former Packeteer products.
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR BlueCoat 14501
+
+BEGIN-VENDOR BlueCoat
+
+# Accepts multiple groups as comma-separated list.
+ATTRIBUTE Blue-Coat-Group 1 string
+ATTRIBUTE Blue-Coat-Authorization 2 integer
+
+VALUE Blue-Coat-Authorization No-Access 0
+VALUE Blue-Coat-Authorization Read-Only-Access 1
+VALUE Blue-Coat-Authorization Read-Write-Access 2
+
+END-VENDOR BlueCoat
diff --git a/share/dictionary.boingo b/share/dictionary.boingo
new file mode 100644
index 0000000..420e858
--- /dev/null
+++ b/share/dictionary.boingo
@@ -0,0 +1,48 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+# Boingo Wi-Fi - http://www.boingo.com/
+#
+# Version: $Id:
+#
+# Jorge Pereira <jpereiran@gmail.com>
+#
+##############################################################################
+
+VENDOR Boingo 22472
+
+BEGIN-VENDOR Boingo
+
+ATTRIBUTE BW-Venue-Id 7 string
+ATTRIBUTE BW-Venue-TZ 8 string
+ATTRIBUTE BW-Service-Type 9 string
+ATTRIBUTE BW-Class 10 string
+ATTRIBUTE BW-Venue-Description 11 string
+ATTRIBUTE BW-Venue-Price-Type 12 string
+ATTRIBUTE BW-Venue-Port-Type 13 string
+ATTRIBUTE BW-ISO-Country-Code 14 string
+ATTRIBUTE BW-e164-Country-Code 15 string
+ATTRIBUTE BW-State-Name 16 string
+ATTRIBUTE BW-City-Name 17 string
+ATTRIBUTE BW-Area-Code 18 integer
+ATTRIBUTE CL-Brand 19 string
+ATTRIBUTE CL-Software-Version 20 string
+ATTRIBUTE CL-Reg-Number 21 string
+ATTRIBUTE CL-Method-Version 22 string
+ATTRIBUTE CL-Token-Version 23 string
+ATTRIBUTE CL-APDB-Version 24 string
+ATTRIBUTE CL-User-Agent 25 string
+ATTRIBUTE CL-SSC 26 string
+ATTRIBUTE BW-User-Group 27 string
+ATTRIBUTE BW-Venue-Name 29 string
+ATTRIBUTE BW-Category 30 string
+ATTRIBUTE BW-User-Role 32 string
+ATTRIBUTE BW-User-Name 33 string
+ATTRIBUTE BW-User-Password 34 string
+ATTRIBUTE BW-User-Prefix 35 string
+ATTRIBUTE BW-User-Realm 36 string
+ATTRIBUTE BW-Operator-Name 37 string
+
+END-VENDOR Boingo
diff --git a/share/dictionary.bristol b/share/dictionary.bristol
new file mode 100644
index 0000000..d2fe1f1
--- /dev/null
+++ b/share/dictionary.bristol
@@ -0,0 +1,23 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# RoamNode VSA's
+#
+# Version: $Id$
+#
+
+VENDOR Bristol 4363
+
+#
+# Standard attribute
+#
+BEGIN-VENDOR Bristol
+
+ATTRIBUTE NN-Data-Rate 1 integer
+ATTRIBUTE NN-Data-Rate-Ceiling 2 integer
+ATTRIBUTE NN-Homenode 3 ipaddr
+ATTRIBUTE NN-Homeservice 4 ipaddr
+ATTRIBUTE NN-Homeservice-Name 5 string
+
+END-VENDOR Bristol
diff --git a/share/dictionary.broadsoft b/share/dictionary.broadsoft
new file mode 100644
index 0000000..40520c4
--- /dev/null
+++ b/share/dictionary.broadsoft
@@ -0,0 +1,371 @@
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+
+VENDOR BroadSoft 6431
+
+BEGIN-VENDOR BroadSoft
+
+#ATTRIBUTE BWAS-Call-Detail-Record-Version 0 string
+ATTRIBUTE BWAS-Record-id 1 string
+ATTRIBUTE BWAS-Service-provider 2 string
+ATTRIBUTE BWAS-Type 3 string
+ATTRIBUTE BWAS-User-Number 4 string
+ATTRIBUTE BWAS-Group-Number 5 string
+ATTRIBUTE BWAS-Direction 6 string
+ATTRIBUTE BWAS-Calling-Number 7 string
+ATTRIBUTE BWAS-Calling-Presentation-Indic 8 string
+ATTRIBUTE BWAS-Called-Number 9 string
+ATTRIBUTE BWAS-Start-Time 10 string
+ATTRIBUTE BWAS-User-Timezone 11 string
+ATTRIBUTE BWAS-Answer-Indic 12 string
+ATTRIBUTE BWAS-Answer-Time 13 string
+ATTRIBUTE BWAS-Release-Time 14 string
+ATTRIBUTE BWAS-Termination-Cause 15 string
+ATTRIBUTE BWAS-Network-Type 16 string
+ATTRIBUTE BWAS-Carrier-Identification-Code 17 string
+ATTRIBUTE BWAS-Dialed-Digits 18 string
+ATTRIBUTE BWAS-Call-Category 19 string
+ATTRIBUTE BWAS-Network-Call-Type 20 string
+ATTRIBUTE BWAS-Network-Translated-Number 21 string
+ATTRIBUTE BWAS-Network-Translated-Group 22 string
+ATTRIBUTE BWAS-Releasing-Party 23 string
+ATTRIBUTE BWAS-Route 24 string
+ATTRIBUTE BWAS-Network-Callid 25 string
+ATTRIBUTE BWAS-Codec 26 string
+ATTRIBUTE BWAS-Access-Device-Address 27 string
+ATTRIBUTE BWAS-Access-Callid 28 string
+ATTRIBUTE BWAS-Spare-29 29 string
+ATTRIBUTE BWAS-Failover-Correlation-Id 30 string
+ATTRIBUTE BWAS-Spare-31 31 string
+ATTRIBUTE BWAS-Group 32 string
+ATTRIBUTE BWAS-Department 33 string
+ATTRIBUTE BWAS-Account-Code 34 string
+ATTRIBUTE BWAS-Authorization-Code 35 string
+ATTRIBUTE BWAS-Original-Called-Number 36 string
+ATTRIBUTE BWAS-Original-Called-Presentation-Indic 37 string
+ATTRIBUTE BWAS-Original-Called-Reason 38 string
+ATTRIBUTE BWAS-Redirecting-Number 39 string
+ATTRIBUTE BWAS-Redirecting-Presentation-Indic 40 string
+ATTRIBUTE BWAS-Redirecting-Reason 41 string
+ATTRIBUTE BWAS-Charge-Indic 42 string
+ATTRIBUTE BWAS-Type-Of-Network 43 string
+ATTRIBUTE BWAS-VP-Calling-Invoke-Time 44 string
+ATTRIBUTE BWAS-Local-Callid 45 string
+ATTRIBUTE BWAS-Remote-Callid 46 string
+ATTRIBUTE BWAS-Calling-Party-Category 47 string
+ATTRIBUTE BWAS-Conference-Invoke-Time 48 string
+ATTRIBUTE BWAS-Conference-Callid 49 string
+ATTRIBUTE BWAS-Conference-To 50 string
+ATTRIBUTE BWAS-Conference-From 51 string
+ATTRIBUTE BWAS-Conference-Id 52 string
+ATTRIBUTE BWAS-Conference-Role 53 string
+ATTRIBUTE BWAS-Conference-Bridge 54 string
+ATTRIBUTE BWAS-Conference-Owner 55 string
+ATTRIBUTE BWAS-Conference-Owner-Dn 56 string
+ATTRIBUTE BWAS-Conference-Title 57 string
+ATTRIBUTE BWAS-Conference-Project-Code 58 string
+ATTRIBUTE BWAS-Charging-Vector-Key 59 string
+ATTRIBUTE BWAS-Charging-Vection-Creator 60 string
+ATTRIBUTE BWAS-Charging-Vection-Orig 61 string
+ATTRIBUTE BWAS-Charging-Vection-Term 62 string
+ATTRIBUTE BWAS-Acc-Per-Call-Invoke-Time 63 string
+ATTRIBUTE BWAS-Acc-Per-Call-Fac-Result 64 string
+ATTRIBUTE BWAS-Acb-Act-Invoke-Time 65 string
+ATTRIBUTE BWAS-Acb-Act-Fac-Result 66 string
+ATTRIBUTE BWAS-Acb-Deact-Invoke-Time 67 string
+ATTRIBUTE BWAS-Acb-Deact-Fac-Result 68 string
+ATTRIBUTE BWAS-Call-Park-Invoke-Time 69 string
+ATTRIBUTE BWAS-Call-Park-Fac-Result 70 string
+ATTRIBUTE BWAS-Call-Park-Retr-Invoke-Time 71 string
+ATTRIBUTE BWAS-Call-Park-Retr-Fac-Result 72 string
+ATTRIBUTE BWAS-Call-Pickup-Invoke-Time 73 string
+ATTRIBUTE BWAS-Call-Pickup-Fac-Result 74 string
+ATTRIBUTE BWAS-Directed-Call-Pickup-Invoke-Time 75 string
+ATTRIBUTE BWAS-Directed-Call-Pickup-Fac-Result 76 string
+ATTRIBUTE BWAS-Dpubi-Invoke-Time 77 string
+ATTRIBUTE BWAS-Dpubi-Fac-Result 78 string
+ATTRIBUTE BWAS-Cancel-Cwt-Per-Call-Invoke-Time 79 string
+ATTRIBUTE BWAS-Cancel-Cwt-Per-Call-Fac-Result 80 string
+ATTRIBUTE BWAS-Cfa-Act-Invoke-Time 81 string
+ATTRIBUTE BWAS-Cfa-Act-Fac-Result 82 string
+ATTRIBUTE BWAS-Cfa-Deact-Invoke-Time 83 string
+ATTRIBUTE BWAS-Cfa-Deact-Fac-Result 84 string
+ATTRIBUTE BWAS-Cfb-Act-Invoke-Time 85 string
+ATTRIBUTE BWAS-Cfb-Act-Fac-Result 86 string
+ATTRIBUTE BWAS-Cfb-Deact-Invoke-Time 87 string
+ATTRIBUTE BWAS-Cfb-Deact-Fac-Result 88 string
+ATTRIBUTE BWAS-Cfna-Act-Invoke-Time 89 string
+ATTRIBUTE BWAS-Cfna-Act-Fac-Result 90 string
+ATTRIBUTE BWAS-Cfna-Deact-Invoke-Time 91 string
+ATTRIBUTE BWAS-Cfna-Deact-Fac-Result 92 string
+ATTRIBUTE BWAS-Clid-Delivery-Per-Call-Invoke-Time 93 string
+ATTRIBUTE BWAS-Clid-Delivery-Per-Call-Fac-Result 94 string
+ATTRIBUTE BWAS-Clid-Blocking-Per-Call-Invoke-Time 95 string
+ATTRIBUTE BWAS-Clid-Blocking-Per-Call-Fac-Result 96 string
+ATTRIBUTE BWAS-Cot-Invoke-Time 97 string
+ATTRIBUTE BWAS-Cot-Fac-Result 98 string
+ATTRIBUTE BWAS-Direct-Vm-Xfer-Invoke-Time 99 string
+ATTRIBUTE BWAS-Direct-Vm-Xfer-Fac-Result 100 string
+ATTRIBUTE BWAS-Dnd-Act-Invoke-Time 101 string
+ATTRIBUTE BWAS-Dnd-Act-Fac-Result 102 string
+ATTRIBUTE BWAS-Dnd-Deact-Invoke-Time 103 string
+ATTRIBUTE BWAS-Dnd-Deact-Fac-Result 104 string
+ATTRIBUTE BWAS-Sac-Lock-Invoke-Time 105 string
+ATTRIBUTE BWAS-Sac-Lock-Fac-Result 106 string
+ATTRIBUTE BWAS-Sac-Unlock-Invoke-Time 107 string
+ATTRIBUTE BWAS-Sac-Unlock-Fac-Result 108 string
+ATTRIBUTE BWAS-Flash-Call-Hold-Invoke-Time 109 string
+ATTRIBUTE BWAS-Flash-Call-Hold-Fac-Result 110 string
+ATTRIBUTE BWAS-Last-Number-Redial-Invoke-Time 111 string
+ATTRIBUTE BWAS-Last-Number-Redial-Fac-Result 112 string
+ATTRIBUTE BWAS-Return-Call-Invoke-Time 113 string
+ATTRIBUTE BWAS-Return-Call-Fac-Result 114 string
+ATTRIBUTE BWAS-Sd100-Programming-Invoke-Time 115 string
+ATTRIBUTE BWAS-Sd100-Programming-Fac-Result 116 string
+ATTRIBUTE BWAS-Sd8-Programming-Invoke-Time 117 string
+ATTRIBUTE BWAS-Sd8-Programming-Fac-Result 118 string
+ATTRIBUTE BWAS-Clear-Mwi-Invoke-Time 119 string
+ATTRIBUTE BWAS-Clear-Mwi-Fac-Result 120 string
+ATTRIBUTE BWAS-UserId 121 string
+ATTRIBUTE BWAS-Other-Party-Name 122 string
+ATTRIBUTE BWAS-Other-Party-Name-Pres-Indic 123 string
+ATTRIBUTE BWAS-Moh-Deact-Fac-Result 125 string
+ATTRIBUTE BWAS-Push-to-Talk-Invoke-Time 126 string
+ATTRIBUTE BWAS-Push-to-Talk-Fac-Result 127 string
+ATTRIBUTE BWAS-Hoteling-Invoke-Time 128 string
+ATTRIBUTE BWAS-Hoteling-Group 129 string
+ATTRIBUTE BWAS-Hoteling-UserId 130 string
+ATTRIBUTE BWAS-Hoteling-User-Number 131 string
+ATTRIBUTE BWAS-Hoteling-Group-Number 132 string
+ATTRIBUTE BWAS-Diversion-Inhibitor-Invoke-time 133 string
+ATTRIBUTE BWAS-Diversion-Inhibitor-Fac-Result 134 string
+ATTRIBUTE BWAS-Trunk-Group-Name 135 string
+ATTRIBUTE BWAS-Spare-136 136 string
+ATTRIBUTE BWAS-InstantGroupCall-Invoke-Time 137 string
+ATTRIBUTE BWAS-InstantGroupCall-PushToTalk 138 string
+ATTRIBUTE BWAS-InstantGroupCall-Related-Callid 139 string
+ATTRIBUTE BWAS-CustomRingback-Invoke-Time 140 string
+ATTRIBUTE BWAS-CLID-Permitted 141 string
+ATTRIBUTE BWAS-AHR-Invoke-Time 142 string
+ATTRIBUTE BWAS-AHR-Action 143 string
+ATTRIBUTE BWAS-Access-Network-Info 144 string
+ATTRIBUTE BWAS-Charging-Function-Addresses 145 string
+ATTRIBUTE BWAS-Charge-Number 146 string
+ATTRIBUTE BWAS-Related-CallId 147 string
+ATTRIBUTE BWAS-Related-CallId-Reason 148 string
+ATTRIBUTE BWAS-Transfer-Invoke-Time 149 string
+ATTRIBUTE BWAS-Transfer-Result 150 string
+ATTRIBUTE BWAS-Transfer-Related-CallId 151 string
+ATTRIBUTE BWAS-Transfer-Type 152 string
+ATTRIBUTE BWAS-Conf-Start-Time 153 string
+ATTRIBUTE BWAS-Conf-Stop-Time 154 string
+ATTRIBUTE BWAS-Conf-Id 155 string
+ATTRIBUTE BWAS-Conf-Type 156 string
+ATTRIBUTE BWAS-Codec-Usage 157 string
+ATTRIBUTE BWAS-Vmb-Act-Invoke-Time 158 string
+ATTRIBUTE BWAS-Vmb-Act-Fac-Result 159 string
+ATTRIBUTE BWAS-Vmb-Deact-Invoke-Time 160 string
+ATTRIBUTE BWAS-Vmb-Deact-Fac-Result 161 string
+ATTRIBUTE BWAS-Vmna-Act-Invoke-Time 162 string
+ATTRIBUTE BWAS-Vmna-Act-Fac-Result 163 string
+ATTRIBUTE BWAS-Vmna-Deact-Invoke-Time 164 string
+ATTRIBUTE BWAS-Vmna-Deact-Fac-Result 165 string
+ATTRIBUTE BWAS-Vma-Act-Invoke-Time 166 string
+ATTRIBUTE BWAS-Vma-Act-Fac-Result 167 string
+ATTRIBUTE BWAS-Vma-Deact-Invoke-Time 168 string
+ATTRIBUTE BWAS-Vma-Deact-Fac-Result 169 string
+ATTRIBUTE BWAS-No-Answer-Set-Invoke-Time 170 string
+ATTRIBUTE BWAS-No-Answer-Set-Fac-Result 171 string
+ATTRIBUTE BWAS-Clid-Blocking-Act-Invoke-Time 172 string
+ATTRIBUTE BWAS-Clid-Blocking-Act-Fac-Result 173 string
+ATTRIBUTE BWAS-Clid-Blocking-Deact-Invoke-Time 174 string
+ATTRIBUTE BWAS-Clid-Blocking-Deact-Fac-Result 175 string
+ATTRIBUTE BWAS-Call-Waiting-Act-Invoke-Time 176 string
+ATTRIBUTE BWAS-Call-Waiting-Act-Fac-Result 177 string
+ATTRIBUTE BWAS-Call-Waiting-Deact-Invoke-Time 178 string
+ATTRIBUTE BWAS-Call-Waiting-Deact-Fac-Result 179 string
+ATTRIBUTE BWAS-Fax-Messaging 180 string
+ATTRIBUTE BWAS-TSD-Digits 181 string
+ATTRIBUTE BWAS-Trunk-Group-Info 182 string
+ATTRIBUTE BWAS-Recall-Type 183 string
+ATTRIBUTE BWAS-Cfnrc-Act-Invoke-Time 184 string
+ATTRIBUTE BWAS-Cfnrc-Act-Fac-Result 185 string
+ATTRIBUTE BWAS-Cfnrc-Deact-Invoke-Time 186 string
+ATTRIBUTE BWAS-Cfnrc-Deact-Fac-Result 187 string
+ATTRIBUTE BWAS-Q850-Cause 188 string
+ATTRIBUTE BWAS-Dialed-Digits-Context 189 string
+ATTRIBUTE BWAS-Called-Number-Context 190 string
+ATTRIBUTE BWAS-Network-Translated-Number-Context 191 string
+ATTRIBUTE BWAS-Calling-Number-Context 192 string
+ATTRIBUTE BWAS-Original-Called-Number-Context 193 string
+ATTRIBUTE BWAS-Redirecting-Number-Context 194 string
+ATTRIBUTE BWAS-Location-Control-Act-Result 195 string
+ATTRIBUTE BWAS-Location-Control-Deact-Result 196 string
+ATTRIBUTE BWAS-Call-Retrieve-Result 197 string
+ATTRIBUTE BWAS-Routing-Number 198 string
+ATTRIBUTE BWAS-Origination-Method 199 string
+ATTRIBUTE BWAS-Call-Parked-Invoke-Time 200 string
+ATTRIBUTE BWAS-BA-Related-Call-Id 201 string
+ATTRIBUTE BWAS-Acr-Act-Invoke-Time 202 string
+ATTRIBUTE BWAS-Acr-Act-Fac-Result 203 string
+ATTRIBUTE BWAS-Acr-Deact-Invoke-Time 204 string
+ATTRIBUTE BWAS-Acr-Deact-Fac-Result 205 string
+ATTRIBUTE BWAS-Outside-Access-Code 206 string
+ATTRIBUTE BWAS-Primary-Device-Line-Port 207 string
+ATTRIBUTE BWAS-Called-Asserted-Identity 208 string
+ATTRIBUTE BWAS-Called-Asserted-Pres-Indicator 209 string
+ATTRIBUTE BWAS-SDP 210 string
+ATTRIBUTE BWAS-Media-Initiator-Flag 211 string
+ATTRIBUTE BWAS-SDP-Offer-Timestamp 212 string
+ATTRIBUTE BWAS-SDP-Answer-Timestamp 213 string
+ATTRIBUTE BWAS-Early-Media-SDP 214 string
+ATTRIBUTE BWAS-Early-Media-Initiator-Flag 215 string
+ATTRIBUTE BWAS-Body-Content-Type 216 string
+ATTRIBUTE BWAS-Body-Content-Length 217 string
+ATTRIBUTE BWAS-Body-Content-Disposition 218 string
+ATTRIBUTE BWAS-Body-Originator 219 string
+ATTRIBUTE BWAS-SIP-Error-Code 220 string
+ATTRIBUTE BWAS-OtherInfoInPCV 221 string
+ATTRIBUTE BWAS-Received-Calling-Number 222 string
+ATTRIBUTE BWAS-CustomRingback-Media-Selection 223 string
+ATTRIBUTE BWAS-AOC-Type 224 string
+ATTRIBUTE BWAS-AOC-Charge 225 string
+ATTRIBUTE BWAS-AOC-Currency 226 string
+ATTRIBUTE BWAS-AOC-Time 227 string
+ATTRIBUTE BWAS-AOC-Sum 228 string
+ATTRIBUTE BWAS-AOC-Activation-Time 229 string
+ATTRIBUTE BWAS-AOC-Result 230 string
+ATTRIBUTE BWAS-AS-Call-Type 231 string
+ATTRIBUTE BWAS-Scf-Act-Invoke-Time 232 string
+ATTRIBUTE BWAS-Scf-Act-Fac-Result 233 string
+ATTRIBUTE BWAS-Scf-Deact-Invoke-Time 234 string
+ATTRIBUTE BWAS-Scf-Deact-Fac-Result 235 string
+ATTRIBUTE BWAS-Cfa-Inter-Invoke-Time 236 string
+ATTRIBUTE BWAS-Cfa-Inter-Fac-Result 237 string
+ATTRIBUTE BWAS-Cfna-Inter-Invoke-Time 238 string
+ATTRIBUTE BWAS-Cfna-Inter-Fac-Result 239 string
+ATTRIBUTE BWAS-Cfb-Inter-Invoke-Time 240 string
+ATTRIBUTE BWAS-Cfb-Inter-Fac-Result 241 string
+ATTRIBUTE BWAS-CBF-Auth-Code 242 string
+ATTRIBUTE BWAS-Call-Bridge-Result 243 string
+ATTRIBUTE BWAS-Return-Call-Number-Deletion-Invoke-Time 244 string
+ATTRIBUTE BWAS-Return-Call-Number-Deletion-Fac-Result 245 string
+ATTRIBUTE BWAS-Prepaid-Status 246 string
+ATTRIBUTE BWAS-Configurable-CLID 247 string
+ATTRIBUTE BWAS-Call-Center-Night-Service-Act-Result 248 string
+ATTRIBUTE BWAS-Call-Center-Night-Service-Deact-Result 249 string
+ATTRIBUTE BWAS-Call-Center-Forced-Forwarding-Act-Result 250 string
+ATTRIBUTE BWAS-Call-Center-Forced-Forwarding-Deact-Result 251 string
+ATTRIBUTE BWAS-Call-Center-Outgoing-Call-Fac-Result 252 string
+ATTRIBUTE BWAS-Call-Center-Outgoing-Personal-Call-Fac-Result 253 string
+ATTRIBUTE BWAS-Call-Center-Outgoing-Phone-Number 254 string
+ATTRIBUTE BroadSoft-Attr-255 255 string
+
+#
+# These are "special" attributes. They get sent in Broadsoft-Attr-255,
+# with their number as the leading value. e.g.
+#
+# Broadsoft-Attr-255 = "256=12345"
+#
+# Which means "BWAS-Intercept-Group-Routing-Number" has value 12345.
+#
+# No other vendor does this, for the simple reason that it's
+# ridiculous.
+#
+#ATTRIBUTE BWAS-Intercept-Group-Routing-Number 256 string
+#ATTRIBUTE BWAS-CB-Activation-Invoke-Time 257 string
+#ATTRIBUTE BWAS-CB-Activation-Fac-Result 258 string
+#ATTRIBUTE BWAS-CB-Deactivation-Invoke-Time 259 string
+#ATTRIBUTE BWAS-CB-Deactivation-Fac-Result 260 string
+#ATTRIBUTE BWAS-CB-Query-Invoke-Time 261 string
+#ATTRIBUTE BWAS-CB-Query-Fac-Result 262 string
+#ATTRIBUTE BWAS-Cfnrc-Inter-Invoke-Time 263 string
+#ATTRIBUTE BWAS-Cfnrc-Inter-Fac-Result 264 string
+#ATTRIBUTE BWAS-VMR-Dialing-Invoke-Time 265 string
+#ATTRIBUTE BWAS-VMR-Dialing-Fac-result 266 string
+#ATTRIBUTE BWAS-VP-Dialing-Invoke-Time 267 string
+#ATTRIBUTE BWAS-VP-Dialing-Fac-result 268 string
+#ATTRIBUTE BWAS-Camel-Loc-Info 269 string
+#ATTRIBUTE BWAS-Camel-Msc-Address 270 string
+#ATTRIBUTE BWAS-Camel-CellId-Or-LAI 271 string
+#ATTRIBUTE BWAS-NAME-Permitted 272 string
+#ATTRIBUTE BWAS-Call-Center-User-Id 273 string
+#ATTRIBUTE BWAS-Call-Center-Outgoing-Group-Phone-Number 274 string
+#ATTRIBUTE BWAS-VON-Type 275 string
+#ATTRIBUTE BWAS-PreAlertingAnncmtDuration 276 string
+#ATTRIBUTE BWAS-CC-Disp-Code-Tagging-Invoke-Time 277 string
+#ATTRIBUTE BWAS-CC-Disp-Code-Tagging-Result 278 string
+#ATTRIBUTE BWAS-CC-Escalated-Call-Invoke-Time 279 string
+#ATTRIBUTE BWAS-CC-Escalated-Call-FAC-Result 280 string
+#ATTRIBUTE BWAS-CC-Monitoring-BI-Invoke-Time 281 string
+#ATTRIBUTE BWAS-CC-Monitoring-BI-FAC-Result 282 string
+#ATTRIBUTE BWAS-Mid-Call-Cot-Invoke-Time 283 string
+#ATTRIBUTE BWAS-Office-Zone 284 string
+#ATTRIBUTE BWAS-Primary-Zone 285 string
+#ATTRIBUTE BWAS-Roaming-MSC-Address 286 string
+#ATTRIBUTE BWAS-CC-Emergency-Call-Invoke-Time 287 string
+#ATTRIBUTE BWAS-Monitoring-Next-Call-Invoke-Time 288 string
+#ATTRIBUTE BWAS-Monitoring-Next-Call-FAC-Result 289 string
+#ATTRIBUTE BWAS-Legacy-Acb-Act-Invoke-Time 290 string
+#ATTRIBUTE BWAS-Legacy-Acb-Act-Fac-Result 291 string
+#ATTRIBUTE BWAS-Legacy-Acb-Deact-Invoke-Time 292 string
+#ATTRIBUTE BWAS-Legacy-Acb-Deact-Fac-Result 293 string
+#ATTRIBUTE BWAS-Custom-Schema-Version 294 string
+#ATTRIBUTE BWAS-Group-Paging-Invoke-Time 295 string
+#ATTRIBUTE BWAS-Group-Paging-Related-CallId 296 string
+#ATTRIBUTE BWAS-DCLID 297 string
+#ATTRIBUTE BWAS-MeetMeConferencing-InvokeTime 298 string
+#ATTRIBUTE BWAS-Call-Me-Now-Type 299 string
+#ATTRIBUTE BWAS-Call-Me-Now-Transaction-Id 300 string
+#ATTRIBUTE BWAS-Call-Me-Now-Related-Call-Id 301 string
+#ATTRIBUTE BWAS-MeetMeConferencing-ConferenceId 302 string
+#ATTRIBUTE BWAS-MeetMeConferencing-Role 303 string
+#ATTRIBUTE BWAS-MeetMeConferencing-Bridge 304 string
+#ATTRIBUTE BWAS-MeetMeConferencing-Owner 305 string
+#ATTRIBUTE BWAS-MeetMeConferencing-OwnerDn 306 string
+#ATTRIBUTE BWAS-MeetMeConferencing-Title 307 string
+#ATTRIBUTE BWAS-MeetMeConferencing-ProjectCode 308 string
+#ATTRIBUTE BWAS-MeetMeConferencing-RecordDuration 309 string
+#ATTRIBUTE BWAS-MobilityNumber 310 string
+#ATTRIBUTE BWAS-MobilityRoutingNumber 311 string
+#ATTRIBUTE BWAS-Location 312 string
+#ATTRIBUTE BWAS-Location-Type 313 string
+#ATTRIBUTE BWAS-Location-Usage 314 string
+#ATTRIBUTE BWAS-Call-Recording-Invocation-Time 315 string
+#ATTRIBUTE BWAS-Call-Recording-FAC-Result 316 string
+#ATTRIBUTE BWAS-Call-Recording-Trigger 317 string
+#ATTRIBUTE BWAS-Call-Recording-Destination 318 string
+#ATTRIBUTE BWAS-Call-Recording-Result 319 string
+#ATTRIBUTE BWAS-Calling-Pres-Number 320 string
+#ATTRIBUTE BWAS-Calling-Pres-Number-Context 321 string
+#ATTRIBUTE BWAS-Calling-Asserted-Number 322 string
+#ATTRIBUTE BWAS-Calling-Asserted-Number-Context 323 string
+#ATTRIBUTE BWAS-SCC-Invocation-Time 324 string
+#ATTRIBUTE BWAS-SCC-Call-Id 325 string
+#ATTRIBUTE BWAS-SCC-Number 326 string
+#ATTRIBUTE BWAS-Acr-Inter-Invoke-Time 327 string
+#ATTRIBUTE BWAS-Acr-Inter-Fac-Result 328 string
+#ATTRIBUTE BWAS-CW-Inter-Invoke-Time 329 string
+#ATTRIBUTE BWAS-CW-Inter-Fac-Result 330 string
+#ATTRIBUTE BWAS-Clid-Blocking-Inter-Invoke-Time 331 string
+#ATTRIBUTE BWAS-Clid-Blocking-Inter-Fac-Result 332 string
+#ATTRIBUTE BWAS-Colr-Inter-Invoke-Time 333 string
+#ATTRIBUTE BWAS-Colr-Inter-Fac-Result 334 string
+#ATTRIBUTE BWAS-Scr-Inter-Invoke-Time 335 string
+#ATTRIBUTE BWAS-Scr-Inter-Fac-Result 336 string
+#ATTRIBUTE BWAS-HuntGroupBusy-Activation-Invocation-Time 337 string
+#ATTRIBUTE BWAS-HuntGroupBusy-Activation-FAC-Result 338 string
+#ATTRIBUTE BWAS-HuntGroupBusy-Activation-Target-HuntGroupId 339 string
+#ATTRIBUTE BWAS-HuntGroupBusy-Deactivation-Invocation-Time 340 string
+#ATTRIBUTE BWAS-HuntGroupBusy-Deactivation-FAC-Result 341 string
+#ATTRIBUTE BWAS-HuntGroupBusy-Deactivation-Target-HuntGroupId 342 string
+#ATTRIBUTE BWAS-HuntGroupBusy-Interrogation-Invocation-Time 343 string
+#ATTRIBUTE BWAS-HuntGroupBusy-Interrogation-FAC-Result 344 string
+#ATTRIBUTE BWAS-HuntGroupBusy-Interrogation-Target-HuntGroupId 345 string
+#ATTRIBUTE BWAS-User-Agent 346 string
+#ATTRIBUTE BWAS-FMFM-Call-Push-Invocation-Time 347 string
+#ATTRIBUTE BWAS-FMFM-Call-Push-FAC-Result 348 string
+#ATTRIBUTE BWAS-SCC-Cause 349 string
+
+END-VENDOR BroadSoft
diff --git a/share/dictionary.brocade b/share/dictionary.brocade
new file mode 100644
index 0000000..cf5ae94
--- /dev/null
+++ b/share/dictionary.brocade
@@ -0,0 +1,24 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+VENDOR Brocade 1588
+BEGIN-VENDOR Brocade
+
+ATTRIBUTE Brocade-Auth-Role 1 string
+# Valid attribute values:
+# Admin BasicSwitchAdmin FabricAdmin Operator
+# SecurityAdmin SwitchAdmin User ZoneAdmin
+
+ATTRIBUTE Brocade-AVPairs1 2 string
+ATTRIBUTE Brocade-AVPairs2 3 string
+ATTRIBUTE Brocade-AVPairs3 4 string
+ATTRIBUTE Brocade-AVPairs4 5 string
+# Brocade-AVPairs1/2/3/4:
+# Optional, specifies Admin Domain or Virtual Fabric List
+
+ATTRIBUTE Brocade-Passwd-ExpiryDate 6 string # Format: MM/DD/YYYY
+ATTRIBUTE Brocade-Passwd-WarnPeriod 7 string # Format: integer in days
+
+END-VENDOR Brocade
+
diff --git a/share/dictionary.bskyb b/share/dictionary.bskyb
new file mode 100644
index 0000000..af575a0
--- /dev/null
+++ b/share/dictionary.bskyb
@@ -0,0 +1,26 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# British Sky Broadcasting Group plc VSA's
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR BSkyB 16924
+
+BEGIN-VENDOR BSkyB
+
+ATTRIBUTE Sky-Wifi-AP-ID 1 integer
+ATTRIBUTE Sky-Wifi-Service-ID 2 integer
+ATTRIBUTE Sky-Wifi-Filter-Profile 3 string
+ATTRIBUTE Sky-Wifi-Billing-Class 4 octets
+ATTRIBUTE Sky-Wifi-Provider-ID 5 integer
+ATTRIBUTE Sky-Wifi-Credentials 6 string
+ATTRIBUTE Sky-Wifi-Replicated-Packet 7 string
+ATTRIBUTE Sky-Wifi-Protocol-Restriction 8 integer
+
+END-VENDOR BSkyB
diff --git a/share/dictionary.bt b/share/dictionary.bt
new file mode 100644
index 0000000..61c2dde
--- /dev/null
+++ b/share/dictionary.bt
@@ -0,0 +1,19 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# British Telecom VSA's
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR BT 594
+
+BEGIN-VENDOR BT
+
+ATTRIBUTE SID-Auth 1 string
+
+END-VENDOR BT
diff --git a/share/dictionary.cablelabs b/share/dictionary.cablelabs
new file mode 100644
index 0000000..26f7818
--- /dev/null
+++ b/share/dictionary.cablelabs
@@ -0,0 +1,202 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# CableLabs
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR CableLabs 4491
+
+BEGIN-VENDOR CableLabs
+
+ATTRIBUTE CableLabs-Reserved 0 octets
+ATTRIBUTE CableLabs-Event-Message 1 octets
+ATTRIBUTE CableLabs-MTA-Endpoint-Name 3 string
+ATTRIBUTE CableLabs-Calling-Party-Number 4 string
+ATTRIBUTE CableLabs-Called-Party-Number 5 string
+ATTRIBUTE CableLabs-Database-ID 6 string
+ATTRIBUTE CableLabs-Query-Type 7 integer
+ATTRIBUTE CableLabs-Returned-Number 9 string
+ATTRIBUTE CableLabs-Call-Termination-Cause 11 octets
+
+#ATTRIBUTE CableLabs-Related-Call-Billing-Correlation-ID 13 octets
+ATTRIBUTE CableLabs-Related-Call-Billing-Crl-ID 13 octets
+
+#ATTRIBUTE CableLabs-First-Call-Calling-Party-Number 14 string
+#ATTRIBUTE CableLabs-Second-Call-Calling-Party-Number 15 string
+ATTRIBUTE CableLabs-First-Call-Calling-Party-Num 14 string
+ATTRIBUTE CableLabs-Second-Call-Calling-Party-Num 15 string
+
+ATTRIBUTE CableLabs-Charge-Number 16 string
+ATTRIBUTE CableLabs-Forwarded-Number 17 string
+ATTRIBUTE CableLabs-Service-Name 18 string
+ATTRIBUTE CableLabs-Intl-Code 20 string
+ATTRIBUTE CableLabs-Dial-Around-Code 21 string
+ATTRIBUTE CableLabs-Location-Routing-Number 22 string
+ATTRIBUTE CableLabs-Carrier-Identification-Code 23 string
+ATTRIBUTE CableLabs-Trunk-Group-ID 24 octets
+ATTRIBUTE CableLabs-Routing-Number 25 string
+ATTRIBUTE CableLabs-MTA-UDP-Portnum 26 integer
+ATTRIBUTE CableLabs-Channel-State 29 integer
+ATTRIBUTE CableLabs-SF-ID 30 integer
+ATTRIBUTE CableLabs-Error-Description 31 string
+ATTRIBUTE CableLabs-QoS-Descriptor 32 octets
+ATTRIBUTE CableLabs-Direction-indicator 37 integer
+ATTRIBUTE CableLabs-Time-Adjustment 38 octets
+ATTRIBUTE CableLabs-SDP-Upstream 39 string
+ATTRIBUTE CableLabs-SDP-Downstream 40 string
+ATTRIBUTE CableLabs-User-Input 41 string
+ATTRIBUTE CableLabs-Translation-Input 42 string
+ATTRIBUTE CableLabs-Redirected-From-Info 43 octets
+
+#ATTRIBUTE CableLabs-Electronic-Surveillance-Indication 44 octets
+ATTRIBUTE CableLabs-Electronic-Surveillance-Ind 44 octets
+
+ATTRIBUTE CableLabs-Redirected-From-Party-Number 45 string
+ATTRIBUTE CableLabs-Redirected-To-Party-Number 46 string
+
+#ATTRIBUTE CableLabs-Electronic-Surveillance-DF-Security 47 octets
+ATTRIBUTE CableLabs-El-Surveillance-DF-Security 47 octets
+
+ATTRIBUTE CableLabs-CCC-ID 48 octets
+ATTRIBUTE CableLabs-Financial-Entity-ID 49 string
+ATTRIBUTE CableLabs-Flow-Direction 50 integer
+ATTRIBUTE CableLabs-Signal-Type 51 integer
+ATTRIBUTE CableLabs-Alerting-Signal 52 integer
+ATTRIBUTE CableLabs-Subject-Audible-Signal 53 integer
+ATTRIBUTE CableLabs-Terminal-Display-Info 54 octets
+ATTRIBUTE CableLabs-Switch-Hook-Flash 55 string
+ATTRIBUTE CableLabs-Dialed-Digits 56 string
+ATTRIBUTE CableLabs-Misc-Signaling-Information 57 string
+ATTRIBUTE CableLabs-AM-Opaque-Data 61 integer
+ATTRIBUTE CableLabs-Subscriber-ID 62 integer
+ATTRIBUTE CableLabs-Volume-Usage-Limit 63 integer
+ATTRIBUTE CableLabs-Gate-Usage-Info 64 integer
+ATTRIBUTE CableLabs-Element-Requesting-QoS 65 integer
+ATTRIBUTE CableLabs-QoS-Release-Reason 66 integer
+ATTRIBUTE CableLabs-Policy-Denied-Reason 67 integer
+ATTRIBUTE CableLabs-Policy-Deleted-Reason 68 integer
+ATTRIBUTE CableLabs-Policy-Update-Reason 69 integer
+ATTRIBUTE CableLabs-Policy-Decision-Status 70 integer
+ATTRIBUTE CableLabs-Application-Manager-ID 71 integer
+ATTRIBUTE CableLabs-Time-Usage-Limit 72 integer
+ATTRIBUTE CableLabs-Gate-Time-Info 73 integer
+ATTRIBUTE CableLabs-Account-Code 80 string
+ATTRIBUTE CableLabs-Authorization-Code 81 string
+
+VALUE CableLabs-Event-Message Reserved 0
+VALUE CableLabs-Event-Message Signaling-Start 1
+VALUE CableLabs-Event-Message Signaling-Stop 2
+VALUE CableLabs-Event-Message Database-Query 3
+VALUE CableLabs-Event-Message Intelligent-Peripheral-Usage-Start 4
+VALUE CableLabs-Event-Message Intelligent-Peripheral-Usage-Stop 5
+VALUE CableLabs-Event-Message Service-Instance 6
+VALUE CableLabs-Event-Message QoS-Reserve 7
+VALUE CableLabs-Event-Message QoS-Release 8
+VALUE CableLabs-Event-Message Service-Activation 9
+VALUE CableLabs-Event-Message Service-Deactivation 10
+VALUE CableLabs-Event-Message Media-Report 11
+VALUE CableLabs-Event-Message Signal-Instance 12
+VALUE CableLabs-Event-Message Interconnect-Signaling-Start 13
+VALUE CableLabs-Event-Message Interconnect-Signaling-Stop 14
+VALUE CableLabs-Event-Message Call-Answer 15
+VALUE CableLabs-Event-Message Call-Disconnect 16
+VALUE CableLabs-Event-Message Time-Change 17
+VALUE CableLabs-Event-Message QoS-Commit 19
+VALUE CableLabs-Event-Message Media-Alive 20
+VALUE CableLabs-Event-Message Policy-Request 31
+VALUE CableLabs-Event-Message Policy-Delete 32
+VALUE CableLabs-Event-Message Policy-Update 33
+
+VALUE CableLabs-Query-Type Reserved 0
+VALUE CableLabs-Query-Type Toll-Free-Number-Looukp 1
+VALUE CableLabs-Query-Type LNP-Number-Lookup 2
+VALUE CableLabs-Query-Type Calling-Name-Delivery-Lookup 3
+
+VALUE CableLabs-Channel-State Reserved 0
+VALUE CableLabs-Channel-State Open 1
+VALUE CableLabs-Channel-State Change 2
+VALUE CableLabs-Channel-State Close 3
+
+VALUE CableLabs-Direction-indicator Undefined 0
+VALUE CableLabs-Direction-indicator Originating 1
+VALUE CableLabs-Direction-indicator Terminating 2
+
+VALUE CableLabs-Flow-Direction Reserved 0
+VALUE CableLabs-Flow-Direction Upstream 1
+VALUE CableLabs-Flow-Direction Downstream 2
+
+VALUE CableLabs-Signal-Type Reserved 0
+VALUE CableLabs-Signal-Type Network-Signal 1
+VALUE CableLabs-Signal-Type Subject-Signal 2
+
+VALUE CableLabs-Alerting-Signal Reserved-0 0
+VALUE CableLabs-Alerting-Signal Ringing 1
+VALUE CableLabs-Alerting-Signal Distinctive-Ringing-2 2
+VALUE CableLabs-Alerting-Signal Distinctive-Ringing-3 3
+VALUE CableLabs-Alerting-Signal Distinctive-Ringing-4 4
+VALUE CableLabs-Alerting-Signal Ringsplash 5
+VALUE CableLabs-Alerting-Signal Call-Waiting-Tone-1 6
+VALUE CableLabs-Alerting-Signal Call-Waiting-Tone-2 7
+VALUE CableLabs-Alerting-Signal Call-Waiting-Tone-3 8
+VALUE CableLabs-Alerting-Signal Call-Waiting-Tone-4 9
+VALUE CableLabs-Alerting-Signal Reserved-10 10
+VALUE CableLabs-Alerting-Signal Distinctive-Ringing-0 11
+VALUE CableLabs-Alerting-Signal Distinctive-Ringing-1 12
+VALUE CableLabs-Alerting-Signal Distinctive-Ringing-5 13
+VALUE CableLabs-Alerting-Signal Distinctive-Ringing-6 14
+VALUE CableLabs-Alerting-Signal Distinctive-Ringing-7 15
+
+VALUE CableLabs-AM-Opaque-Data Reserved-0 0
+VALUE CableLabs-AM-Opaque-Data Dial-Tone 1
+VALUE CableLabs-AM-Opaque-Data Stutter-Dial-Tone 2
+VALUE CableLabs-AM-Opaque-Data Ring-Back-Tone 3
+VALUE CableLabs-AM-Opaque-Data Reorder-Tone 4
+VALUE CableLabs-AM-Opaque-Data Busy-Tone 5
+VALUE CableLabs-AM-Opaque-Data Confirmation-Tone 6
+VALUE CableLabs-AM-Opaque-Data Reserved-7 7
+VALUE CableLabs-AM-Opaque-Data Message-Waiting-Indicator 8
+VALUE CableLabs-AM-Opaque-Data Off-hook-Warning-Tone 9
+
+VALUE CableLabs-Element-Requesting-QoS Client 0
+VALUE CableLabs-Element-Requesting-QoS Policy-Server 1
+VALUE CableLabs-Element-Requesting-QoS Embedded-Client 2
+
+VALUE CableLabs-QoS-Release-Reason Gate-Closed-By-PS 1
+VALUE CableLabs-QoS-Release-Reason Inactivity-Resource-Recovery-Timer-Expiration 2
+VALUE CableLabs-QoS-Release-Reason CM-Failure 3
+VALUE CableLabs-QoS-Release-Reason Pre-Empted 4
+VALUE CableLabs-QoS-Release-Reason RSVP-PathTear-request 5
+VALUE CableLabs-QoS-Release-Reason CM-Request 6
+VALUE CableLabs-QoS-Release-Reason Admitted-Timer-Expiration 7
+VALUE CableLabs-QoS-Release-Reason Other 127
+
+VALUE CableLabs-Policy-Denied-Reason Policy-Server-Admission-Control-Failure 1
+VALUE CableLabs-Policy-Denied-Reason Insufficient-Resources 2
+VALUE CableLabs-Policy-Denied-Reason Unknown-Subscriber 3
+VALUE CableLabs-Policy-Denied-Reason Unauthorized-AMID 4
+VALUE CableLabs-Policy-Denied-Reason Undefined-Service-Class-Name 5
+VALUE CableLabs-Policy-Denied-Reason Incompatible-Envelope 6
+VALUE CableLabs-Policy-Denied-Reason Other 127
+
+VALUE CableLabs-Policy-Deleted-Reason Application-Manager-Request 1
+VALUE CableLabs-Policy-Deleted-Reason CMTS-Decistion 2
+VALUE CableLabs-Policy-Deleted-Reason Other 127
+
+VALUE CableLabs-Policy-Update-Reason Traffic-Profile 1
+VALUE CableLabs-Policy-Update-Reason Classifier 2
+VALUE CableLabs-Policy-Update-Reason Volume-Limit 3
+VALUE CableLabs-Policy-Update-Reason Time-Limit 4
+VALUE CableLabs-Policy-Update-Reason Opaque-Data 5
+VALUE CableLabs-Policy-Update-Reason Multiple-Updates 6
+VALUE CableLabs-Policy-Update-Reason Other 127
+
+VALUE CableLabs-Policy-Decision-Status Policy-Approved 1
+VALUE CableLabs-Policy-Decision-Status Policy-Denied 2
+
+END-VENDOR CableLabs
diff --git a/share/dictionary.cabletron b/share/dictionary.cabletron
new file mode 100644
index 0000000..5bd6f4d
--- /dev/null
+++ b/share/dictionary.cabletron
@@ -0,0 +1,28 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# http://www.cabletron.com (now http://www.enterasys.com)
+# $Id$
+#
+
+VENDOR Cabletron 52
+
+BEGIN-VENDOR Cabletron
+
+ATTRIBUTE Cabletron-Protocol-Enable 201 integer
+ATTRIBUTE Cabletron-Protocol-Callable 202 integer
+
+VALUE Cabletron-Protocol-Enable IP-Enable 1
+VALUE Cabletron-Protocol-Enable Bridge-Enable 2
+VALUE Cabletron-Protocol-Enable IP-BR-Enable 3
+VALUE Cabletron-Protocol-Enable BR-IPX-Enable 6
+VALUE Cabletron-Protocol-Enable IP-BR-IPX-Enable 7
+
+VALUE Cabletron-Protocol-Callable IP-Callable 1
+VALUE Cabletron-Protocol-Callable Bridge-Callable 2
+VALUE Cabletron-Protocol-Callable IP-BR-Callable 3
+VALUE Cabletron-Protocol-Callable BR-IPX-Callable 6
+VALUE Cabletron-Protocol-Callable IP-BR-IPX-Callable 7
+
+END-VENDOR Cabletron
diff --git a/share/dictionary.calix b/share/dictionary.calix
new file mode 100644
index 0000000..0a66326
--- /dev/null
+++ b/share/dictionary.calix
@@ -0,0 +1,29 @@
+# -*- text -*-
+# Copyright (C) 2021 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Based on https://www.calix.com/content/dam/calix/mycalix-misc/lib/tp/cms/ug/r15-x/index.htm?toc136037.htm?5793.htm
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR Calix 6321
+
+ATTRIBUTE Calix-CMS-User-Group 220 string
+ATTRIBUTE Calix-CMS-Alarm-Filter 221 integer
+
+VALUE Calix-CMS-Alarm-Filter Disabled 0
+VALUE Calix-CMS-Alarm-Filter Enabled 1
+
+ATTRIBUTE Calix-CMS-Event-Filter 222 integer
+
+VALUE Calix-CMS-Event-Filter Disabled 0
+VALUE Calix-CMS-Event-Filter Enabled 1
+
+ATTRIBUTE Calix-CMS-Threshold-Event-Filter 223 integer
+
+VALUE Calix-CMS-Threshold-Event-Filter Disabled 0
+VALUE Calix-CMS-Threshold-Event-Filter Enabled 1
diff --git a/share/dictionary.cambium b/share/dictionary.cambium
new file mode 100644
index 0000000..5c136ec
--- /dev/null
+++ b/share/dictionary.cambium
@@ -0,0 +1,78 @@
+# -*- text -*-
+# Copyright (C) 2021 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Cambium VSA's
+#
+# $Id$
+#
+# Derived from:
+# https://community.cambiumnetworks.com/t/40501
+# https://community.cambiumnetworks.com/t/40752
+# https://community.cambiumnetworks.com/t/50024
+#
+##############################################################################
+
+VENDOR Cambium 17713
+
+BEGIN-VENDOR Cambium
+
+ATTRIBUTE Cambium-Auth-Role 1 integer
+
+VALUE Cambium-Auth-Role Invalid 0
+VALUE Cambium-Auth-Role Read-Only 1
+VALUE Cambium-Auth-Role System-Admin 2
+VALUE Cambium-Auth-Role Security-Officer 3
+VALUE Cambium-Auth-Role Deliberately-Bad 4
+
+ATTRIBUTE Cambium-ePMP-Data-VLAN-Id 21 integer
+ATTRIBUTE Cambium-ePMP-Management-VLAN-Id 22 integer
+
+ATTRIBUTE Cambium-ePMP-Max-Burst-Uplink-Rate 26 integer
+ATTRIBUTE Cambium-ePMP-Max-Burst-Downlink-Rate 27 integer
+
+ATTRIBUTE Cambium-ePMP-UserLevel 50 integer
+
+VALUE Cambium-ePMP-UserLevel Install 2
+VALUE Cambium-ePMP-UserLevel Admin 3
+VALUE Cambium-ePMP-UserLevel User 4
+VALUE Cambium-ePMP-UserLevel Read-Only 5
+
+ATTRIBUTE Cambium-ePMP-SM-Priority 51 integer
+
+VALUE Cambium-ePMP-SM-Priority Normal 0
+VALUE Cambium-ePMP-SM-Priority High 1
+VALUE Cambium-ePMP-SM-Priority Low 2
+
+ATTRIBUTE Cambium-ePMP-VLAN-Membersip-Set 52 integer
+ATTRIBUTE Cambium-ePMP-Management-VLAN-Priority 53 integer
+ATTRIBUTE Cambium-ePMP-Data-VLAN-Priority 54 integer
+ATTRIBUTE Cambium-ePMP-Separate-Management-VLAN-Id 55 integer
+ATTRIBUTE Cambium-ePMP-Separate-Management-VLAN-Priority 56 integer
+ATTRIBUTE Cambium-ePMP-Multicast-VLAN-Id 57 integer
+ATTRIBUTE Cambium-ePMP-VLAN-Mapping 58 integer
+
+ATTRIBUTE Cambium-Traffic-Quota-Limit-Up 151 integer
+ATTRIBUTE Cambium-Traffic-Quota-Limit-Down 152 integer
+ATTRIBUTE Cambium-Traffic-Quota-Limit-Up-Gigwords 153 integer
+ATTRIBUTE Cambium-Traffic-Quota-Limit-Down-Gigwords 154 integer
+ATTRIBUTE Cambium-Traffic-Quota-Limit-Total 155 integer
+ATTRIBUTE Cambium-Traffic-Quota-Limit-Total-Gigwords 156 integer
+ATTRIBUTE Cambium-VLAN-Pool-Id 157 string
+
+ATTRIBUTE Cambium-Authorize-Classes 158 tlv
+ATTRIBUTE Cambium-Authorize-Class-Name 158.1 string
+ATTRIBUTE Cambium-Authorize-Bytes-Left 158.2 integer64
+
+ATTRIBUTE Cambium-Traffic-Classes-Acct 159 tlv
+ATTRIBUTE Cambium-Acct-Class-Name 159.1 string
+ATTRIBUTE Cambium-Acct-Input-Octets 159.2 integer
+ATTRIBUTE Cambium-Acct-Output-Octets 159.3 integer
+ATTRIBUTE Cambium-Acct-Input-Packets 159.4 integer
+ATTRIBUTE Cambium-Acct-Output-Packets 159.5 integer
+
+ATTRIBUTE Cambium-Walled-Garden-State 160 integer
+
+END-VENDOR Cambium
diff --git a/share/dictionary.camiant b/share/dictionary.camiant
new file mode 100644
index 0000000..b8a4a2b
--- /dev/null
+++ b/share/dictionary.camiant
@@ -0,0 +1,24 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Tekelec (Formerly Camiant) MSR dictionary
+# http://www.tekelec.com/products/policy-management.asp
+#
+##############################################################################
+
+VENDOR Camiant 21274
+
+BEGIN-VENDOR Camiant
+
+ATTRIBUTE Camiant-MI-role 1 string
+ATTRIBUTE Camiant-SUI-role 2 integer
+ATTRIBUTE Camiant-MI-scope 3 string
+
+VALUE Camiant-SUI-role camiantView 101
+VALUE Camiant-SUI-role camiantUser 102
+VALUE Camiant-SUI-role camiantService 104
+
+END-VENDOR Camiant
diff --git a/share/dictionary.centec b/share/dictionary.centec
new file mode 100644
index 0000000..2772a34
--- /dev/null
+++ b/share/dictionary.centec
@@ -0,0 +1,18 @@
+# Copyright (C) 2021 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+## Centec Packet RADIUS Dictionary
+#
+# http://www.centecnetworks.com
+#
+#
+
+VENDOR Centec 27975
+BEGIN-VENDOR Centec
+
+#
+# Centec Privilege Attributes
+#
+ATTRIBUTE Centec-Exec-Privilege 1 integer
+
+END-VENDOR Centec
diff --git a/share/dictionary.checkpoint b/share/dictionary.checkpoint
new file mode 100644
index 0000000..7382a6e
--- /dev/null
+++ b/share/dictionary.checkpoint
@@ -0,0 +1,13 @@
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Check Point dictionary file for freeradius AAA server
+#
+VENDOR CheckPoint 2620
+
+BEGIN-VENDOR CheckPoint
+
+ATTRIBUTE CP-Gaia-User-Role 229 string
+ATTRIBUTE CP-Gaia-SuperUser-Access 230 integer
+
+END-VENDOR CheckPoint
diff --git a/share/dictionary.chillispot b/share/dictionary.chillispot
new file mode 100644
index 0000000..c086a07
--- /dev/null
+++ b/share/dictionary.chillispot
@@ -0,0 +1,40 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# ChilliSpot (and CoovaChilli) captive portal
+# http://www.chillispot.org
+# http://coova.org/wiki/index.php/CoovaChilli
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR ChilliSpot 14559
+
+BEGIN-VENDOR ChilliSpot
+
+ATTRIBUTE ChilliSpot-Max-Input-Octets 1 integer
+ATTRIBUTE ChilliSpot-Max-Output-Octets 2 integer
+ATTRIBUTE ChilliSpot-Max-Total-Octets 3 integer
+ATTRIBUTE ChilliSpot-Bandwidth-Max-Up 4 integer
+ATTRIBUTE ChilliSpot-Bandwidth-Max-Down 5 integer
+ATTRIBUTE ChilliSpot-Config 6 string
+ATTRIBUTE ChilliSpot-Lang 7 string
+ATTRIBUTE ChilliSpot-Version 8 string
+ATTRIBUTE ChilliSpot-OriginalURL 9 string
+
+# Configuration management parameters (ChilliSpot Only)
+ATTRIBUTE ChilliSpot-UAM-Allowed 100 string
+ATTRIBUTE ChilliSpot-MAC-Allowed 101 string
+ATTRIBUTE ChilliSpot-Interval 102 integer
+
+# Inline with RFC 2882 use of VSE-Authorize-Only for remote config
+# Note that 14559 = 0x38df is used as prefix for the VSE.
+# This is recognized as the best (but bad) way of doing VSEs.
+# (ChilliSpot Only - CoovaChilli uses Service-Type = Administrative-User)
+VALUE Service-Type ChilliSpot-Authorize-Only 0x38df0001
+
+END-VENDOR ChilliSpot
diff --git a/share/dictionary.ciena b/share/dictionary.ciena
new file mode 100644
index 0000000..28e090a
--- /dev/null
+++ b/share/dictionary.ciena
@@ -0,0 +1,41 @@
+# -*- text -*-
+# Copyright (C) 2022 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Dictionary for Ciena
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR Ciena 1271
+
+BEGIN-VENDOR Ciena
+
+ATTRIBUTE Ciena-CN4200-Priv-Level 1 integer
+
+VALUE Ciena-CN4200-Priv-Level limited 1
+VALUE Ciena-CN4200-Priv-Level admin 2
+VALUE Ciena-CN4200-Priv-Level super-user 3
+VALUE Ciena-CN4200-Priv-Level diag 4
+
+ATTRIBUTE Ciena-CES-Priv-Level 10 integer
+
+VALUE Ciena-CES-Priv-Level limited 1
+VALUE Ciena-CES-Priv-Level admin 2
+VALUE Ciena-CES-Priv-Level super-user 3
+VALUE Ciena-CES-Priv-Level diag 4
+
+ATTRIBUTE Ciena-CES-NACM-Groups 11 string
+
+ATTRIBUTE Ciena-BP-Role 220 string
+ATTRIBUTE Ciena-NCS-Role 240 integer
+ATTRIBUTE Ciena-OC-Role 250 string
+ATTRIBUTE Ciena-CS-Client-IP 253 ipaddr
+ATTRIBUTE Ciena-CS-Acc-Level 254 integer
+ATTRIBUTE Ciena-CS-Priv-Level 255 integer
+
+END-VENDOR Ciena
+
diff --git a/share/dictionary.cisco b/share/dictionary.cisco
new file mode 100644
index 0000000..c629228
--- /dev/null
+++ b/share/dictionary.cisco
@@ -0,0 +1,226 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Accounting VSAs originally by
+# "Marcelo M. Sosa Lugones" <marcelo@sosa.com.ar>
+#
+# Version: $Id$
+#
+# For documentation on Cisco RADIUS attributes, see:
+#
+# http://www.cisco.com/univercd/cc/td/doc/product/access/acs_serv/vapp_dev/vsaig3.htm
+#
+# For general documentation on Cisco RADIUS configuration, see:
+#
+# http://www.cisco.com/en/US/partner/tech/tk583/tk547/tsd_technology_support_sub-protocol_home.html
+#
+
+VENDOR Cisco 9
+
+#
+# Standard attribute
+#
+BEGIN-VENDOR Cisco
+
+ATTRIBUTE Cisco-AVPair 1 string
+ATTRIBUTE Cisco-NAS-Port 2 string
+
+#
+# T.37 Store-and-Forward attributes.
+#
+ATTRIBUTE Cisco-Fax-Account-Id-Origin 3 string
+ATTRIBUTE Cisco-Fax-Msg-Id 4 string
+ATTRIBUTE Cisco-Fax-Pages 5 string
+ATTRIBUTE Cisco-Fax-Coverpage-Flag 6 string
+ATTRIBUTE Cisco-Fax-Modem-Time 7 string
+ATTRIBUTE Cisco-Fax-Connect-Speed 8 string
+ATTRIBUTE Cisco-Fax-Recipient-Count 9 string
+ATTRIBUTE Cisco-Fax-Process-Abort-Flag 10 string
+ATTRIBUTE Cisco-Fax-Dsn-Address 11 string
+ATTRIBUTE Cisco-Fax-Dsn-Flag 12 string
+ATTRIBUTE Cisco-Fax-Mdn-Address 13 string
+ATTRIBUTE Cisco-Fax-Mdn-Flag 14 string
+ATTRIBUTE Cisco-Fax-Auth-Status 15 string
+ATTRIBUTE Cisco-Email-Server-Address 16 string
+ATTRIBUTE Cisco-Email-Server-Ack-Flag 17 string
+ATTRIBUTE Cisco-Gateway-Id 18 string
+ATTRIBUTE Cisco-Call-Type 19 string
+ATTRIBUTE Cisco-Port-Used 20 string
+ATTRIBUTE Cisco-Abort-Cause 21 string
+
+#
+# Voice over IP attributes.
+#
+ATTRIBUTE h323-remote-address 23 string
+ATTRIBUTE h323-conf-id 24 string
+ATTRIBUTE h323-setup-time 25 string
+ATTRIBUTE h323-call-origin 26 string
+ATTRIBUTE h323-call-type 27 string
+ATTRIBUTE h323-connect-time 28 string
+ATTRIBUTE h323-disconnect-time 29 string
+ATTRIBUTE h323-disconnect-cause 30 string
+ATTRIBUTE h323-voice-quality 31 string
+ATTRIBUTE h323-gw-id 33 string
+ATTRIBUTE h323-incoming-conf-id 35 string
+
+ATTRIBUTE Cisco-Policy-Up 37 string
+ATTRIBUTE Cisco-Policy-Down 38 string
+
+ATTRIBUTE Cisco-Relay-Information-Option 46 string
+ATTRIBUTE Cisco-DHCP-User-Class 47 string
+ATTRIBUTE Cisco-DHCP-Vendor-Class 48 string
+
+ATTRIBUTE Cisco-DHCP-Relay-GiAddr 50 string
+ATTRIBUTE Cisco-Service-Name 51 string
+ATTRIBUTE Cisco-Parent-Session-Id 52 string
+
+ATTRIBUTE Cisco-Sub-QoS-Pol-In 55 string
+ATTRIBUTE Cisco-Sub-QoS-Pol-Out 56 string
+ATTRIBUTE Cisco-In-ACL 57 string
+ATTRIBUTE Cisco-Out-ACL 58 string
+ATTRIBUTE Cisco-Sub-PBR-Policy-In 59 string
+ATTRIBUTE Cisco-Sub-Activate-Service 60 string
+ATTRIBUTE Cisco-IPv6-In-ACL 61 string
+ATTRIBUTE Cisco-IPv6-Out-ACL 62 string
+ATTRIBUTE Cisco-Sub-Deactivate-Service 63 string
+
+ATTRIBUTE Cisco-DHCP-Subscriber-Id 65 string
+ATTRIBUTE Cisco-DHCPv6-Link-Address 66 string
+
+ATTRIBUTE sip-conf-id 100 string
+ATTRIBUTE h323-credit-amount 101 string
+ATTRIBUTE h323-credit-time 102 string
+ATTRIBUTE h323-return-code 103 string
+ATTRIBUTE h323-prompt-id 104 string
+ATTRIBUTE h323-time-and-day 105 string
+ATTRIBUTE h323-redirect-number 106 string
+ATTRIBUTE h323-preferred-lang 107 string
+ATTRIBUTE h323-redirect-ip-address 108 string
+ATTRIBUTE h323-billing-model 109 string
+ATTRIBUTE h323-currency 110 string
+ATTRIBUTE subscriber 111 string
+ATTRIBUTE gw-rxd-cdn 112 string
+ATTRIBUTE gw-final-xlated-cdn 113 string
+ATTRIBUTE remote-media-address 114 string
+ATTRIBUTE release-source 115 string
+ATTRIBUTE gw-rxd-cgn 116 string
+ATTRIBUTE gw-final-xlated-cgn 117 string
+
+# SIP Attributes
+ATTRIBUTE call-id 141 string
+ATTRIBUTE session-protocol 142 string
+ATTRIBUTE method 143 string
+ATTRIBUTE prev-hop-via 144 string
+ATTRIBUTE prev-hop-ip 145 string
+ATTRIBUTE incoming-req-uri 146 string
+ATTRIBUTE outgoing-req-uri 147 string
+ATTRIBUTE next-hop-ip 148 string
+ATTRIBUTE next-hop-dn 149 string
+ATTRIBUTE sip-hdr 150 string
+ATTRIBUTE dsp-id 151 string
+
+#
+# Extra attributes sent by the Cisco, if you configure
+# "radius-server vsa accounting" (requires IOS11.2+).
+#
+ATTRIBUTE Cisco-Multilink-ID 187 integer
+ATTRIBUTE Cisco-Num-In-Multilink 188 integer
+ATTRIBUTE Cisco-Pre-Input-Octets 190 integer
+ATTRIBUTE Cisco-Pre-Output-Octets 191 integer
+ATTRIBUTE Cisco-Pre-Input-Packets 192 integer
+ATTRIBUTE Cisco-Pre-Output-Packets 193 integer
+ATTRIBUTE Cisco-Maximum-Time 194 integer
+ATTRIBUTE Cisco-Disconnect-Cause 195 integer
+ATTRIBUTE Cisco-Data-Rate 197 integer
+ATTRIBUTE Cisco-PreSession-Time 198 integer
+ATTRIBUTE Cisco-PW-Lifetime 208 integer
+ATTRIBUTE Cisco-IP-Direct 209 integer
+ATTRIBUTE Cisco-PPP-VJ-Slot-Comp 210 integer
+ATTRIBUTE Cisco-PPP-Async-Map 212 integer
+ATTRIBUTE Cisco-IP-Pool-Definition 217 string
+ATTRIBUTE Cisco-Assign-IP-Pool 218 integer
+ATTRIBUTE Cisco-Route-IP 228 integer
+ATTRIBUTE Cisco-Link-Compression 233 integer
+ATTRIBUTE Cisco-Target-Util 234 integer
+ATTRIBUTE Cisco-Maximum-Channels 235 integer
+ATTRIBUTE Cisco-Data-Filter 242 integer
+ATTRIBUTE Cisco-Call-Filter 243 integer
+ATTRIBUTE Cisco-Idle-Limit 244 integer
+ATTRIBUTE Cisco-Subscriber-Password 249 string
+ATTRIBUTE Cisco-Account-Info 250 string
+ATTRIBUTE Cisco-Service-Info 251 string
+ATTRIBUTE Cisco-Command-Code 252 string
+ATTRIBUTE Cisco-Control-Info 253 string
+ATTRIBUTE Cisco-Xmit-Rate 255 integer
+
+VALUE Cisco-Disconnect-Cause No-Reason 0
+VALUE Cisco-Disconnect-Cause No-Disconnect 1
+VALUE Cisco-Disconnect-Cause Unknown 2
+VALUE Cisco-Disconnect-Cause Call-Disconnect 3
+VALUE Cisco-Disconnect-Cause CLID-Authentication-Failure 4
+VALUE Cisco-Disconnect-Cause No-Modem-Available 9
+VALUE Cisco-Disconnect-Cause No-Carrier 10
+VALUE Cisco-Disconnect-Cause Lost-Carrier 11
+VALUE Cisco-Disconnect-Cause No-Detected-Result-Codes 12
+VALUE Cisco-Disconnect-Cause User-Ends-Session 20
+VALUE Cisco-Disconnect-Cause Idle-Timeout 21
+VALUE Cisco-Disconnect-Cause Exit-Telnet-Session 22
+VALUE Cisco-Disconnect-Cause No-Remote-IP-Addr 23
+VALUE Cisco-Disconnect-Cause Exit-Raw-TCP 24
+VALUE Cisco-Disconnect-Cause Password-Fail 25
+VALUE Cisco-Disconnect-Cause Raw-TCP-Disabled 26
+VALUE Cisco-Disconnect-Cause Control-C-Detected 27
+VALUE Cisco-Disconnect-Cause EXEC-Program-Destroyed 28
+VALUE Cisco-Disconnect-Cause Close-Virtual-Connection 29
+VALUE Cisco-Disconnect-Cause End-Virtual-Connection 30
+VALUE Cisco-Disconnect-Cause Exit-Rlogin 31
+VALUE Cisco-Disconnect-Cause Invalid-Rlogin-Option 32
+VALUE Cisco-Disconnect-Cause Insufficient-Resources 33
+VALUE Cisco-Disconnect-Cause Timeout-PPP-LCP 40
+VALUE Cisco-Disconnect-Cause Failed-PPP-LCP-Negotiation 41
+VALUE Cisco-Disconnect-Cause Failed-PPP-PAP-Auth-Fail 42
+VALUE Cisco-Disconnect-Cause Failed-PPP-CHAP-Auth 43
+VALUE Cisco-Disconnect-Cause Failed-PPP-Remote-Auth 44
+VALUE Cisco-Disconnect-Cause PPP-Remote-Terminate 45
+VALUE Cisco-Disconnect-Cause PPP-Closed-Event 46
+VALUE Cisco-Disconnect-Cause NCP-Closed-PPP 47
+VALUE Cisco-Disconnect-Cause MP-Error-PPP 48
+VALUE Cisco-Disconnect-Cause PPP-Maximum-Channels 49
+VALUE Cisco-Disconnect-Cause Tables-Full 50
+VALUE Cisco-Disconnect-Cause Resources-Full 51
+VALUE Cisco-Disconnect-Cause Invalid-IP-Address 52
+VALUE Cisco-Disconnect-Cause Bad-Hostname 53
+VALUE Cisco-Disconnect-Cause Bad-Port 54
+VALUE Cisco-Disconnect-Cause Reset-TCP 60
+VALUE Cisco-Disconnect-Cause TCP-Connection-Refused 61
+VALUE Cisco-Disconnect-Cause Timeout-TCP 62
+VALUE Cisco-Disconnect-Cause Foreign-Host-Close-TCP 63
+VALUE Cisco-Disconnect-Cause TCP-Network-Unreachable 64
+VALUE Cisco-Disconnect-Cause TCP-Host-Unreachable 65
+VALUE Cisco-Disconnect-Cause TCP-Network-Admin-Unreachable 66
+VALUE Cisco-Disconnect-Cause TCP-Port-Unreachable 67
+VALUE Cisco-Disconnect-Cause Session-Timeout 100
+VALUE Cisco-Disconnect-Cause Session-Failed-Security 101
+VALUE Cisco-Disconnect-Cause Session-End-Callback 102
+VALUE Cisco-Disconnect-Cause Invalid-Protocol 120
+VALUE Cisco-Disconnect-Cause RADIUS-Disconnect 150
+VALUE Cisco-Disconnect-Cause Local-Admin-Disconnect 151
+VALUE Cisco-Disconnect-Cause SNMP-Disconnect 152
+VALUE Cisco-Disconnect-Cause V110-Retries 160
+VALUE Cisco-Disconnect-Cause PPP-Authentication-Timeout 170
+VALUE Cisco-Disconnect-Cause Local-Hangup 180
+VALUE Cisco-Disconnect-Cause Remote-Hangup 185
+VALUE Cisco-Disconnect-Cause T1-Quiesced 190
+VALUE Cisco-Disconnect-Cause Call-Duration 195
+VALUE Cisco-Disconnect-Cause VPN-User-Disconnect 600
+VALUE Cisco-Disconnect-Cause VPN-Carrier-Loss 601
+VALUE Cisco-Disconnect-Cause VPN-No-Resources 602
+VALUE Cisco-Disconnect-Cause VPN-Bad-Control-Packet 603
+VALUE Cisco-Disconnect-Cause VPN-Admin-Disconnect 604
+VALUE Cisco-Disconnect-Cause VPN-Tunnel-Shut 605
+VALUE Cisco-Disconnect-Cause VPN-Local-Disconnect 606
+VALUE Cisco-Disconnect-Cause VPN-Session-Limit 607
+VALUE Cisco-Disconnect-Cause VPN-Call-Redirect 608
+
+END-VENDOR Cisco
diff --git a/share/dictionary.cisco.asa b/share/dictionary.cisco.asa
new file mode 100644
index 0000000..e1738fe
--- /dev/null
+++ b/share/dictionary.cisco.asa
@@ -0,0 +1,369 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Cisco Adaptative Security Appliance (ASA) Dictionary
+#
+# http://www.cisco.com/en/US/docs/security/asa/asa90/configuration/guide/ref_extserver.html#wp1802187
+#
+# $Id$
+#
+
+VENDOR Cisco-ASA 3076
+
+BEGIN-VENDOR Cisco-ASA
+
+ATTRIBUTE ASA-Simultaneous-Logins 2 integer
+ATTRIBUTE ASA-Primary-DNS 5 ipaddr
+ATTRIBUTE ASA-Secondary-DNS 6 ipaddr
+ATTRIBUTE ASA-Primary-WINS 7 ipaddr
+ATTRIBUTE ASA-Secondary-WINS 8 ipaddr
+ATTRIBUTE ASA-SEP-Card-Assignment 9 integer
+ATTRIBUTE ASA-Tunneling-Protocols 11 integer
+ATTRIBUTE ASA-IPsec-Sec-Association 12 string
+ATTRIBUTE ASA-IPsec-Authentication 13 integer
+ATTRIBUTE ASA-Banner1 15 string
+ATTRIBUTE ASA-IPsec-Allow-Passwd-Store 16 integer
+ATTRIBUTE ASA-Use-Client-Address 17 integer
+ATTRIBUTE ASA-PPTP-Encryption 20 integer
+ATTRIBUTE ASA-L2TP-Encryption 21 integer
+ATTRIBUTE ASA-Group-Policy 25 string
+ATTRIBUTE ASA-IPsec-Split-Tunnel-List 27 string
+ATTRIBUTE ASA-IPsec-Default-Domain 28 string
+ATTRIBUTE ASA-IPsec-Split-DNS-Names 29 string
+ATTRIBUTE ASA-IPsec-Tunnel-Type 30 integer
+ATTRIBUTE ASA-IPsec-Mode-Config 31 integer
+ATTRIBUTE ASA-IPsec-Over-UDP 34 integer
+ATTRIBUTE ASA-IPsec-Over-UDP-Port 35 integer
+ATTRIBUTE ASA-Banner2 36 string
+ATTRIBUTE ASA-PPTP-MPPC-Compression 37 integer
+ATTRIBUTE ASA-L2TP-MPPC-Compression 38 integer
+ATTRIBUTE ASA-IPsec-IP-Compression 39 integer
+ATTRIBUTE ASA-IPsec-IKE-Peer-ID-Check 40 integer
+ATTRIBUTE ASA-IKE-Keep-Alives 41 integer
+ATTRIBUTE ASA-IPsec-Auth-On-Rekey 42 integer
+ATTRIBUTE ASA-Required-Client-Firewall-Vendor-Code 45 integer
+ATTRIBUTE ASA-Required-Client-Firewall-Product-Code 46 integer
+ATTRIBUTE ASA-Required-Client-Firewall-Description 47 string
+ATTRIBUTE ASA-Require-HW-Client-Auth 48 integer
+ATTRIBUTE ASA-Required-Individual-User-Auth 49 integer
+ATTRIBUTE ASA-Authenticated-User-Idle-Timeout 50 integer
+ATTRIBUTE ASA-Cisco-IP-Phone-Bypass 51 integer
+ATTRIBUTE ASA-IPsec-Split-Tunneling-Policy 55 integer
+ATTRIBUTE ASA-IPsec-Required-Client-Firewall-Capability 56 integer
+ATTRIBUTE ASA-IPsec-Client-Firewall-Filter-Name 57 string
+ATTRIBUTE ASA-IPsec-Client-Firewall-Filter-Optional 58 integer
+ATTRIBUTE ASA-IPsec-Backup-Servers 59 integer
+ATTRIBUTE ASA-IPsec-Backup-Server-List 60 string
+ATTRIBUTE ASA-DHCP-Network-Scope 61 ipaddr
+ATTRIBUTE ASA-Intercept-DHCP-Configure-Msg 62 integer
+ATTRIBUTE ASA-MS-Client-Subnet-Mask 63 ipaddr
+ATTRIBUTE ASA-Allow-Network-Extension-Mode 64 integer
+ATTRIBUTE ASA-Authorization-Type 65 integer
+ATTRIBUTE ASA-Authorization-Required 66 integer
+ATTRIBUTE ASA-Authorization-DN-Field 67 string
+ATTRIBUTE ASA-IKE-KeepAlive-Confidence-Interval 68 integer
+ATTRIBUTE ASA-WebVPN-Content-Filter-Parameters 69 integer
+ATTRIBUTE ASA-WebVPN-HTML-Filter 70 integer
+ATTRIBUTE ASA-WebVPN-URL-List 71 string
+ATTRIBUTE ASA-WebVPN-Port-Forwarding-List 72 string
+ATTRIBUTE ASA-WebVPN-Access-List 73 string
+ATTRIBUTE ASA-WebVPNACL 73 string
+ATTRIBUTE ASA-WebVPN-HTTP-Proxy-IP-Address 74 string
+ATTRIBUTE ASA-Cisco-LEAP-Bypass 75 integer
+ATTRIBUTE ASA-WebVPN-Default-Homepage 76 string
+ATTRIBUTE ASA-Client-Type-Version-Limiting 77 string
+ATTRIBUTE ASA-WebVPN-Group-based-HTTP/HTTPS-Proxy-Exception-List 78 string
+ATTRIBUTE ASA-WebVPN-Port-Forwarding-Name 79 string
+ATTRIBUTE ASA-IE-Proxy-Server 80 string
+ATTRIBUTE ASA-IE-Proxy-Server-Policy 81 integer
+ATTRIBUTE ASA-IE-Proxy-Exception-List 82 string
+ATTRIBUTE ASA-IE-Proxy-Bypass-Local 83 integer
+ATTRIBUTE ASA-IKE-Keepalive-Retry-Interval 84 integer
+ATTRIBUTE ASA-Tunnel-Group-Lock 85 string
+ATTRIBUTE ASA-Access-List-Inbound 86 string
+ATTRIBUTE ASA-Access-List-Outbound 87 string
+ATTRIBUTE ASA-Perfect-Forward-Secrecy-Enable 88 integer
+ATTRIBUTE ASA-NAC-Enable 89 integer
+ATTRIBUTE ASA-NAC-Status-Query-Timer 90 integer
+ATTRIBUTE ASA-NAC-Revalidation-Timer 91 integer
+ATTRIBUTE ASA-NAC-Default-ACL 92 string
+ATTRIBUTE ASA-WebVPN-URL-Entry-Enable 93 integer
+ATTRIBUTE ASA-WebVPN-File-Access-Enable 94 integer
+ATTRIBUTE ASA-WebVPN-File-Server-Entry-Enable 95 integer
+ATTRIBUTE ASA-WebVPN-File-Server-Browsing-Enable 96 integer
+ATTRIBUTE ASA-WebVPN-Port-Forwarding-Enable 97 integer
+ATTRIBUTE ASA-WebVPN-Port-Forwarding-Exchange-Proxy-Enable 98 integer
+ATTRIBUTE ASA-WebVPN-Port-Forwarding-HTTP-Proxy 99 integer
+ATTRIBUTE ASA-WebVPN-Citrix-Metaframe-Enable 101 integer
+ATTRIBUTE ASA-WebVPN-Apply-ACL 102 integer
+ATTRIBUTE ASA-WebVPN-SSL-VPN-Client-Enable 103 integer
+ATTRIBUTE ASA-WebVPN-SSL-VPN-Client-Required 104 integer
+ATTRIBUTE ASA-WebVPN-SSL-VPN-Client-Keep-Installation 105 integer
+ATTRIBUTE ASA-SVC-Keepalive 107 integer
+ATTRIBUTE ASA-WebVPN-SVC-Keepalive-Frequency 107 integer
+ATTRIBUTE ASA-SVC-DPD-Interval-Client 108 integer
+ATTRIBUTE ASA-WebVPN-SVC-Client-DPD-Frequency 108 integer
+ATTRIBUTE ASA-SVC-DPD-Interval-Gateway 109 integer
+ATTRIBUTE ASA-WebVPN-SVC-Gateway-DPD-Frequency 109 integer
+ATTRIBUTE ASA-SVC-Rekey-Time 110 integer
+ATTRIBUTE ASA-WebVPN-SVC-Rekey-Time 110 integer
+ATTRIBUTE ASA-WebVPN-SVC-Rekey-Method 111 integer
+ATTRIBUTE ASA-WebVPN-SVC-Compression 112 integer
+ATTRIBUTE ASA-WebVPN-Customization 113 string
+ATTRIBUTE ASA-WebVPN-SSO-Server-Name 114 string
+ATTRIBUTE ASA-WebVPN-Deny-Message 116 string
+ATTRIBUTE ASA-WebVPN-HTTP-Compression 120 integer
+ATTRIBUTE ASA-WebVPN-Keepalive-Ignore 121 integer
+ATTRIBUTE ASA-Extended-Authentication-On-Rekey 122 integer
+ATTRIBUTE ASA-SVC-DTLS 123 integer
+ATTRIBUTE ASA-WebVPN-SVC-DTLS-Enable 123 integer
+ATTRIBUTE ASA-WebVPN-Auto-HTTP-Signon 124 string
+ATTRIBUTE ASA-SVC-MTU 125 integer
+ATTRIBUTE ASA-WebVPN-SVC-DTLS-MTU 125 integer
+ATTRIBUTE ASA-WebVPN-Hidden-Shares 126 integer
+ATTRIBUTE ASA-SVC-Modules 127 string
+ATTRIBUTE ASA-SVC-Profiles 128 string
+ATTRIBUTE ASA-SVC-Ask 131 integer
+ATTRIBUTE ASA-SVC-Ask-Timeout 132 integer
+ATTRIBUTE ASA-IE-Proxy-PAC-URL 133 string
+ATTRIBUTE ASA-Strip-Realm 135 integer
+ATTRIBUTE ASA-Smart-Tunnel 136 string
+ATTRIBUTE ASA-WebVPN-Smart-Tunnel 136 string
+ATTRIBUTE ASA-WebVPN-ActiveX-Relay 137 integer
+ATTRIBUTE ASA-Smart-Tunnel-Auto 138 integer
+ATTRIBUTE ASA-WebVPN-Smart-Tunnel-Auto-Start 138 integer
+ATTRIBUTE ASA-Smart-Tunnel-Auto-Signon-Enable 139 string
+ATTRIBUTE ASA-WebVPN-Smart-Tunnel-Auto-Sign-On 139 string
+ATTRIBUTE ASA-VLAN 140 integer
+ATTRIBUTE ASA-NAC-Settings 141 string
+ATTRIBUTE ASA-Member-Of 145 string
+ATTRIBUTE ASA-TunnelGroupName 146 string
+ATTRIBUTE ASA-WebVPN-Idle-Timeout-Alert-Interval 148 integer
+ATTRIBUTE ASA-WebVPN-Session-Timeout-Alert-Interval 149 integer
+ATTRIBUTE ASA-ClientType 150 integer
+ATTRIBUTE ASA-SessionType 151 integer
+ATTRIBUTE ASA-SessionSubtype 152 integer
+ATTRIBUTE ASA-WebVPN-Download_Max-Size 157 integer
+ATTRIBUTE ASA-WebVPN-Upload-Max-Size 158 integer
+ATTRIBUTE ASA-WebVPN-Post-Max-Size 159 integer
+ATTRIBUTE ASA-WebVPN-User-Storage 160 string
+ATTRIBUTE ASA-WebVPN-Storage-Objects 161 string
+ATTRIBUTE ASA-WebVPN-Storage-Key 162 string
+ATTRIBUTE ASA-WebVPN-VDI 163 string
+ATTRIBUTE ASA-Address-Pools 217 string
+ATTRIBUTE ASA-IPv6-Address-Pools 218 string
+ATTRIBUTE ASA-IPv6-VPN-Filter 219 string
+ATTRIBUTE ASA-Privilege-Level 220 integer
+ATTRIBUTE ASA-WebVPN-UNIX-User-ID 221 integer
+ATTRIBUTE ASA-WebVPN-UNIX-Group-ID 222 integer
+ATTRIBUTE ASA-WebVPN-Macro-Substitution-Value1 223 string
+ATTRIBUTE ASA-WebVPN-Macro-Substitution-Value2 224 string
+ATTRIBUTE ASA-WebVPNSmart-Card-Removal-Disconnect 225 integer
+ATTRIBUTE ASA-WebVPN-Smart-Tunnel-Tunnel-Policy 227 string
+ATTRIBUTE ASA-WebVPN-Home-Page-Use-Smart-Tunnel 228 integer
+
+VALUE ASA-Authorization-Required No 0
+VALUE ASA-Authorization-Required Yes 1
+
+VALUE ASA-Authorization-Type None 0
+VALUE ASA-Authorization-Type Radius 1
+VALUE ASA-Authorization-Type LDAP 2
+
+VALUE ASA-Cisco-IP-Phone-Bypass Disabled 0
+VALUE ASA-Cisco-IP-Phone-Bypass Enabled 1
+
+VALUE ASA-Cisco-LEAP-Bypass Disabled 0
+VALUE ASA-Cisco-LEAP-Bypass Enabled 1
+
+VALUE ASA-ClientType Cisco-VPN-Client-IKEv1 1
+VALUE ASA-ClientType AnyConnect-Client-SSL-VPN 2
+VALUE ASA-ClientType Clientless-SSL-VPN 3
+VALUE ASA-ClientType Cut-Through-Proxy 4
+VALUE ASA-ClientType L2TP/IPsec-SSL-VPN 5
+VALUE ASA-ClientType AnyConnect-Client-IPSec-VPN-IKEv2 6
+
+VALUE ASA-Extended-Authentication-On-Rekey Disabled 0
+VALUE ASA-Extended-Authentication-On-Rekey Enabled 1
+
+VALUE ASA-IE-Proxy-Bypass-Local None 0
+VALUE ASA-IE-Proxy-Bypass-Local Local 1
+
+VALUE ASA-IE-Proxy-Server-Policy No-Modify 1
+VALUE ASA-IE-Proxy-Server-Policy No-Proxy 2
+VALUE ASA-IE-Proxy-Server-Policy Auto-detect 3
+VALUE ASA-IE-Proxy-Server-Policy Use-Concentrator-Setting 4
+
+VALUE ASA-IKE-Keep-Alives Disabled 0
+VALUE ASA-IKE-Keep-Alives Enabled 1
+
+VALUE ASA-Allow-Network-Extension-Mode Disabled 0
+VALUE ASA-Allow-Network-Extension-Mode Enabled 1
+
+VALUE ASA-Intercept-DHCP-Configure-Msg Disabled 0
+VALUE ASA-Intercept-DHCP-Configure-Msg Enabled 1
+
+VALUE ASA-IPsec-Allow-Passwd-Store Disabled 0
+VALUE ASA-IPsec-Allow-Passwd-Store Enabled 1
+
+VALUE ASA-IPsec-Authentication None 0
+VALUE ASA-IPsec-Authentication RADIUS 1
+VALUE ASA-IPsec-Authentication LDAP-Authorization-only 2
+VALUE ASA-IPsec-Authentication NT-Domain 3
+VALUE ASA-IPsec-Authentication SDI 4
+VALUE ASA-IPsec-Authentication Internal 5
+VALUE ASA-IPsec-Authentication RADIUS-with-Expiry 6
+VALUE ASA-IPsec-Authentication Kerberos/Active-Directory 7
+
+VALUE ASA-IPsec-Auth-On-Rekey Disabled 0
+VALUE ASA-IPsec-Auth-On-Rekey Enabled 1
+
+VALUE ASA-IPsec-Backup-Servers Use-Client-Configured-List 1
+VALUE ASA-IPsec-Backup-Servers Disable-and-clear-client-list 2
+VALUE ASA-IPsec-Backup-Servers Use-Backup-Server-List 3
+
+VALUE ASA-IPsec-Client-Firewall-Filter-Optional Required 0
+VALUE ASA-IPsec-Client-Firewall-Filter-Optional Optional 1
+
+VALUE ASA-IPsec-IKE-Peer-ID-Check Required 1
+VALUE ASA-IPsec-IKE-Peer-ID-Check If-Supported-By-Peer-Certificate 2
+VALUE ASA-IPsec-IKE-Peer-ID-Check Do-Not-Check 3
+
+VALUE ASA-IPsec-IP-Compression Disabled 0
+VALUE ASA-IPsec-IP-Compression Enabled 1
+
+VALUE ASA-IPsec-Mode-Config Disabled 0
+VALUE ASA-IPsec-Mode-Config Enabled 1
+
+VALUE ASA-IPsec-Over-UDP Disabled 0
+VALUE ASA-IPsec-Over-UDP Enabled 1
+
+VALUE ASA-IPsec-Required-Client-Firewall-Capability None 0
+VALUE ASA-IPsec-Required-Client-Firewall-Capability Policy-Remotely-Defined 1
+VALUE ASA-IPsec-Required-Client-Firewall-Capability Policy-Pushed 2
+VALUE ASA-IPsec-Required-Client-Firewall-Capability Policy-from-Server 4
+
+VALUE ASA-IPsec-Split-Tunneling-Policy No-Split-Tunneling 0
+VALUE ASA-IPsec-Split-Tunneling-Policy Split-Tunneling 1
+VALUE ASA-IPsec-Split-Tunneling-Policy Local-LAN-Permitted 2
+
+VALUE ASA-IPsec-Tunnel-Type LAN-to-LAN 1
+VALUE ASA-IPsec-Tunnel-Type Remote-Access 2
+
+VALUE ASA-L2TP-MPPC-Compression Disabled 0
+VALUE ASA-L2TP-MPPC-Compression Enabled 1
+
+VALUE ASA-NAC-Enable No 0
+VALUE ASA-NAC-Enable Yes 1
+
+VALUE ASA-Perfect-Forward-Secrecy-Enable No 0
+VALUE ASA-Perfect-Forward-Secrecy-Enable Yes 1
+
+VALUE ASA-PPTP-MPPC-Compression Disabled 0
+VALUE ASA-PPTP-MPPC-Compression Enabled 1
+
+VALUE ASA-Required-Client-Firewall-Vendor-Code Cisco-CIC 1
+VALUE ASA-Required-Client-Firewall-Vendor-Code Zone-Labs 2
+VALUE ASA-Required-Client-Firewall-Vendor-Code NetworkICE 3
+VALUE ASA-Required-Client-Firewall-Vendor-Code Sygate 4
+VALUE ASA-Required-Client-Firewall-Vendor-Code Cisco-IPSA 5
+
+VALUE ASA-Required-Individual-User-Auth Disabled 0
+VALUE ASA-Required-Individual-User-Auth Enabled 1
+
+VALUE ASA-Require-HW-Client-Auth Disabled 0
+VALUE ASA-Require-HW-Client-Auth Enabled 1
+
+VALUE ASA-SessionSubtype None 0
+VALUE ASA-SessionSubtype Clientless 1
+VALUE ASA-SessionSubtype Client 2
+VALUE ASA-SessionSubtype Client-Only 3
+
+VALUE ASA-SessionType None 0
+VALUE ASA-SessionType AnyConnect-Client-SSL-VPN 1
+VALUE ASA-SessionType AnyConnect-Client-IPSec-VPN/IKEv2 2
+VALUE ASA-SessionType Clientless-SSL-VPN 3
+VALUE ASA-SessionType Clientless-Email-Proxy 4
+VALUE ASA-SessionType Cisco-VPN-Client/IKEv1 5
+VALUE ASA-SessionType IKEv1-LAN-to-LAN 6
+VALUE ASA-SessionType IKEv2-LAN-to-LAN 7
+VALUE ASA-SessionType VPN-Load-Balancing 8
+
+VALUE ASA-Smart-Tunnel-Auto Disabled 0
+VALUE ASA-Smart-Tunnel-Auto Enabled 1
+VALUE ASA-Smart-Tunnel-Auto AutoStart 2
+
+VALUE ASA-Strip-Realm Disabled 0
+VALUE ASA-Strip-Realm Enabled 1
+
+VALUE ASA-SVC-Ask Disabled 0
+VALUE ASA-SVC-Ask Enabled 1
+VALUE ASA-SVC-Ask Enable-Default-Service 3
+VALUE ASA-SVC-Ask Enable-Default-Clientless 5
+
+VALUE ASA-SVC-DTLS FALSE 0
+VALUE ASA-SVC-DTLS TRUE 1
+
+VALUE ASA-Use-Client-Address Disabled 0
+VALUE ASA-Use-Client-Address Enabled 1
+
+VALUE ASA-WebVPN-Apply-ACL Disabled 0
+VALUE ASA-WebVPN-Apply-ACL Enabled 1
+
+VALUE ASA-WebVPN-Citrix-Metaframe-Enable Disabled 0
+VALUE ASA-WebVPN-Citrix-Metaframe-Enable Enabled 1
+
+VALUE ASA-WebVPN-File-Access-Enable Disabled 0
+VALUE ASA-WebVPN-File-Access-Enable Enabled 1
+
+VALUE ASA-WebVPN-File-Server-Browsing-Enable Disabled 0
+VALUE ASA-WebVPN-File-Server-Browsing-Enable Enabled 1
+
+VALUE ASA-WebVPN-File-Server-Entry-Enable Disabled 0
+VALUE ASA-WebVPN-File-Server-Entry-Enable Enabled 1
+
+VALUE ASA-WebVPN-Hidden-Shares None 0
+VALUE ASA-WebVPN-Hidden-Shares Visible 1
+
+VALUE ASA-WebVPN-HTTP-Compression Off 0
+VALUE ASA-WebVPN-HTTP-Compression Deflate-Compression 1
+
+VALUE ASA-WebVPN-Port-Forwarding-Enable Disabled 0
+VALUE ASA-WebVPN-Port-Forwarding-Enable Enabled 1
+
+VALUE ASA-WebVPN-Port-Forwarding-Exchange-Proxy-Enable Disabled 0
+VALUE ASA-WebVPN-Port-Forwarding-Exchange-Proxy-Enable Enabled 1
+
+VALUE ASA-WebVPN-Port-Forwarding-HTTP-Proxy Disabled 0
+VALUE ASA-WebVPN-Port-Forwarding-HTTP-Proxy Enabled 1
+
+VALUE ASA-WebVPNSmart-Card-Removal-Disconnect Disabled 0
+VALUE ASA-WebVPNSmart-Card-Removal-Disconnect Enabled 1
+
+VALUE ASA-WebVPN-Smart-Tunnel-Auto-Start Disabled 0
+VALUE ASA-WebVPN-Smart-Tunnel-Auto-Start Enabled 1
+VALUE ASA-WebVPN-Smart-Tunnel-Auto-Start AutoStart 2
+
+VALUE ASA-WebVPN-SSL-VPN-Client-Enable Disabled 0
+VALUE ASA-WebVPN-SSL-VPN-Client-Enable Enabled 1
+
+VALUE ASA-WebVPN-SSL-VPN-Client-Keep-Installation Disabled 0
+VALUE ASA-WebVPN-SSL-VPN-Client-Keep-Installation Enabled 1
+
+VALUE ASA-WebVPN-SSL-VPN-Client-Required Disabled 0
+VALUE ASA-WebVPN-SSL-VPN-Client-Required Enabled 1
+
+VALUE ASA-WebVPN-SVC-DTLS-Enable Disabled 0
+VALUE ASA-WebVPN-SVC-DTLS-Enable Enabled 1
+
+VALUE ASA-WebVPN-SVC-Rekey-Method Off 0
+VALUE ASA-WebVPN-SVC-Rekey-Method SSL 1
+VALUE ASA-WebVPN-SVC-Rekey-Method New-Tunnel 2
+
+VALUE ASA-WebVPN-SVC-Compression Off 0
+VALUE ASA-WebVPN-SVC-Compression Deflate-Compression 1
+
+VALUE ASA-WebVPN-URL-Entry-Enable Disabled 0
+VALUE ASA-WebVPN-URL-Entry-Enable Enabled 1
+
+END-VENDOR Cisco-ASA
diff --git a/share/dictionary.cisco.bbsm b/share/dictionary.cisco.bbsm
new file mode 100644
index 0000000..4efbca6
--- /dev/null
+++ b/share/dictionary.cisco.bbsm
@@ -0,0 +1,15 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Cisco Building Broadband Service Manager Dictionary
+#
+# http://www.cisco.com/univercd/cc/td/doc/product/access/acs_soft/csacs4nt/csnt30/user/ad.htm
+#
+# $Id$
+#
+VENDOR Cisco-BBSM 5263
+
+BEGIN-VENDOR Cisco-BBSM
+ATTRIBUTE CBBSM-Bandwidth 1 integer
+END-VENDOR Cisco-BBSM
diff --git a/share/dictionary.cisco.vpn3000 b/share/dictionary.cisco.vpn3000
new file mode 100644
index 0000000..cc9d09f
--- /dev/null
+++ b/share/dictionary.cisco.vpn3000
@@ -0,0 +1,243 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Cisco VPN 3000 Concentrator Dictionary
+#
+# http://www.cisco.com/univercd/cc/td/doc/product/access/acs_soft/csacs4nt/csnt30/user/ad.htm
+# http://www.cisco.com/univercd/cc/td/doc/product/access/acs_soft/csacs4nt/acs31/acsuser/ad.htm
+#
+# http://www.cisco.com/en/US/docs/security/asa/asa80/configuration/guide/extsvr.html#wp1661512
+#
+# $Id$
+#
+VENDOR Cisco-VPN3000 3076
+
+BEGIN-VENDOR Cisco-VPN3000
+ATTRIBUTE CVPN3000-Access-Hours 1 string
+ATTRIBUTE CVPN3000-Simultaneous-Logins 2 integer
+ATTRIBUTE CVPN3000-Min-Password-Length 3 integer
+ATTRIBUTE CVPN3000-Allow-Alpha-Only-Passwords 4 integer
+ATTRIBUTE CVPN3000-Primary-DNS 5 ipaddr
+ATTRIBUTE CVPN3000-Secondary-DNS 6 ipaddr
+ATTRIBUTE CVPN3000-Primary-WINS 7 ipaddr
+ATTRIBUTE CVPN3000-Secondary-WINS 8 ipaddr
+ATTRIBUTE CVPN3000-SEP-Card-Assignment 9 integer
+ATTRIBUTE CVPN3000-Priority-On-SEP 10 integer
+ATTRIBUTE CVPN3000-Tunneling-Protocols 11 integer
+ATTRIBUTE CVPN3000-IPSec-Sec-Association 12 string
+ATTRIBUTE CVPN3000-IPSec-Authentication 13 integer
+ATTRIBUTE CVPN3000-IPSec-Banner1 15 string
+ATTRIBUTE CVPN3000-IPSec-Allow-Passwd-Store 16 integer
+ATTRIBUTE CVPN3000-Use-Client-Address 17 integer
+ATTRIBUTE CVPN3000-PPTP-Min-Auth-Protocol 18 integer
+ATTRIBUTE CVPN3000-L2TP-Min-Auth-Protocol 19 integer
+ATTRIBUTE CVPN3000-PPTP-Encryption 20 integer
+ATTRIBUTE CVPN3000-L2TP-Encryption 21 integer
+ATTRIBUTE CVPN3000-Auth-Server-Type 22 integer
+ATTRIBUTE CVPN3000-Auth-Server-Password 23 string
+ATTRIBUTE CVPN3000-Request-Auth-Vector 24 string
+ATTRIBUTE CVPN3000-IPSec-LTL-Keepalives 25 integer
+ATTRIBUTE CVPN3000-IPSec-Group-Name 26 string
+ATTRIBUTE CVPN3000-IPSec-Split-Tunnel-List 27 string
+ATTRIBUTE CVPN3000-IPSec-Default-Domain 28 string
+ATTRIBUTE CVPN3000-IPSec-Split-DNS-Names 29 string
+ATTRIBUTE CVPN3000-IPSec-Tunnel-Type 30 integer
+ATTRIBUTE CVPN3000-IPSec-Mode-Config 31 integer
+ATTRIBUTE CVPN3000-Auth-Server-Priority 32 integer
+ATTRIBUTE CVPN3000-IPSec-User-Group-Lock 33 integer
+ATTRIBUTE CVPN3000-IPSec-Over-UDP 34 integer
+ATTRIBUTE CVPN3000-IPSec-Over-UDP-Port 35 integer
+ATTRIBUTE CVPN3000-IPSec-Banner2 36 string
+ATTRIBUTE CVPN3000-PPTP-MPPC-Compression 37 integer
+ATTRIBUTE CVPN3000-L2TP-MPPC-Compression 38 integer
+ATTRIBUTE CVPN3000-IPSec-IP-Compression 39 integer
+ATTRIBUTE CVPN3000-IPSec-IKE-Peer-ID-Check 40 integer
+ATTRIBUTE CVPN3000-IKE-Keep-Alives 41 integer
+ATTRIBUTE CVPN3000-IPSec-Auth-On-Rekey 42 integer
+ATTRIBUTE CVPN3000-Reqrd-Client-Fw-Vendor-Code 45 integer
+ATTRIBUTE CVPN3000-Reqrd-Client-Fw-Product-Code 46 integer
+ATTRIBUTE CVPN3000-Reqrd-Client-Fw-Description 47 string
+ATTRIBUTE CVPN3000-Require-HW-Client-Auth 48 integer
+ATTRIBUTE CVPN3000-Require-Individual-User-Auth 49 integer
+ATTRIBUTE CVPN3000-Authd-User-Idle-Timeout 50 integer
+ATTRIBUTE CVPN3000-Cisco-IP-Phone-Bypass 51 integer
+ATTRIBUTE CVPN3000-User-Auth-Server-Name 52 string
+ATTRIBUTE CVPN3000-User-Auth-Server-Port 53 integer
+ATTRIBUTE CVPN3000-User-Auth-Server-Secret 54 string
+ATTRIBUTE CVPN3000-IPSec-Split-Tunneling-Policy 55 integer
+ATTRIBUTE CVPN3000-IPSec-Reqrd-Client-Fw-Cap 56 integer
+ATTRIBUTE CVPN3000-IPSec-Client-Fw-Filter-Name 57 string
+ATTRIBUTE CVPN3000-IPSec-Client-Fw-Filter-Opt 58 integer
+ATTRIBUTE CVPN3000-IPSec-Backup-Servers 59 integer
+ATTRIBUTE CVPN3000-IPSec-Backup-Server-List 60 string
+ATTRIBUTE CVPN3000-DHCP-Network-Scope 61 ipaddr
+ATTRIBUTE CVPN3000-MS-Client-Icpt-DHCP-Conf-Msg 62 integer
+ATTRIBUTE CVPN3000-MS-Client-Subnet-Mask 63 ipaddr
+ATTRIBUTE CVPN3000-Allow-Network-Extension-Mode 64 integer
+ATTRIBUTE CVPN3000-IPSec-Authorization-Type 65 integer
+ATTRIBUTE CVPN3000-IPSec-Authorization-Required 66 integer
+ATTRIBUTE CVPN3000-IPSec-DN-Field 67 string
+ATTRIBUTE CVPN3000-IPSec-Confidence-Level 68 integer
+ATTRIBUTE CVPN3000-WebVPN-Content-Filter 69 integer
+ATTRIBUTE CVPN3000-WebVPN-Enable-functions 70 integer
+ATTRIBUTE CVPN3000-WebVPN-Exchange-Addr 74 string
+ATTRIBUTE CVPN3000-LEAP-Bypass 75 integer
+ATTRIBUTE CVPN3000-WebVPN-Exchange-NETBIOS-name 78 string
+ATTRIBUTE CVPN3000-Port-Forwarding-Name 79 string
+ATTRIBUTE CVPN3000-IE-Proxy-Server 80 string
+ATTRIBUTE CVPN3000-IE-Proxy-Server-Policy 81 integer
+ATTRIBUTE CVPN3000-IE-Proxy-Exception-List 82 string
+ATTRIBUTE CVPN3000-IE-Proxy-Bypass-Local 83 integer
+ATTRIBUTE CVPN3000-IKE-Keepalive-Retry-Interval 84 integer
+ATTRIBUTE CVPN3000-Tunnel-Group-Lock 85 string
+ATTRIBUTE Cisco-VPN3000-Access-List-Inbound 86 string
+ATTRIBUTE Cisco-VPN3000-Access-List-Outbound 87 string
+ATTRIBUTE Cisco-VPN3000-Perfect-Forward-Secrecy-Enable 88 integer
+ATTRIBUTE Cisco-VPN3000-NAC-Enable 89 integer
+ATTRIBUTE Cisco-VPN3000-NAC-Status-Query-Timer 90 integer
+ATTRIBUTE Cisco-VPN3000-NAC-Revalidation-Timer 91 integer
+ATTRIBUTE Cisco-VPN3000-NAC-Default-ACL 92 integer
+ATTRIBUTE Cisco-VPN3000-WebVPN-URL-Entry-Enable 93 integer
+ATTRIBUTE Cisco-VPN3000-WebVPN-File-Access-Enable 94 integer
+ATTRIBUTE Cisco-VPN3000-WebVPN-File-Server-Entry-Enable 95 integer
+ATTRIBUTE Cisco-VPN3000-WebVPN-File-Server-Browsing-Enable 96 integer
+ATTRIBUTE Cisco-VPN3000-WebVPN-Port-Forwarding-Enable 97 integer
+ATTRIBUTE Cisco-VPN3000-WebVPN-Outlook-Exchange-Proxy-Enable 98 integer
+ATTRIBUTE Cisco-VPN3000-WebVPN-HTTP-Proxy-Enable 99 integer
+ATTRIBUTE Cisco-VPN3000-WebVPN-Auto-Applet-Download-Enable 100 integer
+ATTRIBUTE Cisco-VPN3000-WebVPN-Citrix-MetaFrame-Enable 101 integer
+ATTRIBUTE Cisco-VPN3000-WebVPN-Apply-ACL 102 integer
+ATTRIBUTE Cisco-VPN3000-WebVPN-SSL-VPN-Client-Enable 103 integer
+ATTRIBUTE Cisco-VPN3000-WebVPN-SSL-VPN-Client-Required 104 integer
+ATTRIBUTE Cisco-VPN3000-WebVPN-SSL-VPN-Client-Keep-Installation 105 integer
+
+ATTRIBUTE CVPN3000-Partition-Primary-DHCP 128 ipaddr
+ATTRIBUTE CVPN3000-Partition-Secondary-DHCP 129 ipaddr
+ATTRIBUTE CVPN3000-Partition-Premise-Router 131 ipaddr
+ATTRIBUTE CVPN3000-Partition-Max-Sessions 132 integer
+ATTRIBUTE CVPN3000-Partition-Mobile-IP-Key 133 string
+ATTRIBUTE CVPN3000-Partition-Mobile-IP-Address 134 ipaddr
+ATTRIBUTE CVPN3000-Partition-Mobile-IP-SPI 135 integer
+ATTRIBUTE CVPN3000-Strip-Realm 136 integer
+ATTRIBUTE CVPN3000-Group-Name 137 integer
+ATTRIBUTE CVPN3000-Smart-Tunnel-Auto 138 integer
+ATTRIBUTE CVPN3000-VLAN 140 integer
+ATTRIBUTE CVPN3000-NAC-Settings 141 string
+ATTRIBUTE CVPN3000-Member-Of 145 string
+ATTRIBUTE CVPN3000-Address-Pools 217 string
+ATTRIBUTE CVPN3000-IPv6-Address-Pools 218 string
+ATTRIBUTE CVPN3000-IPv6-VPN-Filter 219 string
+ATTRIBUTE CVPN3000-Privilege-Level 220 integer
+ATTRIBUTE CVPN3000-WebVPN-Macro-Value1 223 string
+ATTRIBUTE CVPN3000-WebVPN-Macro-Value2 224 string
+
+VALUE CVPN3000-Allow-Alpha-Only-Passwords Disallow 0
+VALUE CVPN3000-Allow-Alpha-Only-Passwords Allow 1
+
+VALUE CVPN3000-SEP-Card-Assignment SEP1 1
+VALUE CVPN3000-SEP-Card-Assignment SEP2 2
+VALUE CVPN3000-SEP-Card-Assignment SEP3 4
+VALUE CVPN3000-SEP-Card-Assignment SEP4 8
+VALUE CVPN3000-SEP-Card-Assignment Any-SEP 15
+
+VALUE CVPN3000-Priority-On-SEP High 1
+VALUE CVPN3000-Priority-On-SEP Med-High 2
+VALUE CVPN3000-Priority-On-SEP Medium 3
+VALUE CVPN3000-Priority-On-SEP Med-Low 4
+VALUE CVPN3000-Priority-On-SEP Low 5
+
+VALUE CVPN3000-Tunneling-Protocols PPTP 1
+VALUE CVPN3000-Tunneling-Protocols L2TP 2
+VALUE CVPN3000-Tunneling-Protocols IPSec 4
+VALUE CVPN3000-Tunneling-Protocols PPTP-and-IPSec 5
+VALUE CVPN3000-Tunneling-Protocols L2TP/IPSec 8
+VALUE CVPN3000-Tunneling-Protocols All 15
+
+VALUE CVPN3000-IPSec-Authentication None 0
+VALUE CVPN3000-IPSec-Authentication RADIUS 1
+VALUE CVPN3000-IPSec-Authentication LDAP 2
+VALUE CVPN3000-IPSec-Authentication NTDomain 3
+VALUE CVPN3000-IPSec-Authentication SDI 4
+VALUE CVPN3000-IPSec-Authentication Internal 5
+
+VALUE CVPN3000-IPSec-Allow-Passwd-Store Disallow 0
+VALUE CVPN3000-IPSec-Allow-Passwd-Store Allow 1
+
+VALUE CVPN3000-Use-Client-Address Disallow 0
+VALUE CVPN3000-Use-Client-Address Allow 1
+
+VALUE CVPN3000-PPTP-Min-Auth-Protocol PAP 1
+VALUE CVPN3000-PPTP-Min-Auth-Protocol CHAP 2
+VALUE CVPN3000-PPTP-Min-Auth-Protocol EAP-MD5 4
+VALUE CVPN3000-PPTP-Min-Auth-Protocol EAP-GTC 8
+VALUE CVPN3000-PPTP-Min-Auth-Protocol EAP-TLS 16
+VALUE CVPN3000-PPTP-Min-Auth-Protocol MSCHAPv1 32
+VALUE CVPN3000-PPTP-Min-Auth-Protocol MSCHAPv2 64
+VALUE CVPN3000-PPTP-Min-Auth-Protocol Default 102
+
+VALUE CVPN3000-L2TP-Min-Auth-Protocol PAP 1
+VALUE CVPN3000-L2TP-Min-Auth-Protocol CHAP 2
+VALUE CVPN3000-L2TP-Min-Auth-Protocol EAP-MD5 4
+VALUE CVPN3000-L2TP-Min-Auth-Protocol EAP-GTC 8
+VALUE CVPN3000-L2TP-Min-Auth-Protocol EAP-TLS 16
+VALUE CVPN3000-L2TP-Min-Auth-Protocol MSCHAPv1 32
+VALUE CVPN3000-L2TP-Min-Auth-Protocol MSCHAPv2 64
+VALUE CVPN3000-L2TP-Min-Auth-Protocol Default 102
+
+VALUE CVPN3000-PPTP-Encryption PPTP-40bit 2
+VALUE CVPN3000-PPTP-Encryption PPTP-40-Encryption-Req 3
+VALUE CVPN3000-PPTP-Encryption PPTP-128 4
+VALUE CVPN3000-PPTP-Encryption PPTP-128-Encryption-Req 5
+VALUE CVPN3000-PPTP-Encryption PPTP-40-or-128 6
+VALUE CVPN3000-PPTP-Encryption PPTP-40-or-128-Encry-Req 7
+VALUE CVPN3000-PPTP-Encryption PPTP-40-Stateless-Req 10
+VALUE CVPN3000-PPTP-Encryption PPTP-40-Enc/Stateless-Req 11
+VALUE CVPN3000-PPTP-Encryption PPTP-128-Stateless-Req 12
+VALUE CVPN3000-PPTP-Encryption PPTP-128-Enc/Stateless-Req 13
+VALUE CVPN3000-PPTP-Encryption PPTP-40/128-Stateless-Req 14
+VALUE CVPN3000-PPTP-Encryption PPTP-40/128-Enc/Statls-Req 15
+
+VALUE CVPN3000-L2TP-Encryption L2TP-40bit 2
+VALUE CVPN3000-L2TP-Encryption L2TP-40-Encryption-Req 3
+VALUE CVPN3000-L2TP-Encryption L2TP-128 4
+VALUE CVPN3000-L2TP-Encryption L2TP-128-Encryption-Req 5
+VALUE CVPN3000-L2TP-Encryption L2TP-40-or-128 6
+VALUE CVPN3000-L2TP-Encryption L2TP-40-or-128-Encry-Req 7
+VALUE CVPN3000-L2TP-Encryption L2TP-40-Stateless-Req 10
+VALUE CVPN3000-L2TP-Encryption L2TP-40-Enc/Stateless-Req 11
+VALUE CVPN3000-L2TP-Encryption L2TP-128-Stateless-Req 12
+VALUE CVPN3000-L2TP-Encryption L2TP-128-Enc/Stateless-Req 13
+VALUE CVPN3000-L2TP-Encryption L2TP-40/128-Stateless-Req 14
+VALUE CVPN3000-L2TP-Encryption L2TP-40/128-Enc/Statls-Req 15
+
+VALUE CVPN3000-Auth-Server-Type First-Active-Server 0
+VALUE CVPN3000-Auth-Server-Type RADIUS 1
+VALUE CVPN3000-Auth-Server-Type LDAP 2
+VALUE CVPN3000-Auth-Server-Type NT 3
+VALUE CVPN3000-Auth-Server-Type SDI 4
+VALUE CVPN3000-Auth-Server-Type Internal 5
+
+VALUE CVPN3000-IPSec-LTL-Keepalives OFF 0
+VALUE CVPN3000-IPSec-LTL-Keepalives ON 1
+
+VALUE CVPN3000-IPSec-Tunnel-Type LAN-to-LAN 1
+VALUE CVPN3000-IPSec-Tunnel-Type Remote-Access 2
+
+VALUE CVPN3000-IPSec-Mode-Config ON 1
+VALUE CVPN3000-IPSec-Mode-Config OFF 0
+
+VALUE CVPN3000-IPSec-User-Group-Lock OFF 0
+VALUE CVPN3000-IPSec-User-Group-Lock ON 1
+
+VALUE CVPN3000-IPSec-Over-UDP OFF 0
+VALUE CVPN3000-IPSec-Over-UDP ON 1
+
+VALUE CVPN3000-Strip-Realm FALSE 0
+VALUE CVPN3000-Strip-Realm TRUE 1
+
+VALUE CVPN3000-Smart-Tunnel-Auto Disabled 0
+VALUE CVPN3000-Smart-Tunnel-Auto Enabled 1
+VALUE CVPN3000-Smart-Tunnel-Auto Auto 2
+
+END-VENDOR Cisco-VPN3000
diff --git a/share/dictionary.cisco.vpn5000 b/share/dictionary.cisco.vpn5000
new file mode 100644
index 0000000..70906ed
--- /dev/null
+++ b/share/dictionary.cisco.vpn5000
@@ -0,0 +1,21 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Cisco VPN 5000 Concentrator Dictionary
+#
+# http://www.cisco.com/univercd/cc/td/doc/product/access/acs_soft/csacs4nt/csnt30/user/ad.htm
+#
+# $Id$
+#
+VENDOR Cisco-VPN5000 255
+
+BEGIN-VENDOR Cisco-VPN5000
+ATTRIBUTE CVPN5000-Tunnel-Throughput 1 integer
+ATTRIBUTE CVPN5000-Client-Assigned-IP 2 string
+ATTRIBUTE CVPN5000-Client-Real-IP 3 string
+ATTRIBUTE CVPN5000-VPN-GroupInfo 4 string
+ATTRIBUTE CVPN5000-VPN-Password 5 string
+ATTRIBUTE CVPN5000-Echo 6 integer
+ATTRIBUTE CVPN5000-Client-Assigned-IPX 7 integer
+END-VENDOR Cisco-VPN5000
diff --git a/share/dictionary.citrix b/share/dictionary.citrix
new file mode 100644
index 0000000..3cba3d6
--- /dev/null
+++ b/share/dictionary.citrix
@@ -0,0 +1,25 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Citrix VSAs
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR Citrix 66
+
+BEGIN-VENDOR Citrix
+
+ATTRIBUTE Citrix-UID 10 integer
+ATTRIBUTE Citrix-GID 11 integer
+ATTRIBUTE Citrix-Home 12 string
+ATTRIBUTE Citrix-Shell 13 string
+ATTRIBUTE Citrix-Group-Names 14 string
+ATTRIBUTE Citrix-Group-Ids 15 string
+ATTRIBUTE Citrix-User-Groups 16 string
+
+END-VENDOR Citrix
diff --git a/share/dictionary.clavister b/share/dictionary.clavister
new file mode 100644
index 0000000..bc59c64
--- /dev/null
+++ b/share/dictionary.clavister
@@ -0,0 +1,22 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Clavister VSAs
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR Clavister 5089
+
+#
+# User group attribute
+#
+BEGIN-VENDOR Clavister
+
+ATTRIBUTE Clavister-User-Group 1 string
+
+END-VENDOR Clavister
diff --git a/share/dictionary.cnergee b/share/dictionary.cnergee
new file mode 100644
index 0000000..99555d7
--- /dev/null
+++ b/share/dictionary.cnergee
@@ -0,0 +1,52 @@
+# -*- text -*-
+# Copyright (C) 2019 The Cnergee Access Server project
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+
+VENDOR Cnergee 49426
+
+BEGIN-VENDOR Cnergee
+
+ATTRIBUTE BELRAS-Up-Speed-Limit 1 integer
+ATTRIBUTE BELRAS-Down-Speed-Limit 2 integer
+ATTRIBUTE BELRAS-Qos-Speed 3 integer
+ATTRIBUTE BELRAS-User 4 string
+ATTRIBUTE BELRAS-DHCP-Router-IP-Address 5 ipaddr
+ATTRIBUTE BELRAS-DHCP-Mask 6 integer
+ATTRIBUTE BELRAS-Redirect 7 integer
+ATTRIBUTE BELRAS-redirect-Pool 8 integer
+ATTRIBUTE BELRAS-DHCP-Option82 9 octets
+ATTRIBUTE BELRAS-Session-Octets-Limit 10 integer
+ATTRIBUTE BELRAS-Octets-Direction 11 integer
+ATTRIBUTE BELRAS-AKAMAI-Speed 12 integer
+ATTRIBUTE BELRAS-CACHE-Speed 13 integer
+ATTRIBUTE BELRAS-CacheFly-Speed 14 integer
+ATTRIBUTE BELRAS-GGC-Speed 15 integer
+ATTRIBUTE BELRAS-GOOGLE-Speed 16 integer
+ATTRIBUTE BELRAS-Incapsula-Speed 17 integer
+ATTRIBUTE BELRAS-LIMELIGHT-Speed 18 integer
+ATTRIBUTE BELRAS-OTHERS-Speed 19 integer
+ATTRIBUTE BELRAS-REDIFF-Speed 20 integer
+ATTRIBUTE BELRAS-TORRENT-Speed 21 integer
+ATTRIBUTE BELRAS-BELCACHE-Speed 22 integer
+ATTRIBUTE BELRAS-DHCP-Lease-Time 23 integer
+ATTRIBUTE BELRAS-Group 24 integer
+ATTRIBUTE BELRAS-LIMIT 25 string
+ATTRIBUTE BELRAS-Auth 26 string
+ATTRIBUTE BELRAS-Acct 27 string
+ATTRIBUTE BELRAS-Framed-IP-Address 28 string
+ATTRIBUTE BELRAS-BL 29 string
+ATTRIBUTE BELRAS-IN 30 string
+ATTRIBUTE BELRAS-CO 31 string
+
+VALUE BELRAS-redirect-Pool Deleted 1
+VALUE BELRAS-redirect-Pool Disabled 2
+VALUE BELRAS-redirect-Pool Disputes 3
+VALUE BELRAS-redirect-Pool Expired 4
+VALUE BELRAS-redirect-Pool Unknown 5
+VALUE BELRAS-redirect-Pool Exhausted 6
+VALUE BELRAS-redirect-Pool WrongMAC 7
+VALUE BELRAS-redirect-Pool VLANmismatch 8
+
+END-VENDOR Cnergee
+
diff --git a/share/dictionary.colubris b/share/dictionary.colubris
new file mode 100644
index 0000000..65ce4ea
--- /dev/null
+++ b/share/dictionary.colubris
@@ -0,0 +1,13 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+
+VENDOR Colubris 8744
+
+BEGIN-VENDOR Colubris
+
+ATTRIBUTE Colubris-AVPair 0 string
+ATTRIBUTE Colubris-Intercept 1 integer
+
+END-VENDOR Colubris
diff --git a/share/dictionary.columbia_university b/share/dictionary.columbia_university
new file mode 100644
index 0000000..0015d7f
--- /dev/null
+++ b/share/dictionary.columbia_university
@@ -0,0 +1,29 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+
+# A duplicate name that they use
+VALUE Service-Type Sip-session 12
+
+# Columbia University VSAs, from:
+#
+# http://www.cs.columbia.edu/IRT/cinema/release/radius_notes.html
+#
+# $Id$
+#
+VENDOR Columbia-University 11862
+
+BEGIN-VENDOR Columbia-University
+
+ATTRIBUTE Sip-Method 0 integer
+ATTRIBUTE Sip-From 1 string
+ATTRIBUTE Sip-To 2 string
+ATTRIBUTE Sip-Translated-Request-URI 4 string
+
+VALUE Sip-Method INVITE 0
+VALUE Sip-Method BYE 1
+VALUE Sip-Method REGISTER 2
+VALUE Sip-Method OTHER 3
+
+END-VENDOR Columbia-University
diff --git a/share/dictionary.compat b/share/dictionary.compat
new file mode 100644
index 0000000..8037904
--- /dev/null
+++ b/share/dictionary.compat
@@ -0,0 +1,44 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Obsolete names for backwards compatibility with older users files.
+# Move the $INCLUDE in the main dictionary file to the end if you want
+# these names to be used in the "details" logfile.
+#
+
+# This has been removed. Too many people get it wrong.
+#ATTRIBUTE Password 2 string encrypt=1
+ATTRIBUTE Client-Id 4 ipaddr
+ATTRIBUTE Client-Port-Id 5 integer
+ATTRIBUTE User-Service-Type 6 integer
+ATTRIBUTE Framed-Address 8 ipaddr
+ATTRIBUTE Framed-Netmask 9 ipaddr
+ATTRIBUTE Framed-Filter-Id 11 string
+ATTRIBUTE Login-Host 14 ipaddr
+ATTRIBUTE Login-Port 16 integer
+ATTRIBUTE Old-Password 17 string
+ATTRIBUTE Port-Message 18 string
+ATTRIBUTE Dialback-No 19 string
+ATTRIBUTE Dialback-Name 20 string
+ATTRIBUTE Challenge-State 24 octets
+VALUE Framed-Compression Van-Jacobsen-TCP-IP 1
+VALUE Framed-Compression VJ-TCP-IP 1
+VALUE Service-Type Shell-User 6
+VALUE Auth-Type Unix 1
+VALUE Service-Type Dialback-Login-User 3
+VALUE Service-Type Dialback-Framed-User 4
+VALUE Service-Type Dialout-Framed-User 5
+
+#
+# For compatibility with MERIT users files.
+#
+ATTRIBUTE Login-Callback-Number 19 string
+ATTRIBUTE Framed-Callback-Id 20 string
+ATTRIBUTE Client-Port-DNIS 30 string
+ATTRIBUTE Caller-ID 31 string
+VALUE Service-Type Login 1
+VALUE Service-Type Framed 2
+VALUE Service-Type Callback-Login 3
+VALUE Service-Type Callback-Framed 4
+VALUE Service-Type Exec-User 7
diff --git a/share/dictionary.compatible b/share/dictionary.compatible
new file mode 100644
index 0000000..3b56dc6
--- /dev/null
+++ b/share/dictionary.compatible
@@ -0,0 +1,22 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Compatible Systems Corporation dictionary
+#
+# Compatible Systems was acquired by Cisco in 2000.
+#
+
+VENDOR Compatible 255
+
+BEGIN-VENDOR Compatible
+
+ATTRIBUTE Compatible-Tunnel-Delay 0 integer
+ATTRIBUTE Compatible-Tunnel-Throughput 1 integer
+ATTRIBUTE Compatible-Tunnel-Server-Endpoint 3 ipaddr
+ATTRIBUTE Compatible-Tunnel-Group-Info 4 string
+ATTRIBUTE Compatible-Tunnel-Password 5 string
+ATTRIBUTE Compatible-Echo 6 integer
+ATTRIBUTE Compatible-Tunnel-IPX 7 integer
+
+END-VENDOR Compatible
diff --git a/share/dictionary.cosine b/share/dictionary.cosine
new file mode 100644
index 0000000..1682e8d
--- /dev/null
+++ b/share/dictionary.cosine
@@ -0,0 +1,26 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Cosine IPSX Dictionary
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR Cosine 3085
+
+BEGIN-VENDOR Cosine
+
+ATTRIBUTE Cosine-Connection-Profile-Name 1 string
+ATTRIBUTE Cosine-Enterprise-ID 2 string
+ATTRIBUTE Cosine-Address-Pool-Name 3 string
+ATTRIBUTE Cosine-DS-Byte 4 integer
+ATTRIBUTE Cosine-VPI-VCI 5 octets
+ATTRIBUTE Cosine-DLCI 6 integer
+ATTRIBUTE Cosine-LNS-IP-Address 7 ipaddr
+ATTRIBUTE Cosine-CLI-User-Permission-ID 8 string
+
+END-VENDOR Cosine
diff --git a/share/dictionary.covaro b/share/dictionary.covaro
new file mode 100644
index 0000000..7959a0b
--- /dev/null
+++ b/share/dictionary.covaro
@@ -0,0 +1,43 @@
+# -*- text -*-
+# Copyright (C) 2022 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Dictionary for Covaro Networks
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR Covaro 18022
+
+BEGIN-VENDOR Covaro
+
+ATTRIBUTE Covaro-User-Privilege 1 integer
+
+VALUE Covaro-User-Privilege SUPERUSER 1
+VALUE Covaro-User-Privilege PROVISIONING 2
+VALUE Covaro-User-Privilege MAINTENANCE 3
+VALUE Covaro-User-Privilege RETRIEVE 4
+
+ATTRIBUTE Covaro-Max-Sessions 2 integer
+ATTRIBUTE Covaro-Session-Timeout 3 integer
+
+ATTRIBUTE Covaro-Inhibit-Message 4 integer
+
+VALUE Covaro-Inhibit-Message N 0
+VALUE Covaro-Inhibit-Message Y 1
+
+ATTRIBUTE Covaro-Inhibit-Dbchg 5 integer
+
+VALUE Covaro-Inhibit-Dbchg N 0
+VALUE Covaro-Inhibit-Dbchg Y 1
+
+ATTRIBUTE Covaro-Inhibit-Pmrept 6 integer
+
+VALUE Covaro-Inhibit-Pmrept N 0
+VALUE Covaro-Inhibit-Pmrept Y 1
+
+END-VENDOR Covaro
+
diff --git a/share/dictionary.dante b/share/dictionary.dante
new file mode 100644
index 0000000..fc7b626
--- /dev/null
+++ b/share/dictionary.dante
@@ -0,0 +1,20 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# DANTE Vendor Specific Attributes Dictionary
+#
+# Created by Alan Buxey <a.l.m.buxey@lboro.ac.uk>
+#
+##############################################################################
+
+VENDOR DANTE 27262
+
+BEGIN-VENDOR DANTE
+
+ATTRIBUTE Default-TTL 1 integer
+
+END-VENDOR DANTE
+
diff --git a/share/dictionary.dellemc b/share/dictionary.dellemc
new file mode 100644
index 0000000..4a6d0af
--- /dev/null
+++ b/share/dictionary.dellemc
@@ -0,0 +1,19 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Dell Inc.
+#
+# DellEMC-AVpair Attribute-Value Pair.
+# DellEMC-Group-Name The Linux primary group name associated with the user.
+# This must be an existing group in /etc/groups.
+
+VENDOR DellEMC 674
+
+BEGIN-VENDOR DellEMC
+
+ATTRIBUTE DellEMC-AVpair 1 string
+ATTRIBUTE DellEMC-Group-Name 2 string
+
+END-VENDOR DellEMC
+
diff --git a/share/dictionary.dhcp b/share/dictionary.dhcp
new file mode 100644
index 0000000..e47aa1b
--- /dev/null
+++ b/share/dictionary.dhcp
@@ -0,0 +1,608 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# DHCP to RADUS gateway dictionary.
+#
+# http://www.iana.org/assignments/bootp-dhcp-parameters
+#
+# Also http://www.networksorcery.com/enp/protocol/bootp/options.htm
+#
+# http://www.bind9.net/rfc-dhcp
+#
+# $Id$
+#
+##############################################################################
+
+#
+
+# This is really Apollo's number, but since they're out of business,
+# I don't think they'll be needing this.
+#
+# HP owns the Apollo assets, but let's not worry about that.
+#
+# The vendor codes are 2 octets, because we need 256 numbers
+# for the base DHCP options, PLUS a few for the DHCP headers,
+# which aren't in option format.
+#
+# On top of that, a number of options are really TLV's.
+# We need to be able to understand them, too.
+#
+VENDOR DHCP 54 format=2,1
+
+BEGIN-VENDOR DHCP
+
+ATTRIBUTE DHCP-Opcode 256 byte
+
+VALUE DHCP-Opcode Client-Message 1
+VALUE DHCP-Opcode Server-Message 2
+
+ATTRIBUTE DHCP-Hardware-Type 257 byte
+ATTRIBUTE DHCP-Hardware-Address-Length 258 byte
+ATTRIBUTE DHCP-Hop-Count 259 byte
+ATTRIBUTE DHCP-Transaction-Id 260 integer
+ATTRIBUTE DHCP-Number-of-Seconds 261 short
+ATTRIBUTE DHCP-Flags 262 short
+ATTRIBUTE DHCP-Client-IP-Address 263 ipaddr
+ATTRIBUTE DHCP-Your-IP-Address 264 ipaddr
+ATTRIBUTE DHCP-Server-IP-Address 265 ipaddr
+ATTRIBUTE DHCP-Gateway-IP-Address 266 ipaddr
+ATTRIBUTE DHCP-Client-Hardware-Address 267 ether # 16 octets
+ATTRIBUTE DHCP-Server-Host-Name 268 string # 64 octets
+ATTRIBUTE DHCP-Boot-Filename 269 string # 128 octets
+
+ATTRIBUTE DHCP-Relay-To-IP-Address 270 ipaddr
+ATTRIBUTE DHCP-Relay-Max-Hop-Count 271 integer
+
+# This is copied from the request packet, giaddr, and
+# added to the reply packet by the server core.
+ATTRIBUTE DHCP-Relay-IP-Address 272 ipaddr
+
+# This address is assigned on a hierarchical basis to then determine
+# the subnet which the client belongs to. Stored as an ipv4prefix
+# to allow closest subnet matching in rlm_files
+ATTRIBUTE DHCP-Network-Subnet 274 ipv4prefix
+
+# This is a name for the group a client belongs to then used for
+# looking up of options
+ATTRIBUTE DHCP-Group-Name 275 string
+
+# These are for controlling option lookups
+ATTRIBUTE DHCP-SQL-Option-Identifier 276 string
+ATTRIBUTE DHCP-SQL-Option-Context 277 string
+
+VALUE DHCP-Flags Broadcast 0x8000
+
+VALUE DHCP-Hardware-Type Ethernet 1
+VALUE DHCP-Hardware-Type Experiemental-Ethernet 2
+VALUE DHCP-Hardware-Type AX.25 3
+VALUE DHCP-Hardware-Type Proteon-Token-Ring 4
+VALUE DHCP-Hardware-Type Chaos 5
+VALUE DHCP-Hardware-Type IEEE-802 6
+VALUE DHCP-Hardware-Type Arcnet 7
+VALUE DHCP-Hardware-Type Hyperchannel 8
+VALUE DHCP-Hardware-Type Lanstar 9
+VALUE DHCP-Hardware-Type Autonet-Short-Address 10
+VALUE DHCP-Hardware-Type LocalTalk 11
+VALUE DHCP-Hardware-Type LocalNet 12
+VALUE DHCP-Hardware-Type Ultra-Link 13
+VALUE DHCP-Hardware-Type SMDS 14
+VALUE DHCP-Hardware-Type Frame-Relay 15
+VALUE DHCP-Hardware-Type ATM-16 16
+VALUE DHCP-Hardware-Type HDLC 17
+VALUE DHCP-Hardware-Type Fibre-Channel 18
+VALUE DHCP-Hardware-Type ATM-19 19
+VALUE DHCP-Hardware-Type Serial-Line 20
+VALUE DHCP-Hardware-Type ATM-21 21
+VALUE DHCP-Hardware-Type MIL-STD-188-220 22
+VALUE DHCP-Hardware-Type Metricom 23
+VALUE DHCP-Hardware-Type IEEE-1394 24
+VALUE DHCP-Hardware-Type MAPOS 25
+VALUE DHCP-Hardware-Type Twinaxial 26
+VALUE DHCP-Hardware-Type EUI-64 27
+VALUE DHCP-Hardware-Type HIPARP 28
+VALUE DHCP-Hardware-Type IP-Over-ISO-7816-3 29
+VALUE DHCP-Hardware-Type ARPSec 30
+VALUE DHCP-Hardware-Type IPSec-Tunnel 31
+VALUE DHCP-Hardware-Type Infiniband 32
+VALUE DHCP-Hardware-Type CAI-TIA-102 33
+VALUE DHCP-Hardware-Type Wiegand-Interface 34
+VALUE DHCP-Hardware-Type Pure-IP 35
+VALUE DHCP-Hardware-Type HW-EXP1 36
+VALUE DHCP-Hardware-Type HFI 37
+#
+# 38-255 Unassigned
+#
+
+##############################################################################
+#
+# DHCP Options, with comments. For now, many are "octets",
+# as FreeRADIUS doesn't handle complex data structures.
+#
+##############################################################################
+
+#ATTRIBUTE DHCP-Pad 0 octets
+ATTRIBUTE DHCP-Subnet-Mask 1 ipaddr
+# Time Offset in twos-complement notation.
+ATTRIBUTE DHCP-Time-Offset 2 integer
+ATTRIBUTE DHCP-Router-Address 3 ipaddr array
+ATTRIBUTE DHCP-Time-Server 4 ipaddr array
+ATTRIBUTE DHCP-IEN-116-Name-Server 5 ipaddr array
+ATTRIBUTE DHCP-Domain-Name-Server 6 ipaddr array
+# Logging-Server addresses
+ATTRIBUTE DHCP-Log-Server 7 ipaddr array
+ATTRIBUTE DHCP-Quotes-Server 8 ipaddr array
+ATTRIBUTE DHCP-LPR-Server 9 ipaddr array
+ATTRIBUTE DHCP-Impress-Server 10 ipaddr array
+ATTRIBUTE DHCP-RLP-Server 11 ipaddr array
+# Hostname string
+ATTRIBUTE DHCP-Hostname 12 string
+# Size of boot file in 512 byte
+ATTRIBUTE DHCP-Boot-File-Size 13 short
+# Client to dump and name
+ATTRIBUTE DHCP-Merit-Dump-File 14 octets
+ATTRIBUTE DHCP-Domain-Name 15 string
+ATTRIBUTE DHCP-Swap-Server 16 ipaddr
+# Path name for root disk
+ATTRIBUTE DHCP-Root-Path 17 string
+ATTRIBUTE DHCP-Bootp-Extensions-Path 18 string
+ATTRIBUTE DHCP-IP-Forward-Enable 19 byte
+ATTRIBUTE DHCP-Source-Route-Enable 20 byte
+# Routing Policy Filters
+ATTRIBUTE DHCP-Policy-Filter 21 octets
+ATTRIBUTE DHCP-Max-Datagram-Reassembly-Size 22 short
+ATTRIBUTE DHCP-Default-IP-TTL 23 octets
+ATTRIBUTE DHCP-Path-MTU-Aging-Timeout 24 integer
+ATTRIBUTE DHCP-Path-MTU-Plateau-Table 25 short array
+ATTRIBUTE DHCP-Interface-MTU-Size 26 short
+ATTRIBUTE DHCP-All-Subnets-Are-Local 27 byte
+ATTRIBUTE DHCP-Broadcast-Address 28 ipaddr
+ATTRIBUTE DHCP-Perform-Mask-Discovery 29 byte
+ATTRIBUTE DHCP-Provide-Mask-To-Others 30 byte
+ATTRIBUTE DHCP-Perform-Router-Discovery 31 byte
+ATTRIBUTE DHCP-Router-Solicitation-Address 32 ipaddr
+# first is destination address, second is router.
+ATTRIBUTE DHCP-Static-Routes 33 ipaddr array
+ATTRIBUTE DHCP-Trailer-Encapsulation 34 byte
+ATTRIBUTE DHCP-ARP-Cache-Timeout 35 integer
+ATTRIBUTE DHCP-Ethernet-Encapsulation 36 byte
+ATTRIBUTE DHCP-Default-TCP-TTL 37 byte
+ATTRIBUTE DHCP-Keep-Alive-Interval 38 integer
+ATTRIBUTE DHCP-Keep-Alive-Garbage 39 byte
+ATTRIBUTE DHCP-NIS-Domain-Name 40 string
+ATTRIBUTE DHCP-NIS-Servers 41 ipaddr array
+ATTRIBUTE DHCP-NTP-Servers 42 ipaddr array
+# N Vendor Specific Information
+ATTRIBUTE DHCP-Vendor 43 octets # tlv
+ATTRIBUTE DHCP-NETBIOS-Name-Servers 44 ipaddr array
+ATTRIBUTE DHCP-NETBIOS-Dgm-Dist-Servers 45 ipaddr array
+ATTRIBUTE DHCP-NETBIOS-Node-Type 46 byte
+# N NETBIOS Scope
+ATTRIBUTE DHCP-NETBIOS 47 octets
+ATTRIBUTE DHCP-X-Window-Font-Server 48 ipaddr array
+ATTRIBUTE DHCP-X-Window-Display-Mgr 49 ipaddr array
+ATTRIBUTE DHCP-Requested-IP-Address 50 ipaddr
+ATTRIBUTE DHCP-IP-Address-Lease-Time 51 integer
+# Overload "sname" or "file"
+ATTRIBUTE DHCP-Overload 52 byte
+ATTRIBUTE DHCP-Message-Type 53 byte
+
+VALUE DHCP-Message-Type DHCP-Do-Not-Respond 0
+VALUE DHCP-Message-Type DHCP-Discover 1
+VALUE DHCP-Message-Type DHCP-Offer 2
+VALUE DHCP-Message-Type DHCP-Request 3
+VALUE DHCP-Message-Type DHCP-Decline 4
+VALUE DHCP-Message-Type DHCP-Ack 5
+VALUE DHCP-Message-Type DHCP-NAK 6
+VALUE DHCP-Message-Type DHCP-Release 7
+VALUE DHCP-Message-Type DHCP-Inform 8
+VALUE DHCP-Message-Type DHCP-Force-Renew 9
+VALUE DHCP-Message-Type DHCP-Lease-Query 10
+VALUE DHCP-Message-Type DHCP-Lease-Unassigned 11
+VALUE DHCP-Message-Type DHCP-Lease-Unknown 12
+VALUE DHCP-Message-Type DHCP-Lease-Active 13
+VALUE DHCP-Message-Type DHCP-Bulk-Lease-Query 14
+VALUE DHCP-Message-Type DHCP-Lease-Query-Done 15
+
+ATTRIBUTE DHCP-DHCP-Server-Identifier 54 ipaddr
+
+# Array of 1-byte numbers indicating which options the client
+# would like to see in the response.
+ATTRIBUTE DHCP-Parameter-Request-List 55 byte array
+ATTRIBUTE DHCP-DHCP-Error-Message 56 string
+ATTRIBUTE DHCP-DHCP-Maximum-Msg-Size 57 short
+ATTRIBUTE DHCP-Renewal-Time 58 integer
+ATTRIBUTE DHCP-Rebinding-Time 59 integer
+ATTRIBUTE DHCP-Vendor-Class-Identifier 60 octets
+
+# Client Identifier
+# First octet MAY be DHCP-Hardware-Type, rest are type-specific data,
+# e.g. MAC address. It's up to the administrator to make sense of
+# the value. We can't do anything more in the parser.
+ATTRIBUTE DHCP-Client-Identifier 61 octets
+ATTRIBUTE DHCP-Netware-Domain-Name 62 octets
+ATTRIBUTE DHCP-Netware-Sub-Options 63 octets
+ATTRIBUTE DHCP-NIS-Client-Domain-Name 64 octets
+ATTRIBUTE DHCP-NIS-Server-Address 65 ipaddr
+ATTRIBUTE DHCP-TFTP-Server-Name 66 string
+ATTRIBUTE DHCP-Boot-File-Name 67 string
+# Home Agent Addresses
+ATTRIBUTE DHCP-Home-Agent-Address 68 octets
+ATTRIBUTE DHCP-SMTP-Server-Address 69 ipaddr array
+ATTRIBUTE DHCP-POP3-Server-Address 70 ipaddr array
+ATTRIBUTE DHCP-NNTP-Server-Address 71 ipaddr array
+ATTRIBUTE DHCP-WWW-Server-Address 72 ipaddr array
+ATTRIBUTE DHCP-Finger-Server-Address 73 ipaddr array
+ATTRIBUTE DHCP-IRC-Server-Address 74 ipaddr array
+ATTRIBUTE DHCP-StreetTalk-Server-Address 75 ipaddr array
+ATTRIBUTE DHCP-STDA-Server-Address 76 ipaddr array
+# User Class Information
+ATTRIBUTE DHCP-User-Class 77 octets
+# directory agent information
+ATTRIBUTE DHCP-Directory-Agent 78 octets
+# service location agent scope
+ATTRIBUTE DHCP-Service-Scope 79 octets
+# Rapid Commit
+ATTRIBUTE DHCP-Rapid-Commit 80 octets
+# Fully Qualified Domain Name
+ATTRIBUTE DHCP-Client-FQDN 81 octets
+# Relay Agent Information
+ATTRIBUTE DHCP-Relay-Agent-Information 82 tlv
+
+ATTRIBUTE DHCP-Agent-Circuit-Id 82.1 octets
+ATTRIBUTE DHCP-Agent-Remote-Id 82.2 octets
+
+ATTRIBUTE DHCP-Relay-Circuit-Id 82.1 octets
+ATTRIBUTE DHCP-Relay-Remote-Id 82.2 octets
+
+# 3 is reserved and shouldn't be used for anything
+ATTRIBUTE DHCP-Docsis-Device-Class 82.4 integer
+ATTRIBUTE DHCP-Relay-Link-Selection 82.5 ipaddr
+ATTRIBUTE DHCP-Subscriber-Id 82.6 string
+
+
+
+# AGH! RADIUS inside of DHCP!
+ATTRIBUTE DHCP-RADIUS-Attributes 82.7 octets
+
+# Horribly complicated
+ATTRIBUTE DHCP-Authentication-Information 82.8 octets
+
+#
+# We'll fix this later
+#
+ATTRIBUTE DHCP-Vendor-Specific-Information 82.9 octets
+
+ATTRIBUTE DHCP-Relay-Agent-Flags 82.10 byte
+ATTRIBUTE DHCP-Server-Identifier-Override 82.11 ipaddr
+
+# Values are in https://www.rfc-editor.org/rfc/rfc5213
+ATTRIBUTE Access-Technology-Type 82.13 uint16
+ATTRIBUTE Network-Name 82.14 string
+ATTRIBUTE Access-Point-Name 82.15 string
+ATTRIBUTE Access-Point-BSSID 82.16 octets # 6 octets
+
+#
+# Section 4.4.1 says that the length is variable, but the "Length"
+# field says it's "4". We've filed an errata to change it to uint32.
+#
+# And both of these definitions refer to https://www.rfc-editor.org/rfc/rfc6757
+#
+ATTRIBUTE Operator-Identifier 82.17 uint32
+ATTRIBUTE Operator-Realm 82.18 string
+
+ATTRIBUTE Remember-Relay-Port 82.19 octets # 0-length, true=exists
+
+# Internet Storage Name Service
+ATTRIBUTE DHCP-iSNS 83 octets
+# Novell Directory Services
+ATTRIBUTE DHCP-NDS-Servers 85 octets
+# Novell Directory Services
+ATTRIBUTE DHCP-NDS-Tree-Name 86 octets
+# Novell Directory Services
+ATTRIBUTE DHCP-NDS-Context 87 octets
+
+# RFC 4280 - Broadcast and Multicast Control Servers
+ATTRIBUTE DHCP-BCMS-Server-IPv4-FQDN 88 string array
+ATTRIBUTE DHCP-BCMS-Server-IPv4-Address 89 ipaddr array
+
+# Authentication
+ATTRIBUTE DHCP-Authentication 90 octets
+
+ATTRIBUTE DHCP-Client-Last-Txn-Time 91 integer # seconds in the past
+
+ATTRIBUTE DHCP-associated-ip 92 octets
+# Client System Architecture
+ATTRIBUTE DHCP-Client-System 93 octets
+# Client Network Device Interface
+ATTRIBUTE DHCP-Client-NDI 94 octets
+# Lightweight Directory Access Protocol
+ATTRIBUTE DHCP-LDAP 95 octets
+# UUID/GUID-based Client Identifier
+ATTRIBUTE DHCP-UUID/GUID 97 octets
+# Open Group's User Authentication
+ATTRIBUTE DHCP-User-Auth 98 octets
+
+# RFC 4776 - Option for Civic Addresses Configuration Information
+ATTRIBUTE DHCP-GeoConf-Civic 99 octets
+
+# RFC 4833 - Timezone Options for DHCP
+ATTRIBUTE DHCP-Timezone-Posix 100 string
+ATTRIBUTE DHCP-Timezone-Database 101 string
+
+# NetInfo Parent-Server Address
+ATTRIBUTE DHCP-Netinfo-Address 112 octets
+# NetInfo Parent-Server Tag
+ATTRIBUTE DHCP-Netinfo-Tag 113 octets
+# URL
+ATTRIBUTE DHCP-URL 114 octets
+# DHCP Auto-Configuration
+ATTRIBUTE DHCP-Auto-Config 116 byte
+# Name Service Search
+ATTRIBUTE DHCP-Name-Service-Search 117 octets
+# Subnet Selection Option
+ATTRIBUTE DHCP-Subnet-Selection-Option 118 ipaddr
+# DNS domain serach list
+ATTRIBUTE DHCP-Domain-Search 119 octets
+# SIP-Servers DHCP Option
+ATTRIBUTE DHCP-SIP-Servers-DHCP-Option 120 octets
+# Classless Static Route Option
+ATTRIBUTE DHCP-Classless-Static-Route 121 octets
+# CableLabs Client Configuration
+ATTRIBUTE DHCP-CCC 122 octets
+# 16 GeoConf Option
+ATTRIBUTE DHCP-GeoConf-Option 123 octets
+
+# Vendor Class
+#
+# String name that defines the vendor space used for the TLV's
+# in option 125.
+#
+ATTRIBUTE DHCP-V-I-Vendor-Class 124 octets
+# Vendor-Specific
+ATTRIBUTE DHCP-V-I-Vendor-Specific 125 octets # tlv
+
+ATTRIBUTE DHCP-Etherboot 128 ether
+# (for IP Phone software load)
+
+# RFC 4578 - Options for the Intel Preboot eXecution Environment
+ATTRIBUTE DHCP-TFTP-Server-IP-Address 128 octets
+ATTRIBUTE DHCP-Call-Server-IP-address 129 octets
+ATTRIBUTE DHCP-Ethernet-Interface 130 octets
+ATTRIBUTE DHCP-Vendor-Discrimination-Str 130 octets
+ATTRIBUTE DHCP-Remote-Stats-Svr-IP-Address 131 octets
+ATTRIBUTE DHCP-IEEE-802.1Q-VLAN-ID 132 octets
+ATTRIBUTE DHCP-IEEE-802.1P-L2-Priority 133 octets
+ATTRIBUTE DHCP-Diffserv-Code-Point 134 octets
+ATTRIBUTE DHCP-HTTP-Proxy 135 octets
+
+# RFC 5192 - PANA Authentication Agent
+ATTRIBUTE DHCP-PANA-Agent 136 ipaddr array
+
+# RFC 5223 - Discovering Location-to-Service Translation (LoST)
+ATTRIBUTE DHCP-LoST-Server 137 octets
+
+# RFC 5417 - CAPWAP Access Controller DHCP Option
+ATTRIBUTE DHCP-CAPWAP-AC-IPv4-Address 138 ipaddr array
+
+# RFC 5678 - Options for IEEE 802.21 Mobility Services (MoS)
+ATTRIBUTE DHCP-MoS-IPv4-Address 139 tlv
+ATTRIBUTE DHCP-MoS-IPv4-Address-IS 139.1 ipaddr array
+ATTRIBUTE DHCP-MoS-IPv4-Address-CS 139.2 ipaddr array
+ATTRIBUTE DHCP-MoS-IPv4-Address-ES 139.3 ipaddr array
+
+ATTRIBUTE DHCP-MoS-IPv4-FQDN 140 tlv
+ATTRIBUTE DHCP-MoS-IPv4-FQDN-IS 140.1 string array
+ATTRIBUTE DHCP-MoS-IPv4-FQDN-CS 140.2 string array
+ATTRIBUTE DHCP-MoS-IPv4-FQDN-ES 140.3 string array
+
+# RFC 6011 - SIP UA Configuration Service Domains
+ATTRIBUTE DHCP-SIP-UA-Configuration-Service-Domains 141 string
+
+# RFC 6153 - Access Network Discovery and Selection Function (ANDSF)
+ATTRIBUTE DHCP-ANDSF-IPv4-Address 142 ipaddr array
+ATTRIBUTE DHCP-ANDSF-IPv6-Address 143 ipv6addr array
+
+# 144 - 149 unused
+
+ATTRIBUTE DHCP-TFTP-Server-IPv4-Address 150 ipaddr array
+
+# RFC 6926 - Bulk Lease Query
+ATTRIBUTE DHCP-Query-Status-Code 151 octets
+ATTRIBUTE DHCP-Query-Server-Base-Time 152 date
+ATTRIBUTE DHCP-Query-Start-Time-Of-State 153 integer
+ATTRIBUTE DHCP-Query-Start-Time 154 date
+ATTRIBUTE DHCP-Query-End-Time 155 date
+ATTRIBUTE DHCP-State 156 byte
+
+VALUE DHCP-State Available 1
+VALUE DHCP-State Active 2
+VALUE DHCP-State Expired 3
+VALUE DHCP-State Released 4
+VALUE DHCP-State Abandoned 5
+VALUE DHCP-State Reset 6
+VALUE DHCP-State Remote 7
+VALUE DHCP-State Transitioning 8
+
+ATTRIBUTE DHCP-Data-Source 157 byte
+
+# RFC draft-ietf-pcp-dhcp-13
+ATTRIBUTE DHCP-PCP-IPv4-Server-Address 158 octets # Complex format (not just ipaddr array)
+
+# RFC 3942 - 159-174 - Unassigned
+# RFC 3942 - 178-207 - Unassigned
+
+# RFC 5071 - PXELINUX
+ATTRIBUTE DHCP-PXELINUX-Magic 208 octets
+ATTRIBUTE DHCP-Packet-Format 209 string
+ATTRIBUTE DHCP-Path-Prefix 210 string
+ATTRIBUTE DHCP-Reboot-Time 211 date
+
+# RFC 5969 - IPv6 Rapid Deployment on IPv4 Infrastructures (6rd)
+ATTRIBUTE DHCP-6RD 212 octets
+
+# RFC 5986 - Discovering the Local Location Information Server (LIS)
+ATTRIBUTE DHCP-Access-Network-Domain-Name 213 string array
+
+# RFC 3942 - 214-219 - Unassigned
+
+# RFC 6656 - Subnet Allocation Option
+ATTRIBUTE DHCP-Virtual-Subnet-Allocation 220 octets # Complex format not just tlv
+ATTRIBUTE DHCP-Virtual-Subnet-Selection 221 octets # Complex format not just tlv
+
+# RFC 3942 - 224-253 - Site Specific
+ATTRIBUTE DHCP-Site-specific-0 224 octets
+ATTRIBUTE DHCP-Site-specific-1 225 octets
+ATTRIBUTE DHCP-Site-specific-2 226 octets
+ATTRIBUTE DHCP-Site-specific-3 227 octets
+ATTRIBUTE DHCP-Site-specific-4 228 octets
+ATTRIBUTE DHCP-Site-specific-5 229 octets
+ATTRIBUTE DHCP-Site-specific-6 230 octets
+ATTRIBUTE DHCP-Site-specific-7 231 octets
+ATTRIBUTE DHCP-Site-specific-8 232 octets
+ATTRIBUTE DHCP-Site-specific-9 233 octets
+ATTRIBUTE DHCP-Site-specific-10 234 octets
+ATTRIBUTE DHCP-Site-specific-11 235 octets
+ATTRIBUTE DHCP-Site-specific-12 236 octets
+ATTRIBUTE DHCP-Site-specific-13 237 octets
+ATTRIBUTE DHCP-Site-specific-14 238 octets
+ATTRIBUTE DHCP-Site-specific-15 239 octets
+ATTRIBUTE DHCP-Site-specific-16 240 octets
+ATTRIBUTE DHCP-Site-specific-17 241 octets
+ATTRIBUTE DHCP-Site-specific-18 242 octets
+ATTRIBUTE DHCP-Site-specific-19 243 octets
+ATTRIBUTE DHCP-Site-specific-20 244 octets
+ATTRIBUTE DHCP-Site-specific-21 245 octets
+ATTRIBUTE DHCP-Site-specific-22 246 octets
+ATTRIBUTE DHCP-Site-specific-23 247 octets
+ATTRIBUTE DHCP-Site-specific-24 248 octets
+ATTRIBUTE DHCP-Site-specific-25 249 octets
+ATTRIBUTE DHCP-Site-specific-26 250 octets
+ATTRIBUTE DHCP-Site-specific-27 251 octets
+ATTRIBUTE DHCP-Site-specific-28 252 octets
+ATTRIBUTE DHCP-Site-specific-29 253 octets
+ATTRIBUTE DHCP-Site-specific-30 253 octets
+
+ATTRIBUTE DHCP-End-Of-Options 255 byte
+
+VALUE DHCP-Parameter-Request-List DHCP-Subnet-Mask 1
+VALUE DHCP-Parameter-Request-List DHCP-Time-Offset 2
+VALUE DHCP-Parameter-Request-List DHCP-Router-Address 3
+VALUE DHCP-Parameter-Request-List DHCP-Time-Server 4
+VALUE DHCP-Parameter-Request-List DHCP-IEN-116-Name-Server 5
+VALUE DHCP-Parameter-Request-List DHCP-Domain-Name-Server 6
+VALUE DHCP-Parameter-Request-List DHCP-Log-Server 7
+VALUE DHCP-Parameter-Request-List DHCP-Quotes-Server 8
+VALUE DHCP-Parameter-Request-List DHCP-LPR-Server 9
+VALUE DHCP-Parameter-Request-List DHCP-Impress-Server 10
+VALUE DHCP-Parameter-Request-List DHCP-RLP-Server 11
+VALUE DHCP-Parameter-Request-List DHCP-Hostname 12
+VALUE DHCP-Parameter-Request-List DHCP-Boot-File-Size 13
+VALUE DHCP-Parameter-Request-List DHCP-Merit-Dump-File 14
+VALUE DHCP-Parameter-Request-List DHCP-Domain-Name 15
+VALUE DHCP-Parameter-Request-List DHCP-Swap-Server 16
+VALUE DHCP-Parameter-Request-List DHCP-Root-Path 17
+VALUE DHCP-Parameter-Request-List DHCP-Bootp-Extensions-Path 18
+VALUE DHCP-Parameter-Request-List DHCP-IP-Forward-Enable 19
+VALUE DHCP-Parameter-Request-List DHCP-Source-Route-Enable 20
+VALUE DHCP-Parameter-Request-List DHCP-Policy-Filter 21
+VALUE DHCP-Parameter-Request-List DHCP-Max-Datagram-Reassembly-Sz 22
+VALUE DHCP-Parameter-Request-List DHCP-Default-IP-TTL 23
+VALUE DHCP-Parameter-Request-List DHCP-Path-MTU-Aging-Timeout 24
+VALUE DHCP-Parameter-Request-List DHCP-Path-MTU-Plateau-Table 25
+VALUE DHCP-Parameter-Request-List DHCP-Interface-MTU-Size 26
+VALUE DHCP-Parameter-Request-List DHCP-All-Subnets-Are-Local 27
+VALUE DHCP-Parameter-Request-List DHCP-Broadcast-Address 28
+VALUE DHCP-Parameter-Request-List DHCP-Perform-Mask-Discovery 29
+VALUE DHCP-Parameter-Request-List DHCP-Provide-Mask-To-Others 30
+VALUE DHCP-Parameter-Request-List DHCP-Perform-Router-Discovery 31
+VALUE DHCP-Parameter-Request-List DHCP-Router-Solicitation-Address 32
+VALUE DHCP-Parameter-Request-List DHCP-Static-Routes 33
+VALUE DHCP-Parameter-Request-List DHCP-Trailer-Encapsulation 34
+VALUE DHCP-Parameter-Request-List DHCP-ARP-Cache-Timeout 35
+VALUE DHCP-Parameter-Request-List DHCP-Ethernet-Encapsulation 36
+VALUE DHCP-Parameter-Request-List DHCP-Default-TCP-TTL 37
+VALUE DHCP-Parameter-Request-List DHCP-Keep-Alive-Interval 38
+VALUE DHCP-Parameter-Request-List DHCP-Keep-Alive-Garbage 39
+VALUE DHCP-Parameter-Request-List DHCP-NIS-Domain-Name 40
+VALUE DHCP-Parameter-Request-List DHCP-NIS-Servers 41
+VALUE DHCP-Parameter-Request-List DHCP-NTP-Servers 42
+VALUE DHCP-Parameter-Request-List DHCP-Vendor 43
+VALUE DHCP-Parameter-Request-List DHCP-NETBIOS-Name-Servers 44
+VALUE DHCP-Parameter-Request-List DHCP-NETBIOS-Dgm-Dist-Servers 45
+VALUE DHCP-Parameter-Request-List DHCP-NETBIOS-Node-Type 46
+VALUE DHCP-Parameter-Request-List DHCP-NETBIOS 47
+VALUE DHCP-Parameter-Request-List DHCP-X-Window-Font-Server 48
+VALUE DHCP-Parameter-Request-List DHCP-X-Window-Display-Mgr 49
+VALUE DHCP-Parameter-Request-List DHCP-Requested-IP-Address 50
+VALUE DHCP-Parameter-Request-List DHCP-IP-Address-Lease-Time 51
+VALUE DHCP-Parameter-Request-List DHCP-Overload 52
+VALUE DHCP-Parameter-Request-List DHCP-Message-Type 53
+VALUE DHCP-Parameter-Request-List DHCP-DHCP-Server-Identifier 54
+VALUE DHCP-Parameter-Request-List DHCP-Parameter-Request-List 55
+VALUE DHCP-Parameter-Request-List DHCP-DHCP-Error-Message 56
+VALUE DHCP-Parameter-Request-List DHCP-DHCP-Maximum-Msg-Size 57
+VALUE DHCP-Parameter-Request-List DHCP-Renewal-Time 58
+VALUE DHCP-Parameter-Request-List DHCP-Rebinding-Time 59
+VALUE DHCP-Parameter-Request-List DHCP-Class-Identifier 60
+VALUE DHCP-Parameter-Request-List DHCP-Client-Identifier 61
+VALUE DHCP-Parameter-Request-List DHCP-Netware-Domain-Name 62
+VALUE DHCP-Parameter-Request-List DHCP-Netware-Sub-Options 63
+VALUE DHCP-Parameter-Request-List DHCP-NIS-Client-Domain-Name 64
+VALUE DHCP-Parameter-Request-List DHCP-NIS-Server-Address 65
+VALUE DHCP-Parameter-Request-List DHCP-TFTP-Server-Name 66
+VALUE DHCP-Parameter-Request-List DHCP-Boot-File-Name 67
+VALUE DHCP-Parameter-Request-List DHCP-Home-Agent-Address 68
+VALUE DHCP-Parameter-Request-List DHCP-SMTP-Server-Address 69
+VALUE DHCP-Parameter-Request-List DHCP-POP3-Server-Address 70
+VALUE DHCP-Parameter-Request-List DHCP-NNTP-Server-Address 71
+VALUE DHCP-Parameter-Request-List DHCP-WWW-Server-Address 72
+VALUE DHCP-Parameter-Request-List DHCP-Finger-Server-Address 73
+VALUE DHCP-Parameter-Request-List DHCP-IRC-Server-Address 74
+VALUE DHCP-Parameter-Request-List DHCP-StreetTalk-Server-Address 75
+VALUE DHCP-Parameter-Request-List DHCP-STDA-Server-Address 76
+VALUE DHCP-Parameter-Request-List DHCP-User-Class 77
+VALUE DHCP-Parameter-Request-List DHCP-Directory-Agent 78
+VALUE DHCP-Parameter-Request-List DHCP-Service-Scope 79
+VALUE DHCP-Parameter-Request-List DHCP-Rapid-Commit 80
+VALUE DHCP-Parameter-Request-List DHCP-Client-FQDN 81
+VALUE DHCP-Parameter-Request-List DHCP-Relay-Agent-Information 82
+VALUE DHCP-Parameter-Request-List DHCP-iSNS 83
+VALUE DHCP-Parameter-Request-List DHCP-NDS-Servers 85
+VALUE DHCP-Parameter-Request-List DHCP-NDS-Tree-Name 86
+VALUE DHCP-Parameter-Request-List DHCP-NDS-Context 87
+VALUE DHCP-Parameter-Request-List DHCP-Authentication 90
+VALUE DHCP-Parameter-Request-List DHCP-Client-Last-Txn-Time 91
+VALUE DHCP-Parameter-Request-List DHCP-associated-ip 92
+VALUE DHCP-Parameter-Request-List DHCP-Client-System 93
+VALUE DHCP-Parameter-Request-List DHCP-Client-NDI 94
+VALUE DHCP-Parameter-Request-List DHCP-LDAP 95
+VALUE DHCP-Parameter-Request-List DHCP-UUID/GUID 97
+VALUE DHCP-Parameter-Request-List DHCP-User-Auth 98
+VALUE DHCP-Parameter-Request-List DHCP-Netinfo-Address 112
+VALUE DHCP-Parameter-Request-List DHCP-Netinfo-Tag 113
+VALUE DHCP-Parameter-Request-List DHCP-URL 114
+VALUE DHCP-Parameter-Request-List DHCP-Auto-Config 116
+VALUE DHCP-Parameter-Request-List DHCP-Name-Service-Search 117
+VALUE DHCP-Parameter-Request-List DHCP-Subnet-Selection-Option 118
+VALUE DHCP-Parameter-Request-List DHCP-Domain-Search 119
+VALUE DHCP-Parameter-Request-List DHCP-SIP-Servers-DHCP-Option 120
+VALUE DHCP-Parameter-Request-List DHCP-Classless-Static-Route 121
+VALUE DHCP-Parameter-Request-List DHCP-CCC 122
+VALUE DHCP-Parameter-Request-List DHCP-GeoConf-Option 123
+VALUE DHCP-Parameter-Request-List DHCP-V-I-Vendor-Class 124
+VALUE DHCP-Parameter-Request-List DHCP-V-I-Vendor-Specific 125
+VALUE DHCP-Parameter-Request-List DHCP-Etherboot 128
+VALUE DHCP-Parameter-Request-List DHCP-TFTP-Server-IP-Address 128
+VALUE DHCP-Parameter-Request-List DHCP-Call-Server-IP-address 129
+VALUE DHCP-Parameter-Request-List DHCP-Ethernet-Interface 130
+VALUE DHCP-Parameter-Request-List DHCP-Vendor-Discrimination-Str 130
+VALUE DHCP-Parameter-Request-List DHCP-Remote-Stats-Svr-IP-Address 131
+VALUE DHCP-Parameter-Request-List DHCP-IEEE-802.1P-VLAN-ID 132
+VALUE DHCP-Parameter-Request-List DHCP-IEEE-802.1Q-L2-Priority 133
+VALUE DHCP-Parameter-Request-List DHCP-Diffserv-Code-Point 134
+VALUE DHCP-Parameter-Request-List DHCP-HTTP-Proxy 135
+
+END-VENDOR DHCP
diff --git a/share/dictionary.digium b/share/dictionary.digium
new file mode 100644
index 0000000..937f2d4
--- /dev/null
+++ b/share/dictionary.digium
@@ -0,0 +1,39 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Digium's Asterisk specific radius attributes
+# markster@digium.com
+#
+# http://bugs.digium.com/file_download.php\?file_id=9688\&type=bug
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR Digium 22736
+
+BEGIN-VENDOR Digium
+
+ATTRIBUTE Asterisk-Acc-Code 101 string
+ATTRIBUTE Asterisk-Src 102 string
+ATTRIBUTE Asterisk-Dst 103 string
+ATTRIBUTE Asterisk-Dst-Ctx 104 string
+ATTRIBUTE Asterisk-Clid 105 string
+ATTRIBUTE Asterisk-Chan 106 string
+ATTRIBUTE Asterisk-Dst-Chan 107 string
+ATTRIBUTE Asterisk-Last-App 108 string
+ATTRIBUTE Asterisk-Last-Data 109 string
+ATTRIBUTE Asterisk-Start-Time 110 string
+ATTRIBUTE Asterisk-Answer-Time 111 string
+ATTRIBUTE Asterisk-End-Time 112 string
+ATTRIBUTE Asterisk-Duration 113 integer
+ATTRIBUTE Asterisk-Bill-Sec 114 integer
+ATTRIBUTE Asterisk-Disposition 115 string
+ATTRIBUTE Asterisk-AMA-Flags 116 string
+ATTRIBUTE Asterisk-Unique-ID 117 string
+ATTRIBUTE Asterisk-User-Field 118 string
+
+END-VENDOR Digium
diff --git a/share/dictionary.dlink b/share/dictionary.dlink
new file mode 100644
index 0000000..2048c8b
--- /dev/null
+++ b/share/dictionary.dlink
@@ -0,0 +1,37 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# D-Link Vendor Specific Attributes Dictionary
+#
+# Created by Sylph Lin <sylph.lin@gmail.com>
+#
+# Version $Id$
+#
+##############################################################################
+
+VENDOR Dlink 171
+
+BEGIN-VENDOR Dlink
+
+ATTRIBUTE Dlink-User-Level 1 integer
+ATTRIBUTE Dlink-Ingress-Bandwidth-Assignment 2 integer
+ATTRIBUTE Dlink-Egress-Bandwidth-Assignment 3 integer
+ATTRIBUTE Dlink-1p-Priority 4 integer
+ATTRIBUTE Dlink-VLAN-Name 10 string
+ATTRIBUTE Dlink-VLAN-ID 11 string
+ATTRIBUTE Dlink-ACL-Profile 12 string
+ATTRIBUTE Dlink-ACL-Rule 13 string
+ATTRIBUTE Dlink-ACL-Script 14 string
+
+VALUE Dlink-User-Level User-Legacy 1
+VALUE Dlink-User-Level User 3
+VALUE Dlink-User-Level Operator 4
+VALUE Dlink-User-Level Admin 5
+VALUE Dlink-User-Level Power-User 6
+VALUE Dlink-User-Level Admin-Legacy 15
+
+END-VENDOR Dlink
+
diff --git a/share/dictionary.dragonwave b/share/dictionary.dragonwave
new file mode 100644
index 0000000..daa18eb
--- /dev/null
+++ b/share/dictionary.dragonwave
@@ -0,0 +1,31 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Dragonwave
+# http://www.dragonwaveinc.comw
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR DragonWave 7262
+
+BEGIN-VENDOR DragonWave
+
+# Used to determine the user login privilege level.
+ATTRIBUTE DragonWave-Privilege-Level 1 integer
+
+# Read-only access.
+
+VALUE DragonWave-Privilege-Level DragonWave-Admin-User 1
+
+# Limited read-write access.
+VALUE DragonWave-Privilege-Level DragonWave-NOC-User 2
+
+# Unlimited read-write access.
+VALUE DragonWave-Privilege-Level DragonWave-Super-User 3
+
+END-VENDOR DragonWave
diff --git a/share/dictionary.efficientip b/share/dictionary.efficientip
new file mode 100644
index 0000000..3c6fb2c
--- /dev/null
+++ b/share/dictionary.efficientip
@@ -0,0 +1,31 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Efficient IP VSA's
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR EfficientIP 2440
+
+BEGIN-VENDOR EfficientIP
+
+ATTRIBUTE EfficientIP-Version 1 integer
+ATTRIBUTE EfficientIP-Service-Class 2 integer
+ATTRIBUTE EfficientIP-Identity-Type 3 integer
+ATTRIBUTE EfficientIP-First-Name 16 string
+ATTRIBUTE EfficientIP-Last-Name 17 string
+ATTRIBUTE EfficientIP-Pseudonym 18 string
+ATTRIBUTE EfficientIP-IP-Host 19 string
+ATTRIBUTE EfficientIP-Email 20 string
+ATTRIBUTE EfficientIP-First-Login-Path 32 string
+ATTRIBUTE EfficientIP-Maintainer-Group 33 string
+ATTRIBUTE EfficientIP-Groups 34 string
+ATTRIBUTE EfficientIP-Admin-Group 35 string
+ATTRIBUTE EfficientIP-Extra-Blob 64 string
+
+END-VENDOR EfficientIP
diff --git a/share/dictionary.eleven b/share/dictionary.eleven
new file mode 100644
index 0000000..93dabcb
--- /dev/null
+++ b/share/dictionary.eleven
@@ -0,0 +1,52 @@
+# -*- text -*-
+# Copyright (C) 2023 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Eleven Software
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR Eleven 52970
+
+BEGIN-VENDOR Eleven
+
+#
+# DPSK attributes
+#
+# The RADIUS server responds with two Cisco-AVPair attributes:
+#
+# Cisco-AVPair = "psk-mode=ascii"
+# Cisco-AVPair = "psk=<passphrase>"
+#
+#
+ATTRIBUTE Eleven-Authentication-Find-Key 3 tlv
+
+#
+# The second EAPoL frame of the 4-way handshake
+#
+ATTRIBUTE Eleven-EAPOL-Frame-2 3.1 octets
+
+#
+# The first EAPoL frame of the 4-way handshake.
+#
+ATTRIBUTE Eleven-EAPOL-Anonce 2 octets
+
+#
+# SSID name
+#
+ATTRIBUTE Eleven-EAPOL-SSID 3 string
+
+#
+# BSSID
+#
+ATTRIBUTE Eleven-EAPOL-APMAC 4 octets
+
+#
+# Wireless client MAC address.
+#
+ATTRIBUTE Eleven-EAPOL-STMAC 5 octets
+
diff --git a/share/dictionary.eltex b/share/dictionary.eltex
new file mode 100644
index 0000000..f4226d2
--- /dev/null
+++ b/share/dictionary.eltex
@@ -0,0 +1,26 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+
+VENDOR Eltex 35265
+
+BEGIN-VENDOR Eltex
+
+ATTRIBUTE Eltex-AVPair 1 string
+
+ATTRIBUTE Eltex-Disconnect-Code-Local 11 integer
+
+VALUE Eltex-Disconnect-Code-Local User-Answer 1
+VALUE Eltex-Disconnect-Code-Local Incomplete-Number 2
+VALUE Eltex-Disconnect-Code-Local Unassigned-Number 3
+VALUE Eltex-Disconnect-Code-Local Unsuccessful-Other-Cause 4
+VALUE Eltex-Disconnect-Code-Local User-Busy 5
+VALUE Eltex-Disconnect-Code-Local Out-of-Order 6
+VALUE Eltex-Disconnect-Code-Local No-Answer 7
+VALUE Eltex-Disconnect-Code-Local Unavailable-Trunk 8
+VALUE Eltex-Disconnect-Code-Local Access-Denied 9
+VALUE Eltex-Disconnect-Code-Local Unavailable-Voice-Channel 10
+VALUE Eltex-Disconnect-Code-Local RADIUS-Server-Unavailable 11
+
+END-VENDOR Eltex
diff --git a/share/dictionary.epygi b/share/dictionary.epygi
new file mode 100644
index 0000000..328e729
--- /dev/null
+++ b/share/dictionary.epygi
@@ -0,0 +1,118 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+
+VENDOR Epygi 16459
+
+#
+# Standard attribute
+#
+BEGIN-VENDOR Epygi
+
+ATTRIBUTE Epygi-AVPair 1 string
+ATTRIBUTE Epygi-NAS-Port 2 string
+
+#
+# Voice over IP attributes.
+#
+ATTRIBUTE Epygi-h323-remote-address 23 string
+ATTRIBUTE Epygi-h323-conf-id 24 string
+ATTRIBUTE Epygi-h323-setup-time 25 string
+ATTRIBUTE Epygi-h323-call-origin 26 string
+ATTRIBUTE Epygi-h323-call-type 27 string
+ATTRIBUTE Epygi-h323-connect-time 28 string
+ATTRIBUTE Epygi-h323-disconnect-time 29 string
+ATTRIBUTE Epygi-h323-disconnect-cause 30 string
+ATTRIBUTE Epygi-h323-voice-quality 31 string
+ATTRIBUTE Epygi-h323-gw-id 33 string
+ATTRIBUTE Epygi-h323-incoming-conf-id 35 string
+
+ATTRIBUTE Epygi-h323-credit-amount 101 string
+ATTRIBUTE Epygi-h323-credit-time 102 string
+ATTRIBUTE Epygi-h323-return-code 103 string
+ATTRIBUTE Epygi-h323-prompt-id 104 string
+ATTRIBUTE Epygi-h323-time-and-day 105 string
+ATTRIBUTE Epygi-h323-redirect-number 106 string
+ATTRIBUTE Epygi-h323-preferred-lang 107 string
+ATTRIBUTE Epygi-h323-redirect-ip-address 108 string
+ATTRIBUTE Epygi-h323-billing-model 109 string
+ATTRIBUTE Epygi-h323-currency 110 string
+
+ATTRIBUTE Epygi-RegExpDate 150 string
+ATTRIBUTE Epygi-FiadID 151 string
+ATTRIBUTE Epygi-PortID 152 string
+ATTRIBUTE Epygi-AccessType 153 string
+ATTRIBUTE Epygi-CallInfo 154 string
+
+ATTRIBUTE Epygi-OrigCallID 170 string
+ATTRIBUTE Epygi-ParentCallID 171 string
+ATTRIBUTE Epygi-CallType 172 integer
+ATTRIBUTE Epygi-DeviceName 173 string
+ATTRIBUTE Epygi-InterfaceName 174 integer
+ATTRIBUTE Epygi-InterfaceNumber 175 integer
+ATTRIBUTE Epygi-TimeslotNumber 176 integer
+ATTRIBUTE Epygi-OrigIpAddr 177 integer
+ATTRIBUTE Epygi-DestIpAddr 178 integer
+ATTRIBUTE Epygi-OrigIpPort 179 integer
+ATTRIBUTE Epygi-DestIpPort 180 integer
+ATTRIBUTE Epygi-CallingPartyNumber 181 string
+ATTRIBUTE Epygi-CalledPartyNumber 182 string
+ATTRIBUTE Epygi-DateTimeOrigination 183 integer
+ATTRIBUTE Epygi-DateTimeConnect 184 integer
+ATTRIBUTE Epygi-DateTimeDisconnect 185 integer
+ATTRIBUTE Epygi-Duration 186 integer
+ATTRIBUTE Epygi-OutSourceRTP_IP 187 integer
+ATTRIBUTE Epygi-OutDestRTP_IP 188 integer
+ATTRIBUTE Epygi-InSourceRTP_IP 189 integer
+ATTRIBUTE Epygi-InDestRTP_IP 190 integer
+ATTRIBUTE Epygi-OutSourceRTP_port 191 integer
+ATTRIBUTE Epygi-OutDestRTP_port 192 integer
+ATTRIBUTE Epygi-InSourceRTP_port 193 integer
+ATTRIBUTE Epygi-InDestRTP_port 194 integer
+ATTRIBUTE Epygi-CallRedirectReason 195 integer
+ATTRIBUTE Epygi-CallDisconnectReason 196 integer
+ATTRIBUTE Epygi-OutRTP_Payload 197 integer
+ATTRIBUTE Epygi-OutRTP_PacketSize 198 integer
+ATTRIBUTE Epygi-OutRTP_Packets 199 integer
+ATTRIBUTE Epygi-OutRTP_Octets 200 integer
+ATTRIBUTE Epygi-InRTP_Payload 201 integer
+ATTRIBUTE Epygi-InRTP_PacketSize 202 integer
+ATTRIBUTE Epygi-InRTP_Packets 203 integer
+ATTRIBUTE Epygi-InRTP_Octets 204 integer
+ATTRIBUTE Epygi-InRTP_PacketsLost 205 integer
+ATTRIBUTE Epygi-InRTP_PacketsDupl 206 integer
+ATTRIBUTE Epygi-InRTP_Jitter 207 integer
+ATTRIBUTE Epygi-InRTP_Latency 208 integer
+
+VALUE Epygi-CallType Internal 0
+VALUE Epygi-CallType SIP 1
+VALUE Epygi-CallType H.323 2
+VALUE Epygi-CallType FXO 3
+VALUE Epygi-CallType T1-E1-CAS 4
+VALUE Epygi-CallType T1-E1-CCS 5
+VALUE Epygi-CallType ISDN-PRI 6
+
+VALUE Epygi-InterfaceName Ethernet 0
+VALUE Epygi-InterfaceName FXO 1
+VALUE Epygi-InterfaceName T1-E1-User 2
+VALUE Epygi-InterfaceName T1-E1-Network 3
+VALUE Epygi-InterfaceName ISDN 4
+
+VALUE Epygi-CallRedirectReason No-Reason 0
+VALUE Epygi-CallRedirectReason Call-Forward-Uncondit 1
+VALUE Epygi-CallRedirectReason Call-Forward-Busy 2
+VALUE Epygi-CallRedirectReason Call-Forward-NoAnswer 3
+VALUE Epygi-CallRedirectReason Call-Tranfer 4
+VALUE Epygi-CallRedirectReason Call-Park 5
+VALUE Epygi-CallRedirectReason Call-Pickup 6
+VALUE Epygi-CallRedirectReason ManyExtension-Ringing 7
+VALUE Epygi-CallRedirectReason Hunt-Group 8
+
+VALUE Epygi-CallDisconnectReason Call-Is-Redirected 0
+VALUE Epygi-CallDisconnectReason Call-Origin-OnHook 1
+VALUE Epygi-CallDisconnectReason Call-Temin-OnHook 2
+VALUE Epygi-CallDisconnectReason Disconected-by-CAC 3
+VALUE Epygi-CallDisconnectReason Other 4
+
+END-VENDOR Epygi
diff --git a/share/dictionary.equallogic b/share/dictionary.equallogic
new file mode 100644
index 0000000..ad72e06
--- /dev/null
+++ b/share/dictionary.equallogic
@@ -0,0 +1,43 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Equallogic was acquired by Dell in 2008.
+#
+
+VENDOR Equallogic 12740
+
+BEGIN-VENDOR Equallogic
+
+ATTRIBUTE Equallogic-Admin-Full-Name 1 string # Optional
+ATTRIBUTE Equallogic-Admin-Email 2 string # Optional
+ATTRIBUTE Equallogic-Admin-Phone 3 string # Optional
+ATTRIBUTE Equallogic-Admin-Mobile 4 string # Optional
+ATTRIBUTE Equallogic-Poll-Interval 5 integer # Up to 6 numerals, default is 30 (seconds)
+ATTRIBUTE Equallogic-EQL-Admin-Privilege 6 integer
+
+VALUE Equallogic-EQL-Admin-Privilege group-administrator 0
+VALUE Equallogic-EQL-Admin-Privilege pool-administrator 1
+VALUE Equallogic-EQL-Admin-Privilege pool-administrator-ro-entire-group 2
+VALUE Equallogic-EQL-Admin-Privilege volume-administrator 3
+
+# For read-only admin privileges set
+# Equallogic-EQL-Admin-Privilege to 0 and
+# Equallogic-Admin-Account-Type to RO
+
+ATTRIBUTE Equallogic-Admin-Pool-Access 7 string # Comma-separated list of pools
+
+# 'Pool1 25gb' sets the quota for Pool1 to 25GB
+# 'Pool1 500mb' sets a quota of 500MB.
+# 'Pool1 unlimited sets an unlimited quota to pool1
+# If no unit is specified, the default capacity unit is MB.
+
+ATTRIBUTE Equallogic-Admin-Repl-Site-Access 8 string # Comma-separated list of sites
+
+# Required if Equallogic-EQL-Admin-Privilege is 3
+# Used only if Equallogic-EQL-Admin-Privilege is 3
+
+ATTRIBUTE Equallogic-Admin-Account-Type 9 string # RO or RW
+
+END-VENDOR Equallogic
+
diff --git a/share/dictionary.ericsson b/share/dictionary.ericsson
new file mode 100644
index 0000000..da715df
--- /dev/null
+++ b/share/dictionary.ericsson
@@ -0,0 +1,134 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Ericsson dictionary
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR Ericsson 193
+
+BEGIN-VENDOR Ericsson
+
+ATTRIBUTE Ericsson-ViG-Balance 3 integer
+ATTRIBUTE Ericsson-ViG-Codec 4 integer
+ATTRIBUTE Ericsson-ViG-Currency 5 string
+ATTRIBUTE Ericsson-ViG-Currency-Quote 6 string
+ATTRIBUTE Ericsson-ViG-Endpoint-Type 8 integer
+ATTRIBUTE Ericsson-ViG-Sequence-Number 9 integer
+ATTRIBUTE Ericsson-ViG-Access-Agent-IP-Address 11 ipaddr
+ATTRIBUTE Ericsson-ViG-QoS-Class 12 integer
+
+#
+# These next two attributes look to be similar to Digest-Response (206) and
+# Digest-Attributes (207)
+#
+ATTRIBUTE Ericsson-ViG-Digest-Response 14 string
+ATTRIBUTE Ericsson-ViG-Digest-Attributes 15 octets
+
+ATTRIBUTE Ericsson-ViG-Business-Agreement-Name 16 string
+ATTRIBUTE Ericsson-ViG-Call-Role 17 integer
+ATTRIBUTE Ericsson-ViG-Remote-SK-UA-IP-Address 20 ipaddr
+ATTRIBUTE Ericsson-ViG-Site 23 string
+ATTRIBUTE Ericsson-ViG-TTL-relative 32 integer
+ATTRIBUTE Ericsson-ViG-Account-error-reason 33 integer
+ATTRIBUTE Ericsson-ViG-Layer-identity 34 integer
+ATTRIBUTE Ericsson-ViG-Major-protocol-version 35 integer
+ATTRIBUTE Ericsson-ViG-Minor-protocol-version 36 integer
+ATTRIBUTE Ericsson-ViG-Authentication-type 37 integer
+ATTRIBUTE Ericsson-ViG-Trusted-access 38 integer
+ATTRIBUTE Ericsson-ViG-User-name 39 string
+ATTRIBUTE Ericsson-ViG-Global-unique-call-ID 40 string
+ATTRIBUTE Ericsson-ViG-Global-unique-service-ID 41 string
+ATTRIBUTE Ericsson-ViG-Interim-interval 42 integer
+ATTRIBUTE Ericsson-ViG-Alive-Indicator 43 integer
+ATTRIBUTE Ericsson-ViG-TTL-Absolute 44 integer
+ATTRIBUTE Ericsson-ViG-TTL-Start-Event 45 integer
+ATTRIBUTE Ericsson-ViG-SK-IP-address 46 ipaddr
+ATTRIBUTE Ericsson-ViG-UA-IP-address 47 ipaddr
+ATTRIBUTE Ericsson-ViG-SA-IP-address 48 ipaddr
+ATTRIBUTE Ericsson-ViG-Calling-e164-number 49 string
+ATTRIBUTE Ericsson-ViG-Calling-H323Id 50 string
+ATTRIBUTE Ericsson-ViG-Calling-Email-address 51 string
+ATTRIBUTE Ericsson-ViG-Dialled-e164-number 52 string
+ATTRIBUTE Ericsson-ViG-Dialled-H323Id 53 string
+ATTRIBUTE Ericsson-ViG-Dialled-Email-address 54 string
+ATTRIBUTE Ericsson-ViG-Routed-e164-number 55 string
+ATTRIBUTE Ericsson-ViG-Routed-H323Id 56 string
+ATTRIBUTE Ericsson-ViG-Routed-Email-address 57 string
+ATTRIBUTE Ericsson-ViG-SiteKeeper-name 58 string
+ATTRIBUTE Ericsson-ViG-Access-Group-name 59 string
+ATTRIBUTE Ericsson-ViG-Access-Agent-name 60 string
+ATTRIBUTE Ericsson-ViG-User-agent-group-name 61 string
+ATTRIBUTE Ericsson-ViG-User-agent-name 62 string
+ATTRIBUTE Ericsson-ViG-Routing-tariff 63 integer
+ATTRIBUTE Ericsson-ViG-Re-selection-counter 64 integer
+ATTRIBUTE Ericsson-ViG-CPN-digits 65 string
+ATTRIBUTE Ericsson-ViG-CPN-TON 66 integer
+ATTRIBUTE Ericsson-ViG-CPN-NP 67 integer
+ATTRIBUTE Ericsson-ViG-CPN-PI 68 integer
+ATTRIBUTE Ericsson-ViG-CPN-SI 69 integer
+ATTRIBUTE Ericsson-ViG-Dialled-num-digits 70 string
+ATTRIBUTE Ericsson-ViG-Dialled-num-TON 71 integer
+ATTRIBUTE Ericsson-ViG-Dialled-num-NP 72 integer
+ATTRIBUTE Ericsson-ViG-Routing-num-digits 73 string
+ATTRIBUTE Ericsson-ViG-Routing-num-TON 74 integer
+ATTRIBUTE Ericsson-ViG-Routing-num-NP 75 integer
+ATTRIBUTE Ericsson-ViG-Redirecting-num-digits 76 string
+ATTRIBUTE Ericsson-ViG-Redirecting-num-TON 77 integer
+ATTRIBUTE Ericsson-ViG-Redirecting-num-NP 78 integer
+ATTRIBUTE Ericsson-ViG-Redirecting-num-PI 79 integer
+ATTRIBUTE Ericsson-ViG-Redirecting-num-RFD 80 integer
+ATTRIBUTE Ericsson-ViG-Time-stamp-UTC 81 integer
+ATTRIBUTE Ericsson-ViG-Time-stamp-TZ 82 integer
+ATTRIBUTE Ericsson-ViG-Time-stamp-DST 83 integer
+ATTRIBUTE Ericsson-ViG-Session-routing-duration 84 integer
+ATTRIBUTE Ericsson-ViG-Session-ringing-duration 85 integer
+ATTRIBUTE Ericsson-ViG-Access-type 86 integer
+ATTRIBUTE Ericsson-ViG-Requested-bandwidth 87 integer
+ATTRIBUTE Ericsson-ViG-Allowed-bandwidth 88 integer
+ATTRIBUTE Ericsson-ViG-Media-channel-count 89 integer
+ATTRIBUTE Ericsson-ViG-Voice-media-rec-forward 90 string
+ATTRIBUTE Ericsson-ViG-Voice-media-rec-backward 91 string
+ATTRIBUTE Ericsson-ViG-Video-media-rec-forward 92 string
+ATTRIBUTE Ericsson-ViG-Video-media-rec-backward 93 string
+ATTRIBUTE Ericsson-ViG-Fax-media-rec-forward 94 string
+ATTRIBUTE Ericsson-ViG-Fax-media-rec-backward 95 string
+ATTRIBUTE Ericsson-ViG-Data-media-rec-forward 96 string
+ATTRIBUTE Ericsson-ViG-Data-media-rec-backward 97 string
+ATTRIBUTE Ericsson-ViG-Charging-Case 98 integer
+ATTRIBUTE Ericsson-ViG-Rel-cause-coding-std 99 integer
+ATTRIBUTE Ericsson-ViG-Rel-cause-location 100 integer
+ATTRIBUTE Ericsson-ViG-Rel-cause-class 101 integer
+ATTRIBUTE Ericsson-ViG-Rel-cause-value 102 integer
+ATTRIBUTE Ericsson-ViG-Rel-reason 103 integer
+ATTRIBUTE Ericsson-ViG-Internal-Rel-reason-val 104 integer
+ATTRIBUTE Ericsson-ViG-Internal-Rel-reason-orig 105 integer
+ATTRIBUTE Ericsson-ViG-Service-ID 106 integer
+ATTRIBUTE Ericsson-ViG-User-ID 107 string
+ATTRIBUTE Ericsson-ViG-Service-Name 108 string
+ATTRIBUTE Ericsson-ViG-Test-Call-Indicator 109 integer
+ATTRIBUTE Ericsson-ViG-Emergency-Call-Indicator 110 integer
+ATTRIBUTE Ericsson-ViG-Calling-ID 111 string
+ATTRIBUTE Ericsson-ViG-Called-ID 112 string
+ATTRIBUTE Ericsson-ViG-Translated-ID 113 string
+ATTRIBUTE Ericsson-ViG-Calling-User-Group-ID 114 string
+ATTRIBUTE Ericsson-ViG-Calling-Usr-Sub-Group-ID 115 string
+ATTRIBUTE Ericsson-ViG-Called-Usr-Group-ID 116 string
+ATTRIBUTE Ericsson-ViG-Called-Usr-Sub-Group-ID 117 string
+ATTRIBUTE Ericsson-ViG-Terminal-Type 118 string
+ATTRIBUTE Ericsson-ViG-Service-Duration 119 integer
+ATTRIBUTE Ericsson-ViG-Service-Execution-Result 120 integer
+ATTRIBUTE Ericsson-ViG-Service-Exe-Rslt-Desc 121 string
+ATTRIBUTE Ericsson-ViG-Service-Description 122 string
+ATTRIBUTE Ericsson-ViG-Service-Specific-Info 123 string
+ATTRIBUTE Ericsson-ViG-Proxy-IP-Address 124 ipaddr
+ATTRIBUTE Ericsson-ViG-Auth-DataRequest 125 integer
+ATTRIBUTE Ericsson-ViG-IPT-Time-Stamp 126 integer
+ATTRIBUTE Ericsson-ViG-User-Name-Info 127 integer
+
+END-VENDOR Ericsson
diff --git a/share/dictionary.ericsson.ab b/share/dictionary.ericsson.ab
new file mode 100644
index 0000000..903fd71
--- /dev/null
+++ b/share/dictionary.ericsson.ab
@@ -0,0 +1,451 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+VENDOR Ericsson-AB 2352
+BEGIN-VENDOR Ericsson-AB
+
+ATTRIBUTE Client-DNS-Pri 1 ipaddr
+ATTRIBUTE Client-DNS-Sec 2 ipaddr
+ATTRIBUTE DHCP-Max-Leases 3 integer
+ATTRIBUTE Context-Name 4 string
+ATTRIBUTE Bridge-Group 5 string
+ATTRIBUTE BG-Aging-Time 6 string
+ATTRIBUTE BG-Path-Cost 7 string
+ATTRIBUTE BG-Span-Dis 8 string
+ATTRIBUTE BG-Trans-BPDU 9 string
+ATTRIBUTE Rate-Limit-Rate 10 integer
+ATTRIBUTE Rate-Limit-Burst 11 integer
+ATTRIBUTE Police-Rate 12 integer
+ATTRIBUTE Police-Burst 13 integer
+ATTRIBUTE Source-Validation 14 integer
+
+VALUE Source-Validation Enabled 1
+VALUE Source-Validation Disabled 2
+
+ATTRIBUTE Tunnel-Domain 15 integer
+
+VALUE Tunnel-Domain Enabled 1
+VALUE Tunnel-Domain Disabled 2
+
+ATTRIBUTE Tunnel-Local-Name 16 string
+ATTRIBUTE Tunnel-Remote-Name 17 string
+ATTRIBUTE Tunnel-Function 18 integer
+
+VALUE Tunnel-Function LAC-Only 1
+VALUE Tunnel-Function LNS-Only 2
+VALUE Tunnel-Function LAC-LNS 3
+
+ATTRIBUTE Tunnel-Flow-Control 19 integer
+ATTRIBUTE Tunnel-Static 20 integer
+ATTRIBUTE Tunnel-Max-Sessions 21 integer
+ATTRIBUTE Tunnel-Max-Tunnels 22 integer
+ATTRIBUTE Tunnel-Session-Auth 23 integer
+
+VALUE Tunnel-Session-Auth CHAP 1
+VALUE Tunnel-Session-Auth PAP 2
+VALUE Tunnel-Session-Auth CHAP-PAP 3
+
+ATTRIBUTE Tunnel-Window 24 integer
+ATTRIBUTE Tunnel-Retransmit 25 integer
+ATTRIBUTE Tunnel-Cmd-Timeout 26 integer
+ATTRIBUTE PPPOE-URL 27 string
+ATTRIBUTE PPPOE-MOTM 28 string
+ATTRIBUTE Tunnel-Group 29 integer
+
+VALUE Tunnel-Group Enabled 1
+VALUE Tunnel-Group Disabled 2
+
+ATTRIBUTE Tunnel-Context 30 string
+ATTRIBUTE Tunnel-Algorithm 31 integer
+
+VALUE Tunnel-Algorithm First 1
+VALUE Tunnel-Algorithm Load-Balance 2
+VALUE Tunnel-Algorithm WRR 3
+
+ATTRIBUTE Tunnel-Deadtime 32 integer
+ATTRIBUTE Mcast-Send 33 integer
+
+VALUE Mcast-Send NO-SEND 1
+VALUE Mcast-Send SEND 2
+VALUE Mcast-Send UNSOLICITED-SEND 3
+
+ATTRIBUTE Mcast-Receive 34 integer
+
+VALUE Mcast-Receive NO-RECEIVE 1
+VALUE Mcast-Receive RECEIVE 2
+
+ATTRIBUTE Mcast-MaxGroups 35 integer
+ATTRIBUTE Ip-Address-Pool-Name 36 string
+ATTRIBUTE Tunnel-DNIS 37 integer
+
+VALUE Tunnel-DNIS DNIS 1
+VALUE Tunnel-DNIS DNIS-Only 2
+VALUE Tunnel-DNIS DNIS-Generate 4
+
+ATTRIBUTE Medium-Type 38 integer
+
+VALUE Medium-Type DSL 11
+VALUE Medium-Type Cable 12
+VALUE Medium-Type Wireless 13
+VALUE Medium-Type Satellite 14
+
+ATTRIBUTE PVC-Encapsulation-Type 39 integer
+
+VALUE PVC-Encapsulation-Type AAA-ENCAPS-ATM-RAW 1
+VALUE PVC-Encapsulation-Type AAA-ENCAPS-ATM-ROUTE1483 2
+VALUE PVC-Encapsulation-Type AAA-ENCAPS-ATM-AUTO1483 3
+VALUE PVC-Encapsulation-Type AAA-ENCAPS-ATM-MULTI 4
+VALUE PVC-Encapsulation-Type AAA-ENCAPS-ATM-BRIDGE1483 5
+VALUE PVC-Encapsulation-Type AAA-ENCAPS-ATM-PPP 6
+VALUE PVC-Encapsulation-Type AAA-ENCAPS-ATM-PPP-SERIAL 7
+VALUE PVC-Encapsulation-Type AAA-ENCAPS-ATM-PPP-NLPID 8
+VALUE PVC-Encapsulation-Type AAA-ENCAPS-ATM-PPP-AUTO 9
+VALUE PVC-Encapsulation-Type AAA-ENCAPS-ATM-PPPOE 10
+VALUE PVC-Encapsulation-Type AAA-ENCAPS-ATM-L2TP 11
+VALUE PVC-Encapsulation-Type AAA-ENCAPS-ATM-PPP-LLC 12
+VALUE PVC-Encapsulation-Type AAA-ENCAPS-FRAME-AUTO1490 13
+VALUE PVC-Encapsulation-Type AAA-ENCAPS-FRAME-MULTI 14
+VALUE PVC-Encapsulation-Type AAA-ENCAPS-FRAME-BRIDGE1490 15
+VALUE PVC-Encapsulation-Type AAA-ENCAPS-FRAME-PPP 16
+VALUE PVC-Encapsulation-Type AAA-ENCAPS-FRAME-PPP-AUTO 17
+VALUE PVC-Encapsulation-Type AAA-ENCAPS-FRAME-PPPOE 18
+VALUE PVC-Encapsulation-Type AAA-ENCAPS-FRAME-ROUTE1490 19
+VALUE PVC-Encapsulation-Type AAA-ENCAPS-FRAME-L2TP 20
+VALUE PVC-Encapsulation-Type AAA-ENCAPS-L2TP-VC-MUXED 21
+VALUE PVC-Encapsulation-Type AAA-ENCAPS-ETH 22
+VALUE PVC-Encapsulation-Type AAA-ENCAPS-ETH-PPPOE 23
+VALUE PVC-Encapsulation-Type AAA-ENCAPS-ETH-MULTI 24
+VALUE PVC-Encapsulation-Type AAA-ENCAPS-ETH-DOT1Q 25
+VALUE PVC-Encapsulation-Type AAA-ENCAPS-ETH-DOT1Q-PPPOE 26
+VALUE PVC-Encapsulation-Type AAA-ENCAPS-ATM-MULTI-PPPOE 27
+VALUE PVC-Encapsulation-Type AAA-ENCAPS-ATM-MULTI-IPV6OE 28
+VALUE PVC-Encapsulation-Type AAA-ENCAPS-ATM-MULTI-PPPOE-N-IPV6OE 29
+VALUE PVC-Encapsulation-Type AAA-ENCAPS-ETH-DOT1Q-TUNNEL 30
+VALUE PVC-Encapsulation-Type AAA-ENCAPS-ETH-DOT1Q-TUNNEL-PPPOE 31
+
+ATTRIBUTE PVC-Profile-Name 40 string
+ATTRIBUTE PVC-Circuit-Padding 41 integer
+
+VALUE PVC-Circuit-Padding AAA-CIRCUIT-PADDING 1
+VALUE PVC-Circuit-Padding AAA-CIRCUIT-NO-PADDING 2
+
+ATTRIBUTE Bind-Type 42 integer
+
+VALUE Bind-Type AAA-AUTH-BIND 1
+VALUE Bind-Type AAA-BYPASS-BIND 2
+VALUE Bind-Type AAA-INTERFACE-BIND 3
+VALUE Bind-Type AAA-SUBSCRIBE-BIND 4
+VALUE Bind-Type AAA-TUNNEL-BIND 5
+VALUE Bind-Type AAA-SESSION-BIND 6
+VALUE Bind-Type AAA-Q8021-BIND 7
+VALUE Bind-Type AAA-MULTI-BIND 8
+VALUE Bind-Type AAA-DHCP-BIND 9
+VALUE Bind-Type AAA-MULTI-BIND-SUB 10
+VALUE Bind-Type AAA-BRIDGE-GROUP-BIND 11
+VALUE Bind-Type AAA-VLAN-BIND 12
+VALUE Bind-Type AAA-VLAN-GROUP-BIND 13
+VALUE Bind-Type AAA-AUTO-SUBSCRIBER-BIND 14
+
+ATTRIBUTE Bind-Auth-Protocol 43 integer
+
+VALUE Bind-Auth-Protocol AAA-PPP-PAP 1
+VALUE Bind-Auth-Protocol AAA-PPP-CHAP 2
+VALUE Bind-Auth-Protocol AAA-PPP-CHAP-WAIT 3
+VALUE Bind-Auth-Protocol AAA-PPP-CHAP-PAP 4
+VALUE Bind-Auth-Protocol AAA-PPP-CHAP-WAIT-PAP 5
+VALUE Bind-Auth-Protocol AAA-PPP-EAP 6
+VALUE Bind-Auth-Protocol AAA-PPP-PAP-CHAP 7
+VALUE Bind-Auth-Protocol AAA-PPP-PAP-CHAP-WAIT 8
+
+ATTRIBUTE Bind-Auth-Max-Sessions 44 integer
+ATTRIBUTE Bind-Bypass-Bypass 45 string
+ATTRIBUTE Bind-Auth-Context 46 string
+ATTRIBUTE Bind-Auth-Service-Grp 47 string
+ATTRIBUTE Bind-Bypass-Context 48 string
+ATTRIBUTE Bind-Int-Context 49 string
+ATTRIBUTE Bind-Tun-Context 50 string
+ATTRIBUTE Bind-Ses-Context 51 string
+ATTRIBUTE Bind-Dot1q-Slot 52 integer
+ATTRIBUTE Bind-Dot1q-Port 53 integer
+ATTRIBUTE Bind-Dot1q-Vlan-Tag-Id 54 integer
+ATTRIBUTE Bind-Int-Interface-Name 55 string
+ATTRIBUTE Bind-L2TP-Tunnel-Name 56 string
+ATTRIBUTE Bind-L2TP-Flow-Control 57 integer
+ATTRIBUTE Bind-Sub-User-At-Context 58 string
+ATTRIBUTE Bind-Sub-Password 59 string
+ATTRIBUTE Ip-Host-Addr 60 string
+ATTRIBUTE IP-TOS-Field 61 integer
+
+VALUE IP-TOS-Field normal 0
+VALUE IP-TOS-Field min-cost-only 1
+VALUE IP-TOS-Field max-reliability-only 2
+VALUE IP-TOS-Field max-reliability-plus-min-cost 3
+VALUE IP-TOS-Field max-throughput-only 4
+VALUE IP-TOS-Field max-throughput-plus-min-cost 5
+VALUE IP-TOS-Field max-throughput-plus-max-reliability 6
+VALUE IP-TOS-Field max-throughput-plus-max-reliability-plus-min-cost 7
+VALUE IP-TOS-Field min-delay-only 8
+VALUE IP-TOS-Field min-delay-plus-min-cost 9
+VALUE IP-TOS-Field min-delay-plus-max-reliability 10
+VALUE IP-TOS-Field min-delay-plus-max-reliability-plus-min-cost 11
+VALUE IP-TOS-Field min-delay-plus-max-throughput 12
+VALUE IP-TOS-Field min-delay-plus-max-throughput-plus-min-cost 13
+VALUE IP-TOS-Field min-delay-plus-max-throughput-plus-max-reliability 14
+VALUE IP-TOS-Field min-delay-plus-max-throughput-plus-max-reliability-plus-min-cost 15
+
+ATTRIBUTE NAS-Real-Port 62 integer
+ATTRIBUTE Tunnel-Session-Auth-Ctx 63 string
+ATTRIBUTE Tunnel-Session-Auth-Service-Grp 64 string
+ATTRIBUTE Tunnel-Rate-Limit-Rate 65 integer
+ATTRIBUTE Tunnel-Rate-Limit-Burst 66 integer
+ATTRIBUTE Tunnel-Police-Rate 67 integer
+ATTRIBUTE Tunnel-Police-Burst 68 integer
+ATTRIBUTE Tunnel-L2F-Second-Password 69 string
+ATTRIBUTE ACL-Definition 70 string
+ATTRIBUTE PPPoE-IP-Route-Add 71 string
+ATTRIBUTE TTY-Level-Max 72 integer
+ATTRIBUTE TTY-Level-Start 73 integer
+ATTRIBUTE Tunnel-Checksum 74 integer
+ATTRIBUTE Tunnel-Profile 75 string
+ATTRIBUTE Tunnel-Client-VPN 78 string
+ATTRIBUTE Tunnel-Server-VPN 79 string
+ATTRIBUTE Tunnel-Client-Rhost 80 string
+ATTRIBUTE Tunnel-Server-Rhost 81 string
+ATTRIBUTE Tunnel-Client-Int-Addr 82 ipaddr
+ATTRIBUTE Tunnel-Server-Int-Addr 83 ipaddr
+ATTRIBUTE PPP-Compression 84 integer
+ATTRIBUTE Tunnel-Hello-Timer 85 integer has_tag
+ATTRIBUTE Redback-Reason 86 integer
+ATTRIBUTE Qos-Policing-Profile-Name 87 string
+ATTRIBUTE Qos-Metering-Profile-Name 88 string
+ATTRIBUTE Qos-Policy-Queuing 89 string
+ATTRIBUTE IGMP-Service-Profile-Name 90 string
+ATTRIBUTE Subscriber-Profile-Name 91 string
+ATTRIBUTE Forward-Policy 92 string
+ATTRIBUTE Remote-Port 93 string
+ATTRIBUTE Reauth 94 string
+ATTRIBUTE Reauth-More 95 integer
+ATTRIBUTE Agent-Remote-Id 96 octets
+ATTRIBUTE Agent-Circuit-Id 97 octets
+ATTRIBUTE Platform-Type 98 integer
+
+VALUE Platform-Type SMS 1
+VALUE Platform-Type SmartEdge-800 2
+VALUE Platform-Type SE-400 3
+VALUE Platform-Type SE-100 4
+
+ATTRIBUTE Client-NBNS-Pri 99 ipaddr
+ATTRIBUTE Client-NBNS-Sec 100 ipaddr
+ATTRIBUTE Shaping-Profile-Name 101 string
+ATTRIBUTE BG-Cct-Addr-Max 103 integer
+ATTRIBUTE IP-Interface-Name 104 string
+ATTRIBUTE NAT-Policy-Name 105 string
+ATTRIBUTE RB-NPM-Service-Id 106 string
+ATTRIBUTE HTTP-Redirect-Profile-Name 107 string
+ATTRIBUTE Bind-Auto-Sub-User 108 string
+ATTRIBUTE Bind-Auto-Sub-Context 109 string
+ATTRIBUTE Bind-Auto-Sub-Password 110 string
+ATTRIBUTE Circuit-Protocol-Encap 111 integer
+
+VALUE Circuit-Protocol-Encap ENCAPS-PPPOE 27
+
+ATTRIBUTE OS-Version 112 string
+ATTRIBUTE Session-Traffic-Limit 113 string
+ATTRIBUTE QOS-Reference 114 string
+ATTRIBUTE Rate-Limit-Excess-Burst 121 octets
+ATTRIBUTE Police-Excess-Burst 122 octets
+ATTRIBUTE Tunnel-Rate-Limit-Excess-Burst 123 octets
+ATTRIBUTE Tunnel-Police-Excess-Burst 124 octets
+ATTRIBUTE DHCP-Vendor-Class-ID 125 string
+ATTRIBUTE Qos-Rate 126 string
+ATTRIBUTE DHCP-Vendor-Encap-Option 127 string
+ATTRIBUTE Acct-Input-Octets-64 128 integer64
+ATTRIBUTE Acct-Output-Octets-64 129 integer64
+ATTRIBUTE Acct-Input-Packets-64 130 integer64
+ATTRIBUTE Acct-Output-Packets-64 131 integer64
+ATTRIBUTE Assigned-IP-Address 132 ipaddr
+ATTRIBUTE Acct-Mcast-In-Octets-64 133 integer64
+ATTRIBUTE Acct-Mcast-Out-Octets-64 134 integer64
+ATTRIBUTE Acct-Mcast-In-Packets-64 135 integer64
+ATTRIBUTE Acct-Mcast-Out-Packets-64 136 integer64
+ATTRIBUTE LAC-Port 137 integer
+ATTRIBUTE LAC-Real-Port 138 integer
+ATTRIBUTE LAC-Port-Type 139 integer
+
+VALUE LAC-Port-Type NAS-PORT-TYPE-10BT 40
+VALUE LAC-Port-Type NAS-PORT-TYPE-100BT 41
+VALUE LAC-Port-Type NAS-PORT-TYPE-DS3-FR 42
+VALUE LAC-Port-Type NAS-PORT-TYPE-DS3-ATM 43
+VALUE LAC-Port-Type NAS-PORT-TYPE-OC3 44
+VALUE LAC-Port-Type NAS-PORT-TYPE-HSSI 45
+VALUE LAC-Port-Type NAS-PORT-TYPE-EIA530 46
+VALUE LAC-Port-Type NAS-PORT-TYPE-T1 47
+VALUE LAC-Port-Type NAS-PORT-TYPE-CHAN-T3 48
+VALUE LAC-Port-Type NAS-PORT-TYPE-DS1-FR 49
+VALUE LAC-Port-Type NAS-PORT-TYPE-E3-ATM 50
+VALUE LAC-Port-Type NAS-PORT-TYPE-IMA-ATM 51
+VALUE LAC-Port-Type NAS-PORT-TYPE-DS3-ATM-2 52
+VALUE LAC-Port-Type NAS-PORT-TYPE-OC3-ATM-2 53
+VALUE LAC-Port-Type NAS-PORT-TYPE-1000BSX 54
+VALUE LAC-Port-Type NAS-PORT-TYPE-E1-FR 55
+VALUE LAC-Port-Type NAS-PORT-TYPE-E1-ATM 56
+VALUE LAC-Port-Type NAS-PORT-TYPE-E3-FR 57
+VALUE LAC-Port-Type NAS-PORT-TYPE-OC3-POS 58
+VALUE LAC-Port-Type NAS-PORT-TYPE-OC12-POS 59
+VALUE LAC-Port-Type NAS-PORT-TYPE-PPPOE 60
+
+ATTRIBUTE LAC-Real-Port-Type 140 integer
+
+VALUE LAC-Real-Port-Type NAS-PORT-TYPE-10BT 40
+VALUE LAC-Real-Port-Type NAS-PORT-TYPE-100BT 41
+VALUE LAC-Real-Port-Type NAS-PORT-TYPE-DS3-FR 42
+VALUE LAC-Real-Port-Type NAS-PORT-TYPE-DS3-ATM 43
+VALUE LAC-Real-Port-Type NAS-PORT-TYPE-OC3 44
+VALUE LAC-Real-Port-Type NAS-PORT-TYPE-HSSI 45
+VALUE LAC-Real-Port-Type NAS-PORT-TYPE-EIA530 46
+VALUE LAC-Real-Port-Type NAS-PORT-TYPE-T1 47
+VALUE LAC-Real-Port-Type NAS-PORT-TYPE-CHAN-T3 48
+VALUE LAC-Real-Port-Type NAS-PORT-TYPE-DS1-FR 49
+VALUE LAC-Real-Port-Type NAS-PORT-TYPE-E3-ATM 50
+VALUE LAC-Real-Port-Type NAS-PORT-TYPE-IMA-ATM 51
+VALUE LAC-Real-Port-Type NAS-PORT-TYPE-DS3-ATM-2 52
+VALUE LAC-Real-Port-Type NAS-PORT-TYPE-OC3-ATM-2 53
+VALUE LAC-Real-Port-Type NAS-PORT-TYPE-1000BSX 54
+VALUE LAC-Real-Port-Type NAS-PORT-TYPE-E1-FR 55
+VALUE LAC-Real-Port-Type NAS-PORT-TYPE-E1-ATM 56
+VALUE LAC-Real-Port-Type NAS-PORT-TYPE-E3-FR 57
+VALUE LAC-Real-Port-Type NAS-PORT-TYPE-OC3-POS 58
+VALUE LAC-Real-Port-Type NAS-PORT-TYPE-OC12-POS 59
+VALUE LAC-Real-Port-Type NAS-PORT-TYPE-PPPOE 60
+
+ATTRIBUTE Acct-Dyn-Ac-Ent 141 string
+ATTRIBUTE Session-Error-Code 142 integer
+ATTRIBUTE Session-Error-Msg 143 string
+ATTRIBUTE Acct-Update-Reason 144 integer
+
+VALUE Acct-Update-Reason AAA-LOAD-ACCT-SESSION-UP 1
+VALUE Acct-Update-Reason AAA-LOAD-ACCT-SESSION-DOWN 2
+VALUE Acct-Update-Reason AAA-LOAD-ACCT-PERIODIC 3
+VALUE Acct-Update-Reason AAA-LOAD-ACCT-DYN-AC-ENT-START 4
+VALUE Acct-Update-Reason AAA-LOAD-ACCT-DYN-AC-ENT-STOP 5
+VALUE Acct-Update-Reason AAA-LOAD-ACCT-DYN-AC-ENT-TIMEOUT 6
+VALUE Acct-Update-Reason AAA-LOAD-ACCT-SUBSCRIBER-REAUTHOR 7
+VALUE Acct-Update-Reason AAA-LOAD-ACCT-PPP-IPCP-UP 8
+VALUE Acct-Update-Reason AAA-LOAD-ACCT-PPP-MP-LINK-UP 9
+VALUE Acct-Update-Reason AAA-LOAD-ACCT-DHCP-IP-ADDR-GRANTED 10
+VALUE Acct-Update-Reason AAA-LOAD-ACCT-DHCP-IP-ADDR-RELEASED 11
+VALUE Acct-Update-Reason AAA-LOAD-ACCT-ACL-TIMERED-ACTION 12
+VALUE Acct-Update-Reason AAA-LOAD-ACCT-ACL-ACTION 13
+VALUE Acct-Update-Reason AAA-LOAD-ACCT-CMD 14
+VALUE Acct-Update-Reason AAA-LOAD-ACCT-TEST 15
+
+ATTRIBUTE Mac-Addr 145 string
+ATTRIBUTE Vlan-Source-Info 146 string
+ATTRIBUTE Acct-Mcast-In-Octets 147 integer
+ATTRIBUTE Acct-Mcast-Out-Octets 148 integer
+ATTRIBUTE Acct-Mcast-In-Packets 149 integer
+ATTRIBUTE Acct-Mcast-Out-Packets 150 integer
+ATTRIBUTE Reauth-Session-Id 151 string
+ATTRIBUTE QOS-Rate-Inbound 156 string
+ATTRIBUTE QOS-Rate-Outbound 157 string
+ATTRIBUTE Route-Tag 158 integer
+ATTRIBUTE LI-Id 159 integer
+ATTRIBUTE LI-Md-Address 160 ipaddr
+ATTRIBUTE LI-Md-Port 161 integer
+ATTRIBUTE LI-Action 162 integer
+ATTRIBUTE LI-Profile 163 string
+ATTRIBUTE Dynamic-Policy-Filter 164 string
+ATTRIBUTE HTTP-Redirect-URL 165 string
+ATTRIBUTE DSL-Actual-Rate-Up 166 integer
+ATTRIBUTE DSL-Actual-Rate-Down 167 integer
+ATTRIBUTE DSL-Min-Rate-Up 168 integer
+ATTRIBUTE DSL-Min-Rate-Down 169 integer
+ATTRIBUTE DSL-Attainable-Rate-Up 170 integer
+ATTRIBUTE DSL-Attainable-Rate-Down 171 integer
+ATTRIBUTE DSL-Max-Rate-Up 172 integer
+ATTRIBUTE DSL-Max-Rate-Down 173 integer
+ATTRIBUTE DSL-Min-Low-Power-Rate-Up 174 integer
+ATTRIBUTE DSL-Min-Low-Power-Rate-Down 175 integer
+ATTRIBUTE DSL-Max-Inter-Delay-Up 176 integer
+ATTRIBUTE DSL-Actual-Inter-Delay-Up 177 integer
+ATTRIBUTE DSL-Max-Inter-Delay-Down 178 integer
+ATTRIBUTE DSL-Actual-Inter-Delay-Down 179 integer
+ATTRIBUTE DSL-Line-State 180 integer
+
+VALUE DSL-Line-State Showtime 1
+VALUE DSL-Line-State Idle 2
+VALUE DSL-Line-State Silent 3
+
+ATTRIBUTE DSL-L2-Encapsulation 181 integer
+ATTRIBUTE DSL-Transmission-System 182 integer
+
+VALUE DSL-Transmission-System ADSL1 1
+VALUE DSL-Transmission-System ADSL2 2
+VALUE DSL-Transmission-System ADSL2+ 3
+VALUE DSL-Transmission-System VDSL1 4
+VALUE DSL-Transmission-System VDSL2 5
+VALUE DSL-Transmission-System SDSL 6
+VALUE DSL-Transmission-System UNKNOWN 7
+
+ATTRIBUTE DSL-PPPOA-PPPOE-Inter-Work-Flag 183 integer
+ATTRIBUTE DSL-Actual-Rate-Down-Factor 185 integer
+ATTRIBUTE DSL-Combined-Line-Info 184 string
+ATTRIBUTE Class-Volume-limit 186 string
+ATTRIBUTE Class-Volume-In-Counter 187 string
+ATTRIBUTE Class-Volume-Out-Counter 188 string
+ATTRIBUTE Flow-FAC-Profile 189 string
+ATTRIBUTE Service-Name 190 string has_tag
+ATTRIBUTE Service-Action 191 integer has_tag
+
+VALUE Service-Action DE-ACTIVATE 0
+VALUE Service-Action ACTIVATE-WITH-ACCT 1
+VALUE Service-Action ACTIVATE-WITHOUT-ACCT 2
+
+ATTRIBUTE Service-Parameter 192 string has_tag
+ATTRIBUTE Service-Error-Cause 193 integer has_tag
+
+VALUE Service-Error-Cause Service-success 0
+VALUE Service-Error-Cause Unsupported-attribute 401
+VALUE Service-Error-Cause Missing-attribute 402
+VALUE Service-Error-Cause Invalid-request 404
+VALUE Service-Error-Cause Resource-unavailable 506
+VALUE Service-Error-Cause Generic-service-error 550
+VALUE Service-Error-Cause Service-not-found 551
+VALUE Service-Error-Cause Service-already-active 552
+VALUE Service-Error-Cause Service-accounting-disabled 553
+VALUE Service-Error-Cause Service-duplicate-parameter 554
+
+ATTRIBUTE Deactivate-Service-Name 194 string has_tag
+ATTRIBUTE Qos-Profile-Overhead 195 string
+ATTRIBUTE Dynamic-QoS-Param 196 string
+ATTRIBUTE Acct-Alt-Session-ID 197 string
+ATTRIBUTE Idle-Timeout-Threshold 198 integer
+ATTRIBUTE Double-Authentication 199 integer
+ATTRIBUTE SBC-Adjacency 200 string
+ATTRIBUTE DHCP-Field 201 octets
+ATTRIBUTE DHCP-Option 202 octets
+ATTRIBUTE Security-Service 203 string
+ATTRIBUTE Reauth-Service-Name 204 string has_tag
+ATTRIBUTE Flow-IP-Profile 205 string
+ATTRIBUTE Radius-Throttle-Watermark 206 integer
+ATTRIBUTE RB-IPV6-DNS 207 string
+ATTRIBUTE RB-IPv6-Option 208 string
+ATTRIBUTE Cluster-Partition-ID 209 string
+ATTRIBUTE Circuit-Group-Member 210 string
+ATTRIBUTE Delegated-Max-Prefix 212 integer
+ATTRIBUTE IPv4-Address-Release-Control 213 string
+ATTRIBUTE Acct-Input-IPv4-Octets 214 integer
+ATTRIBUTE Acct-Output-IPv4-Octets 215 integer
+ATTRIBUTE Acct-Input-IPv4-Packets 216 integer
+ATTRIBUTE Acct-Output-IPv4-Packets 217 integer
+ATTRIBUTE Acct-Input-IPv4-Gigawords 218 integer
+ATTRIBUTE Acct-Output-IPv4-Gigawords 219 integer
+ATTRIBUTE Acct-Input-IPv6-Octets 220 integer
+ATTRIBUTE Acct-Output-IPv6-Octets 221 integer
+ATTRIBUTE Acct-Input-IPv6-Packets 222 integer
+ATTRIBUTE Acct-Output-IPv6-Packets 223 integer
+ATTRIBUTE Acct-Input-IPv6-Gigawords 224 integer
+ATTRIBUTE Acct-Output-IPv6-Gigawords 225 integer
+
+END-VENDOR Ericsson-AB
diff --git a/share/dictionary.ericsson.packet.core.networks b/share/dictionary.ericsson.packet.core.networks
new file mode 100644
index 0000000..34e5a69
--- /dev/null
+++ b/share/dictionary.ericsson.packet.core.networks
@@ -0,0 +1,15 @@
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+
+VENDOR Ericsson-Packet-Core-Networks 10923
+
+#
+# Ericsson specific
+
+BEGIN-VENDOR Ericsson-Packet-Core-Networks
+
+ATTRIBUTE Suggested-Rule-Space 30 string
+ATTRIBUTE Suggested-Secondary-Rule-Space 31 string
+
+END-VENDOR Ericsson-Packet-Core-Networks
diff --git a/share/dictionary.erx b/share/dictionary.erx
new file mode 100644
index 0000000..2a4f3ed
--- /dev/null
+++ b/share/dictionary.erx
@@ -0,0 +1,433 @@
+# -*- text -*-
+# Copyright (C) 2020 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+# Version $Id$
+#
+# Juniper's (was Unisphere's) broadband RAS
+# From Terje Krogdahl <tekr@nextra.com>
+#
+# Version: $Id$
+#
+
+# This dictionary applies to access services on Juniper JUNOS (M/MX)
+# based platforms as well as JUNOSe, although some of the attributes
+# have been given new names on JUNOS:
+# http://www.juniper.net/techpubs/software/junos/junos112/radius-dictionary/unisphereDictionary_for_JUNOS_v11-2.dct
+# http://www.juniper.net/techpubs/en_US/junos10.3/topics/reference/general/aaa-subscriber-access-radius-vsa.html
+#
+# Juniper now publishes a single 'current' document for the latest OS with all supported VSAs here:
+# https://www.juniper.net/documentation/en_US/junos/topics/reference/general/aaa-subscriber-access-radius-vsa.html
+#
+# In this file, we keep the ERX prefix and the JUNOSe attribute names
+# for backwards compatibility
+#
+# Juniper ERX dictionaries are available at:
+# http://www.juniper.net/techpubs/software/erx/junose71/unisphere7-1.dct
+# http://www.juniper.net/techpubs/software/erx/junose700/unisphere7-0.dct
+# http://www.juniper.net/techpubs/software/erx/junose700/swconfig-broadband/html/radius-attributes.html
+# http://www.juniper.net/techpubs/software/erx/junose52/unisphere5-2.dct
+# http://www.juniper.net/techpubs/software/erx/erx50x/swconfig-broadband/html/radius-attributes.html
+# (The below are from when it was the Unisphere ERX)
+# http://www.juniper.net/techpubs/software/erx/erx410/unisphere4-1.dct
+# http://www.juniper.net/techpubs/software/erx/erx403/unisphere4-0.dct
+# http://www.juniper.net/techpubs/software/erx/erx3xx/unisphere3-2.dct
+# http://www.juniper.net/techpubs/software/erx/erx3xx/unisphere3-0.dct
+#
+# As a note on ERX broken-ness, If you don't send a Framed-IP-Address
+# in the Access-Accept packet, the ERX disconnects the user, and
+# sends an Accounting-Request packet with Acct-Status-Type = Stop
+#
+# It does NOT send a 'Start' packet, so this behaviour confuses the
+# heck out of most admins, who do everything right, but have the ERX
+# do stupid things.
+#
+# The ERX supports Ascend "abinary" format. See:
+#
+# http://www.juniper.net/techpubs/software/erx/junose71/swconfig-policy/html/policy-mgmt-apply5.html
+#
+# For this to work in FreeRADIUS, you will have to specify the attribute
+# in hex, as in:
+#
+# Ascend-Data-Filter = 0x010203...
+#
+
+VENDOR ERX 4874
+
+BEGIN-VENDOR ERX
+
+ATTRIBUTE ERX-Virtual-Router-Name 1 string
+ATTRIBUTE ERX-Address-Pool-Name 2 string
+ATTRIBUTE ERX-Local-Loopback-Interface 3 string
+ATTRIBUTE ERX-Primary-Dns 4 ipaddr
+ATTRIBUTE ERX-Secondary-Dns 5 ipaddr
+ATTRIBUTE ERX-Primary-Wins 6 ipaddr
+ATTRIBUTE ERX-Secondary-Wins 7 ipaddr
+ATTRIBUTE ERX-Tunnel-Virtual-Router 8 string has_tag
+ATTRIBUTE ERX-Tunnel-Password 9 string has_tag # sent in cleartext!
+ATTRIBUTE ERX-Ingress-Policy-Name 10 string
+ATTRIBUTE ERX-Egress-Policy-Name 11 string
+ATTRIBUTE ERX-Ingress-Statistics 12 integer
+ATTRIBUTE ERX-Egress-Statistics 13 integer
+ATTRIBUTE ERX-Atm-Service-Category 14 integer
+ATTRIBUTE ERX-Atm-PCR 15 integer
+ATTRIBUTE ERX-Atm-SCR 16 integer
+ATTRIBUTE ERX-Atm-MBS 17 integer
+ATTRIBUTE ERX-Cli-Initial-Access-Level 18 string
+ATTRIBUTE ERX-Cli-Allow-All-VR-Access 19 integer
+ATTRIBUTE ERX-Alternate-Cli-Access-Level 20 string
+ATTRIBUTE ERX-Alternate-Cli-Vrouter-Name 21 string
+ATTRIBUTE ERX-Sa-Validate 22 integer
+ATTRIBUTE ERX-Igmp-Enable 23 integer
+ATTRIBUTE ERX-Pppoe-Description 24 string
+ATTRIBUTE ERX-Redirect-VR-Name 25 string
+ATTRIBUTE ERX-Qos-Profile-Name 26 string
+ATTRIBUTE ERX-Pppoe-Max-Sessions 27 integer
+ATTRIBUTE ERX-Pppoe-Url 28 string
+ATTRIBUTE ERX-Qos-Profile-Interface-Type 29 integer
+ATTRIBUTE ERX-Tunnel-Nas-Port-Method 30 integer
+ATTRIBUTE ERX-Service-Bundle 31 string
+ATTRIBUTE ERX-Tunnel-Tos 32 integer
+ATTRIBUTE ERX-Tunnel-Maximum-Sessions 33 integer
+ATTRIBUTE ERX-Framed-Ip-Route-Tag 34 string
+ATTRIBUTE ERX-Dial-Out-Number 35 string
+ATTRIBUTE ERX-PPP-Username 36 string
+ATTRIBUTE ERX-PPP-Password 37 string
+ATTRIBUTE ERX-PPP-Auth-Protocol 38 integer
+ATTRIBUTE ERX-Minimum-BPS 39 integer
+ATTRIBUTE ERX-Maximum-BPS 40 integer
+ATTRIBUTE ERX-Bearer-Type 41 integer
+ATTRIBUTE ERX-Input-Gigapkts 42 integer
+ATTRIBUTE ERX-Output-Gigapkts 43 integer
+ATTRIBUTE ERX-Tunnel-Interface-Id 44 string
+ATTRIBUTE ERX-IpV6-Virtual-Router 45 string
+ATTRIBUTE ERX-IpV6-Local-Interface 46 string
+ATTRIBUTE ERX-Ipv6-Primary-Dns 47 ipv6addr
+ATTRIBUTE ERX-Ipv6-Secondary-Dns 48 ipv6addr
+ATTRIBUTE Sdx-Service-Name 49 string
+ATTRIBUTE Sdx-Session-Volume-Quota 50 string
+ATTRIBUTE Sdx-Tunnel-Disconnect-Cause-Info 51 string
+ATTRIBUTE ERX-Radius-Client-Address 52 ipaddr
+ATTRIBUTE ERX-Service-Description 53 string
+ATTRIBUTE ERX-L2tp-Recv-Window-Size 54 integer
+ATTRIBUTE ERX-Dhcp-Options 55 octets
+ATTRIBUTE ERX-Dhcp-Mac-Addr 56 string
+ATTRIBUTE ERX-Dhcp-Gi-Address 57 ipaddr
+ATTRIBUTE ERX-LI-Action 58 integer encrypt=2
+ATTRIBUTE ERX-Med-Dev-Handle 59 octets encrypt=2
+ATTRIBUTE ERX-Med-Ip-Address 60 ipaddr encrypt=2
+ATTRIBUTE ERX-Med-Port-Number 61 integer encrypt=2
+ATTRIBUTE ERX-MLPPP-Bundle-Name 62 string
+ATTRIBUTE ERX-Interface-Desc 63 string
+ATTRIBUTE ERX-Tunnel-Group 64 string
+ATTRIBUTE ERX-Service-Activate 65 string has_tag
+ATTRIBUTE ERX-Service-Deactivate 66 string
+ATTRIBUTE ERX-Service-Volume 67 integer has_tag
+ATTRIBUTE ERX-Service-Timeout 68 integer has_tag
+ATTRIBUTE ERX-Service-Statistics 69 integer has_tag
+
+ATTRIBUTE ERX-DF-Bit 70 integer
+
+ATTRIBUTE ERX-IGMP-Access-Name 71 string
+ATTRIBUTE ERX-IGMP-Access-Src-Name 72 string
+ATTRIBUTE ERX-IGMP-OIF-Map-Name 73 string
+
+ATTRIBUTE ERX-MLD-Access-Name 74 string
+ATTRIBUTE ERX-MLD-Access-Src-Name 75 string
+ATTRIBUTE ERX-MLD-OIF-Map-Name 76 string
+ATTRIBUTE ERX-MLD-Version 77 integer
+ATTRIBUTE ERX-IGMP-Version 78 integer
+ATTRIBUTE ERX-IP-Mcast-Adm-Bw-Limit 79 integer
+ATTRIBUTE ERX-IPv6-Mcast-Adm-Bw-Limit 80 integer
+ATTRIBUTE ERX-Qos-Parameters 82 string
+ATTRIBUTE ERX-Service-Session 83 string
+
+ATTRIBUTE ERX-Mobile-IP-Algorithm 84 integer
+ATTRIBUTE ERX-Mobile-IP-SPI 85 integer
+ATTRIBUTE ERX-Mobile-IP-Key 86 string
+ATTRIBUTE ERX-Mobile-IP-Replay 87 integer
+ATTRIBUTE ERX-Mobile-IP-Access-Control 88 string
+ATTRIBUTE ERX-Mobile-IP-Lifetime 89 integer
+
+ATTRIBUTE ERX-L2TP-Resynch-Method 90 integer
+
+ATTRIBUTE ERX-Tunnel-Switch-Profile 91 string
+
+ATTRIBUTE ERX-L2c-Up-Stream-Data 92 string
+ATTRIBUTE ERX-L2c-Down-Stream-Data 93 string
+
+ATTRIBUTE ERX-Tunnel-Tx-Speed-Method 94 integer
+
+ATTRIBUTE ERX-IGMP-Query-Interval 95 integer
+ATTRIBUTE ERX-IGMP-Max-Resp-Time 96 integer
+ATTRIBUTE ERX-IGMP-Immediate-Leave 97 integer
+ATTRIBUTE ERX-MLD-Query-Interval 98 integer
+ATTRIBUTE ERX-MLD-Max-Resp-Time 99 integer
+ATTRIBUTE ERX-MLD-Immediate-Leave 100 integer
+ATTRIBUTE ERX-IP-Block-Multicast 101 integer
+
+ATTRIBUTE ERX-IGMP-Explicit-Tracking 102 integer
+ATTRIBUTE ERX-IGMP-No-Tracking-V2-Grps 103 integer
+ATTRIBUTE ERX-MLD-Explicit-Tracking 104 integer
+ATTRIBUTE ERX-MLD-No-Tracking-V1-Grps 105 integer
+
+ATTRIBUTE ERX-IPv6-Ingress-Policy-Name 106 string
+ATTRIBUTE ERX-IPv6-Egress-Policy-Name 107 string
+ATTRIBUTE ERX-CoS-Shaping-Pmt-Type 108 string
+ATTRIBUTE ERX-DHCP-Guided-Relay-Server 109 ipaddr
+
+ATTRIBUTE ERX-Acc-Loop-Cir-Id 110 string
+ATTRIBUTE ERX-Acc-Aggr-Cir-Id-Bin 111 octets
+ATTRIBUTE ERX-Acc-Aggr-Cir-Id-Asc 112 string
+ATTRIBUTE ERX-Act-Data-Rate-Up 113 integer
+ATTRIBUTE ERX-Act-Data-Rate-Dn 114 integer
+ATTRIBUTE ERX-Min-Data-Rate-Up 115 integer
+ATTRIBUTE ERX-Min-Data-Rate-Dn 116 integer
+ATTRIBUTE ERX-Att-Data-Rate-Up 117 integer
+ATTRIBUTE ERX-Att-Data-Rate-Dn 118 integer
+ATTRIBUTE ERX-Max-Data-Rate-Up 119 integer
+ATTRIBUTE ERX-Max-Data-Rate-Dn 120 integer
+ATTRIBUTE ERX-Min-LP-Data-Rate-Up 121 integer
+ATTRIBUTE ERX-Min-LP-Data-Rate-Dn 122 integer
+ATTRIBUTE ERX-Max-Interlv-Delay-Up 123 integer
+ATTRIBUTE ERX-Act-Interlv-Delay-Up 124 integer
+ATTRIBUTE ERX-Max-Interlv-Delay-Dn 125 integer
+ATTRIBUTE ERX-Act-Interlv-Delay-Dn 126 integer
+ATTRIBUTE ERX-DSL-Line-State 127 integer
+ATTRIBUTE ERX-DSL-Type 128 integer
+
+ATTRIBUTE ERX-IPv6-NdRa-Prefix 129 ipv6prefix
+ATTRIBUTE ERX-Qos-Set-Name 130 string
+
+ATTRIBUTE ERX-Service-Acct-Interval 140 integer has_tag
+
+ATTRIBUTE ERX-DownStream-Calc-Rate 141 integer
+ATTRIBUTE ERX-UpStream-Calc-Rate 142 integer
+ATTRIBUTE ERX-Max-Clients-Per-Interface 143 integer
+
+ATTRIBUTE ERX-PPP-Monitor-Ingress-Only 144 integer
+
+ATTRIBUTE ERX-CoS-Scheduler-Pmt-Type 146 string
+ATTRIBUTE ERX-Backup-Address-Pool 147 string
+
+ATTRIBUTE ERX-ICR-Partition-Id 150 string
+ATTRIBUTE ERX-IPv6-Acct-Input-Octets 151 integer
+ATTRIBUTE ERX-IPv6-Acct-Output-Octets 152 integer
+ATTRIBUTE ERX-IPv6-Acct-Input-Packets 153 integer
+ATTRIBUTE ERX-IPv6-Acct-Output-Packets 154 integer
+ATTRIBUTE ERX-IPv6-Acct-Input-Gigawords 155 integer
+ATTRIBUTE ERX-IPv6-Acct-Output-Gigawords 156 integer
+ATTRIBUTE ERX-IPv6-NdRa-Pool-Name 157 string
+ATTRIBUTE ERX-PppoE-Padn 158 string
+ATTRIBUTE ERX-Dhcp-Option-82 159 octets
+ATTRIBUTE ERX-Vlan-Map-Id 160 integer
+ATTRIBUTE ERX-IPv6-Delegated-Pool-Name 161 string
+ATTRIBUTE ERX-Tx-Connect-Speed 162 integer
+ATTRIBUTE ERX-Rx-Connect-Speed 163 integer
+
+# ATTRIBUTE 164 - 173 RESERVED
+ATTRIBUTE ERX-Service-Activate-Type 173 integer has_tag
+ATTRIBUTE ERX-Client-Profile-Name 174 string
+ATTRIBUTE ERX-Redirect-GW-Address 175 ipaddr
+ATTRIBUTE ERX-APN-Name 176 string
+ATTRIBUTE ERX-Cos-Shaping-Rate 177 string
+ATTRIBUTE ERX-Action-Reason 178 string
+ATTRIBUTE ERX-Service-Volume-Gigawords 179 integer has_tag
+ATTRIBUTE ERX-Update-Service 180 string has_tag
+ATTRIBUTE ERX-DHCPv6-Guided-Relay-Server 181 ipv6addr
+ATTRIBUTE ERX-Acc-Loop-Remote-Id 182 string
+ATTRIBUTE ERX-Acc-Loop-Encap 183 octets
+ATTRIBUTE ERX-Inner-Vlan-Map-Id 184 integer
+ATTRIBUTE ERX-Core-Facing-Interface 185 string
+ATTRIBUTE ERX-DHCP-First-Relay-IPv4-Address 189 ipaddr
+ATTRIBUTE ERX-DHCP-First-Relay-IPv6-Address 190 ipv6addr
+ATTRIBUTE ERX-Input-Interface-Filter 191 string
+ATTRIBUTE ERX-Output-Interface-Filter 192 string
+ATTRIBUTE ERX-Pim-Enable 193 integer
+ATTRIBUTE ERX-Bulk-CoA-Transaction-Id 194 integer
+ATTRIBUTE ERX-Bulk-CoA-Identifier 195 integer
+ATTRIBUTE ERX-IPv4-Input-Service-Set 196 string
+ATTRIBUTE ERX-IPv4-Output-Service-Set 197 string
+ATTRIBUTE ERX-IPv4-Input-Service-Filter 198 string
+ATTRIBUTE ERX-IPv4-Output-Service-Filter 199 string
+ATTRIBUTE ERX-IPv6-Input-Service-Set 200 string
+ATTRIBUTE ERX-IPv6-Output-Service-Set 201 string
+ATTRIBUTE ERX-IPv6-Input-Service-Filter 202 string
+ATTRIBUTE ERX-IPv6-Output-Service-Filter 203 string
+ATTRIBUTE ERX-Adv-Pcef-Profile-Name 204 string
+ATTRIBUTE ERX-Adv-Pcef-Rule-Name 205 string
+ATTRIBUTE ERX-Re-Authentication-Catalyst 206 integer
+ATTRIBUTE ERX-DHCPv6-Options 207 octets
+ATTRIBUTE ERX-DHCP-Header 208 octets
+ATTRIBUTE ERX-DHCPv6-Header 209 octets
+ATTRIBUTE ERX-Acct-Request-Reason 210 integer
+
+ATTRIBUTE ERX-Inner-Tag-Protocol-Id 211 string
+ATTRIBUTE ERX-Routing-Services 212 integer
+ATTRIBUTE ERX-Interface-Set-Targeting-Weight 213 integer
+ATTRIBUTE ERX-Interface-Targeting-Weight 214 integer
+ATTRIBUTE ERX-Hybrid-Access-DSL-Downstream-Speed 216 integer
+ATTRIBUTE ERX-Hybrid-Access-LTE-Downstream-Speed 217 integer
+
+ATTRIBUTE ERX-PON-Access-Type 219 integer
+ATTRIBUTE ERX-ONT-ONU-Average-Data-Rate-Downstream 220 integer
+ATTRIBUTE ERX-ONT-ONU-Peak-Data-Rate-Downstream 221 integer
+ATTRIBUTE ERX-ONT-ONU-Maximum-Data-Rate-Upstream 222 integer
+ATTRIBUTE ERX-ONT-ONU-Assured-Data-Rate-Upstream 223 integer
+ATTRIBUTE ERX-PON-Tree-Maximum-Data-Rate-Upstream 224 integer
+ATTRIBUTE ERX-PON-Tree-Maximum-Data-Rate-Downstream 225 integer
+
+ATTRIBUTE ERX-Expected-Throughput-Upstream 226 integer
+ATTRIBUTE ERX-Expected-Throughput-Downstream 227 integer
+ATTRIBUTE ERX-Attainable-Expected-Throughput-Upstream 228 integer
+ATTRIBUTE ERX-Attainable-Expected-Throughput-Downstream 229 integer
+ATTRIBUTE ERX-Gamma-Data-Rate-Upstream 230 integer
+ATTRIBUTE ERX-Gamma-Data-Rate-Downstream 231 integer
+ATTRIBUTE ERX-Attainable-Gamma-Data-Rate-Upstream 232 integer
+ATTRIBUTE ERX-Attainable-Gamma-Data-Rate-Downstream 233 integer
+
+#
+# Values Attribute Name Number
+#
+VALUE ERX-Ingress-Statistics disable 0
+VALUE ERX-Ingress-Statistics enable 1
+
+VALUE ERX-Egress-Statistics disable 0
+VALUE ERX-Egress-Statistics enable 1
+
+VALUE ERX-Atm-Service-Category UBR 1
+VALUE ERX-Atm-Service-Category UBRPCR 2
+VALUE ERX-Atm-Service-Category nrtVBR 3
+VALUE ERX-Atm-Service-Category CBR 4
+
+VALUE ERX-Cli-Allow-All-VR-Access disable 0
+VALUE ERX-Cli-Allow-All-VR-Access enable 1
+
+VALUE ERX-Sa-Validate disable 0
+VALUE ERX-Sa-Validate enable 1
+
+VALUE ERX-Igmp-Enable disable 0
+VALUE ERX-Igmp-Enable enable 1
+
+VALUE ERX-Qos-Profile-Interface-Type IP 1
+VALUE ERX-Qos-Profile-Interface-Type ATM 2
+VALUE ERX-Qos-Profile-Interface-Type HDLC 3
+VALUE ERX-Qos-Profile-Interface-Type ETHERNET 4
+VALUE ERX-Qos-Profile-Interface-Type SERVER-PORT 5
+VALUE ERX-Qos-Profile-Interface-Type ATM-1483 6
+VALUE ERX-Qos-Profile-Interface-Type FRAME-RELAY 7
+VALUE ERX-Qos-Profile-Interface-Type MPLS-MINOR 8
+VALUE ERX-Qos-Profile-Interface-Type CBF 9
+VALUE ERX-Qos-Profile-Interface-Type IP-TUNNEL 10
+VALUE ERX-Qos-Profile-Interface-Type VLAN-SUB 11
+VALUE ERX-Qos-Profile-Interface-Type PPPOE-SUB 12
+
+VALUE ERX-Tunnel-Nas-Port-Method None 0
+VALUE ERX-Tunnel-Nas-Port-Method CISCO-CLID 1
+
+VALUE ERX-PPP-Auth-Protocol None 0
+VALUE ERX-PPP-Auth-Protocol PAP 1
+VALUE ERX-PPP-Auth-Protocol CHAP 2
+VALUE ERX-PPP-Auth-Protocol PAP-CHAP 3
+VALUE ERX-PPP-Auth-Protocol CHAP-PAP 4
+
+VALUE ERX-Bearer-Type None 0
+VALUE ERX-Bearer-Type Analog 1
+VALUE ERX-Bearer-Type Digital 2
+
+VALUE ERX-LI-Action off 0
+VALUE ERX-LI-Action on 1
+VALUE ERX-LI-Action noop 2
+
+VALUE ERX-DF-Bit dont-ignore-df-bit 0
+VALUE ERX-DF-Bit ignore-df-bit 1
+
+VALUE ERX-MLD-Version v1 1
+VALUE ERX-MLD-Version v2 2
+
+VALUE ERX-IGMP-Version v1 1
+VALUE ERX-IGMP-Version v2 2
+VALUE ERX-IGMP-Version v3 3
+
+VALUE ERX-Service-Statistics disabled 0
+VALUE ERX-Service-Statistics time 1
+VALUE ERX-Service-Statistics time-volume 2
+
+VALUE ERX-L2TP-Resynch-Method disable 0
+VALUE ERX-L2TP-Resynch-Method failover 1
+VALUE ERX-L2TP-Resynch-Method silent-failover 2
+VALUE ERX-L2TP-Resynch-Method failover-with-silent-backup 3
+
+VALUE ERX-Tunnel-Tx-Speed-Method static-layer2 1
+VALUE ERX-Tunnel-Tx-Speed-Method dynamic-layer2 2
+VALUE ERX-Tunnel-Tx-Speed-Method qos 3
+VALUE ERX-Tunnel-Tx-Speed-Method actual 4
+
+VALUE ERX-IGMP-Immediate-Leave disabled 0
+VALUE ERX-IGMP-Immediate-Leave enabled 1
+
+VALUE ERX-MLD-Immediate-Leave disabled 0
+VALUE ERX-MLD-Immediate-Leave enabled 1
+
+VALUE ERX-IP-Block-Multicast disabled 0
+VALUE ERX-IP-Block-Multicast enabled 1
+
+VALUE ERX-IGMP-Explicit-Tracking disabled 0
+VALUE ERX-IGMP-Explicit-Tracking enabled 1
+
+VALUE ERX-IGMP-No-Tracking-V2-Grps disabled 0
+VALUE ERX-IGMP-No-Tracking-V2-Grps enabled 1
+
+VALUE ERX-MLD-Explicit-Tracking disabled 0
+VALUE ERX-MLD-Explicit-Tracking enabled 1
+
+VALUE ERX-MLD-No-Tracking-V1-Grps disabled 0
+VALUE ERX-MLD-No-Tracking-V1-Grps enabled 1
+
+VALUE ERX-DSL-Line-State SHOWTIME 1
+VALUE ERX-DSL-Line-State IDLE 2
+VALUE ERX-DSL-Line-State SILENT 3
+
+VALUE ERX-DSL-Type ADSL1 1
+VALUE ERX-DSL-Type ADSL2 2
+VALUE ERX-DSL-Type ADSL2PLUS 3
+VALUE ERX-DSL-Type VDSL1 4
+VALUE ERX-DSL-Type VDSL2 5
+VALUE ERX-DSL-Type SDSL 6
+VALUE ERX-DSL-Type UNKNOWN 7
+
+VALUE ERX-PPP-Monitor-Ingress-Only disabled 0
+VALUE ERX-PPP-Monitor-Ingress-Only enabled 1
+
+VALUE ERX-Service-Activate-Type dynamic 1
+VALUE ERX-Service-Activate-Type opscript 1
+
+VALUE ERX-Pim-Enable disabled 0
+VALUE ERX-Pim-Enable enabled 1
+
+VALUE ERX-Re-Authentication-Catalyst disabled 0
+VALUE ERX-Re-Authentication-Catalyst client-renew 1
+
+VALUE ERX-Acct-Request-Reason Acct-Start-Ack 1
+VALUE ERX-Acct-Request-Reason Periodic 2
+VALUE ERX-Acct-Request-Reason IP-Active 4
+VALUE ERX-Acct-Request-Reason IP-Inactive 8
+VALUE ERX-Acct-Request-Reason IPv6-Active 16
+VALUE ERX-Acct-Request-Reason IPv6-Inactive 32
+VALUE ERX-Acct-Request-Reason Session-Active 64
+VALUE ERX-Acct-Request-Reason Session-Inactive 128
+VALUE ERX-Acct-Request-Reason Line-Speed-Change 256
+VALUE ERX-Acct-Request-Reason Address-Assignment-Change 512
+VALUE ERX-Acct-Request-Reason CoA-Complete 1024
+
+VALUE ERX-Routing-Services disabled 0
+VALUE ERX-Routing-Services enabled 1
+
+VALUE ERX-PON-Access-Type Other 0
+VALUE ERX-PON-Access-Type GPON 1
+VALUE ERX-PON-Access-Type XG-PON1 2
+VALUE ERX-PON-Access-Type TWDM-PON 3
+VALUE ERX-PON-Access-Type XGS-PON 4
+VALUE ERX-PON-Access-Type WDM-PON 5
+VALUE ERX-PON-Access-Type UNKNOWN 7
+
+END-VENDOR ERX
diff --git a/share/dictionary.extreme b/share/dictionary.extreme
new file mode 100644
index 0000000..d180bb9
--- /dev/null
+++ b/share/dictionary.extreme
@@ -0,0 +1,36 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Dictionary for Extreme Networks VSA's.
+# http://www.extremenetworks.com/
+#
+# $Id$
+#
+VENDOR Extreme 1916
+
+BEGIN-VENDOR Extreme
+
+ATTRIBUTE Extreme-CLI-Authorization 201 integer
+ATTRIBUTE Extreme-Shell-Command 202 string
+ATTRIBUTE Extreme-Netlogin-Vlan 203 string
+ATTRIBUTE Extreme-Netlogin-Url 204 string
+ATTRIBUTE Extreme-Netlogin-Url-Desc 205 string
+ATTRIBUTE Extreme-Netlogin-Only 206 integer
+ATTRIBUTE Extreme-User-Location 208 string
+ATTRIBUTE Extreme-Netlogin-Vlan-Tag 209 integer
+ATTRIBUTE Extreme-Netlogin-Extended-Vlan 211 string
+ATTRIBUTE Extreme-Security-Profile 212 string
+ATTRIBUTE Extreme-VM-Name 213 string
+ATTRIBUTE Extreme-VM-VPP-Name 214 string
+ATTRIBUTE Extreme-VM-IP-Addr 215 ipaddr
+ATTRIBUTE Extreme-VM-VLAN-ID 216 integer
+ATTRIBUTE Extreme-VM-VR-Name 217 string
+
+VALUE Extreme-CLI-Authorization Disabled 0
+VALUE Extreme-CLI-Authorization Enabled 1
+
+VALUE Extreme-Netlogin-Only Disabled 0
+VALUE Extreme-Netlogin-Only Enabled 1
+
+END-VENDOR Extreme
diff --git a/share/dictionary.f5 b/share/dictionary.f5
new file mode 100644
index 0000000..abcbfee
--- /dev/null
+++ b/share/dictionary.f5
@@ -0,0 +1,51 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# F5 VSAs
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR F5 3375
+BEGIN-VENDOR F5
+
+ATTRIBUTE F5-LTM-User-Role 1 integer
+ATTRIBUTE F5-LTM-User-Role-Universal 2 integer # enable/disable
+ATTRIBUTE F5-LTM-User-Partition 3 string
+ATTRIBUTE F5-LTM-User-Console 4 integer # enable/disable
+ATTRIBUTE F5-LTM-User-Shell 5 string # supported values are disable, tmsh, and bpsh
+ATTRIBUTE F5-LTM-User-Context-1 10 integer
+ATTRIBUTE F5-LTM-User-Context-2 11 integer
+ATTRIBUTE F5-LTM-User-Info-1 12 string
+ATTRIBUTE F5-LTM-User-Info-2 13 string
+ATTRIBUTE F5-LTM-Audit-Msg 14 string
+
+VALUE F5-LTM-User-Role Administrator 0
+VALUE F5-LTM-User-Role Resource-Admin 20
+VALUE F5-LTM-User-Role User-Manager 40
+VALUE F5-LTM-User-Role Auditor 80
+VALUE F5-LTM-User-Role Manager 100
+VALUE F5-LTM-User-Role App-Editor 300
+VALUE F5-LTM-User-Role Advanced-Operator 350
+VALUE F5-LTM-User-Role Operator 400
+VALUE F5-LTM-User-Role Firewall-Manager 450
+VALUE F5-LTM-User-Role Fraud-Protection-Manager 480
+VALUE F5-LTM-User-Role Certificate-Manager 500
+VALUE F5-LTM-User-Role IRule-Manager 510
+VALUE F5-LTM-User-Role Guest 700
+VALUE F5-LTM-User-Role Web-Application-Security-Administrator 800
+VALUE F5-LTM-User-Role Web-Application-Security-Editor 810
+VALUE F5-LTM-User-Role Acceleration-Policy-Editor 850
+VALUE F5-LTM-User-Role No-Access 900
+
+VALUE F5-LTM-User-Role-Universal Disabled 0
+VALUE F5-LTM-User-Role-Universal Enabled 1
+
+VALUE F5-LTM-User-Console Disabled 0
+VALUE F5-LTM-User-Console Enabled 1
+
+END-VENDOR F5
diff --git a/share/dictionary.fdxtended b/share/dictionary.fdxtended
new file mode 100644
index 0000000..22c5c18
--- /dev/null
+++ b/share/dictionary.fdxtended
@@ -0,0 +1,19 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+VENDOR fdXtended 34536
+
+BEGIN-VENDOR fdXtended
+ATTRIBUTE fdXtended-Bandwidth-Up 1 integer
+ATTRIBUTE fdXtended-Bandwidth-Down 2 integer
+ATTRIBUTE fdXtended-PostAuthURL 3 string
+ATTRIBUTE fdXtended-One2onenat-IP 4 string
+ATTRIBUTE fdXtended-ContentFilter 5 integer
+ATTRIBUTE fdXtended-NetworkPolicy 6 integer
+ATTRIBUTE fdXtended-BytesDown 7 integer
+ATTRIBUTE fdXtended-BytesUp 8 integer
+ATTRIBUTE fdXtended-Expiration 9 string
+ATTRIBUTE fdXtended-SessionTimeout 10 integer
+ATTRIBUTE fdXtended-Wan-Interface 11 string
+END-VENDOR fdXtended
diff --git a/share/dictionary.force10 b/share/dictionary.force10
new file mode 100644
index 0000000..367a6c5
--- /dev/null
+++ b/share/dictionary.force10
@@ -0,0 +1,10 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Version $Id$
+
+VENDOR Force10 6027
+BEGIN-VENDOR Force10
+ATTRIBUTE Force10-AVPair 1 string
+END-VENDOR Force10
diff --git a/share/dictionary.fortinet b/share/dictionary.fortinet
new file mode 100644
index 0000000..d730a1d
--- /dev/null
+++ b/share/dictionary.fortinet
@@ -0,0 +1,55 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Fortinet's VSA's
+#
+# 2019-0502
+#
+# $Id$
+#
+##############################################################################
+
+#
+# Fortinet's VSA's
+#
+
+VENDOR Fortinet 12356
+
+BEGIN-VENDOR Fortinet
+ATTRIBUTE Fortinet-Group-Name 1 string
+ATTRIBUTE Fortinet-Client-IP-Address 2 ipaddr
+ATTRIBUTE Fortinet-Vdom-Name 3 string
+ATTRIBUTE Fortinet-Client-IPv6-Address 4 octets
+ATTRIBUTE Fortinet-Interface-Name 5 string
+ATTRIBUTE Fortinet-Access-Profile 6 string
+ATTRIBUTE Fortinet-SSID 7 string
+ATTRIBUTE Fortinet-AP-Name 8 string
+ATTRIBUTE Fortinet-FAC-Auth-Status 11 string
+ATTRIBUTE Fortinet-FAC-Token-ID 12 string
+ATTRIBUTE Fortinet-FAC-Challenge-Code 15 string
+ATTRIBUTE Fortinet-Webfilter-Category-Allow 16 octets
+ATTRIBUTE Fortinet-Webfilter-Category-Block 17 octets
+ATTRIBUTE Fortinet-Webfilter-Category-Monitor 18 octets
+ATTRIBUTE Fortinet-AppCtrl-Category-Allow 19 octets
+ATTRIBUTE Fortinet-AppCtrl-Category-Block 20 octets
+ATTRIBUTE Fortinet-AppCtrl-Risk-Allow 21 octets
+ATTRIBUTE Fortinet-AppCtrl-Risk-Block 22 octets
+ATTRIBUTE Fortinet-WirelessController-Device-MAC 23 ether
+ATTRIBUTE Fortinet-WirelessController-WTP-ID 24 string
+ATTRIBUTE Fortinet-WirelessController-Assoc-Time 25 date
+ATTRIBUTE Fortinet-FortiWAN-AVPair 26 string
+ATTRIBUTE Fortinet-FDD-Access-Profile 30 string
+ATTRIBUTE Fortinet-FDD-Trusted-Hosts 31 string
+ATTRIBUTE Fortinet-FDD-SPP-Name 32 string
+ATTRIBUTE Fortinet-FDD-Is-System-Admin 33 string
+ATTRIBUTE Fortinet-FDD-Is-SPP-Admin 34 string
+ATTRIBUTE Fortinet-FDD-SPP-Policy-Group 35 string
+ATTRIBUTE Fortinet-FDD-Allow-API-Access 36 string
+ATTRIBUTE Fortinet-Fpc-User-Role 40 string
+ATTRIBUTE Fortinet-Tenant-Identification 41 string
+ATTRIBUTE Fortinet-Host-Port-AVPair 42 string
+
+END-VENDOR Fortinet
diff --git a/share/dictionary.foundry b/share/dictionary.foundry
new file mode 100644
index 0000000..4b34870
--- /dev/null
+++ b/share/dictionary.foundry
@@ -0,0 +1,58 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# As posted to the list by Thomas Keitel <tkeitel@arc.nasa.gov>
+#
+# Version: $Id$
+#
+
+VENDOR Foundry 1991
+
+BEGIN-VENDOR Foundry
+
+ATTRIBUTE Foundry-Privilege-Level 1 integer
+ATTRIBUTE Foundry-Command-String 2 string
+ATTRIBUTE Foundry-Command-Exception-Flag 3 integer
+ATTRIBUTE Foundry-INM-Privilege 4 integer
+ATTRIBUTE Foundry-Access-List 5 string
+ATTRIBUTE Foundry-MAC-Authent-needs-802.1x 6 integer
+ATTRIBUTE Foundry-802.1x-Valid-Lookup 7 integer
+ATTRIBUTE Foundry-MAC-Based-Vlan-QoS 8 integer
+ATTRIBUTE Foundry-INM-Role-Aor-List 9 string
+ATTRIBUTE Foundry-SI-Context-Role 10 string
+# Foundry-COA-Command appears to stomp on Foundry-SI-Context-Role (different departments)
+# https://www.brocade.com/content/html/en/fastiron-os/08-0-60/fastiron-08060-securityguide/GUID-A3193D90-3FF4-4B04-8C6D-084743FDE91C.html
+ATTRIBUTE Foundry-COA-Command 10 string
+ATTRIBUTE Foundry-SI-Role-Template 11 string
+# Foundry-Voice-Phone-Config appears to stomp on Foundry-SI-Role-Template (different departments)
+# http://docs.ruckuswireless.com/fastiron/08.0.60/fastiron-08060-securityguide/GUID-7E649B6D-A80B-40FD-A19A-478ED22C3E2A.html
+ATTRIBUTE Foundry-Voice-Phone-Config 11 string
+
+VALUE Foundry-INM-Privilege AAA_pri_0 0
+VALUE Foundry-INM-Privilege AAA_pri_1 1
+VALUE Foundry-INM-Privilege AAA_pri_2 2
+VALUE Foundry-INM-Privilege AAA_pri_3 3
+VALUE Foundry-INM-Privilege AAA_pri_4 4
+VALUE Foundry-INM-Privilege AAA_pri_5 5
+VALUE Foundry-INM-Privilege AAA_pri_6 6
+VALUE Foundry-INM-Privilege AAA_pri_7 7
+VALUE Foundry-INM-Privilege AAA_pri_8 8
+VALUE Foundry-INM-Privilege AAA_pri_9 9
+VALUE Foundry-INM-Privilege AAA_pri_10 10
+VALUE Foundry-INM-Privilege AAA_pri_11 11
+VALUE Foundry-INM-Privilege AAA_pri_12 12
+VALUE Foundry-INM-Privilege AAA_pri_13 13
+VALUE Foundry-INM-Privilege AAA_pri_14 14
+VALUE Foundry-INM-Privilege AAA_pri_15 15
+
+VALUE Foundry-MAC-Based-Vlan-QoS QoS_priority_0 0
+VALUE Foundry-MAC-Based-Vlan-QoS QoS_priority_1 1
+VALUE Foundry-MAC-Based-Vlan-QoS QoS_priority_2 2
+VALUE Foundry-MAC-Based-Vlan-QoS QoS_priority_3 3
+VALUE Foundry-MAC-Based-Vlan-QoS QoS_priority_4 4
+VALUE Foundry-MAC-Based-Vlan-QoS QoS_priority_5 5
+VALUE Foundry-MAC-Based-Vlan-QoS QoS_priority_6 6
+VALUE Foundry-MAC-Based-Vlan-QoS QoS_priority_7 7
+
+END-VENDOR Foundry
diff --git a/share/dictionary.freedhcp b/share/dictionary.freedhcp
new file mode 100644
index 0000000..fe2836d
--- /dev/null
+++ b/share/dictionary.freedhcp
@@ -0,0 +1,369 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# DHCP options carried inside of RADIUS VSAs.
+#
+# DHCP options can carry up to 255 octets, and RADIUS VSAs can
+# carry only 247 octets. DHCP options can carry multiple things
+# (e.g. IP addresses) in one option, and RADIUS can't.
+#
+# Despite those issues, this dictionary is still useful.
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR FreeDHCP 34673
+
+BEGIN-VENDOR FreeDHCP
+
+##############################################################################
+#
+# DHCP Options, with comments. For now, many are "octets",
+# as FreeRADIUS doesn't handle complex data structures.
+#
+##############################################################################
+
+#ATTRIBUTE FreeDHCP-Pad 0 octets
+ATTRIBUTE FreeDHCP-Subnet-Mask 1 ipaddr
+# Time Offset in twos-complement notation.
+ATTRIBUTE FreeDHCP-Time-Offset 2 integer
+ATTRIBUTE FreeDHCP-Router-Address 3 ipaddr array
+ATTRIBUTE FreeDHCP-Time-Server 4 ipaddr array
+ATTRIBUTE FreeDHCP-IEN-116-Name-Server 5 ipaddr array
+ATTRIBUTE FreeDHCP-Domain-Name-Server 6 ipaddr array
+# Logging-Server addresses
+ATTRIBUTE FreeDHCP-Log-Server 7 ipaddr array
+ATTRIBUTE FreeDHCP-Quotes-Server 8 ipaddr array
+ATTRIBUTE FreeDHCP-LPR-Server 9 ipaddr array
+ATTRIBUTE FreeDHCP-Impress-Server 10 ipaddr array
+ATTRIBUTE FreeDHCP-RLP-Server 11 ipaddr array
+# Hostname string
+ATTRIBUTE FreeDHCP-Hostname 12 string
+# Size of boot file in 512 byte
+ATTRIBUTE FreeDHCP-Boot-File-Size 13 short
+# Client to dump and name
+ATTRIBUTE FreeDHCP-Merit-Dump-File 14 octets
+ATTRIBUTE FreeDHCP-Domain-Name 15 string
+ATTRIBUTE FreeDHCP-Swap-Server 16 ipaddr
+# Path name for root disk
+ATTRIBUTE FreeDHCP-Root-Path 17 string
+ATTRIBUTE FreeDHCP-Bootp-Extensions-Path 18 string
+ATTRIBUTE FreeDHCP-IP-Forward-Enable 19 byte
+ATTRIBUTE FreeDHCP-Source-Route-Enable 20 byte
+# Routing Policy Filters
+ATTRIBUTE FreeDHCP-Policy-Filter 21 octets
+ATTRIBUTE FreeDHCP-Max-Datagram-Reassembly-Sz 22 short
+ATTRIBUTE FreeDHCP-Default-IP-TTL 23 octets
+ATTRIBUTE FreeDHCP-Path-MTU-Aging-Timeout 24 integer
+ATTRIBUTE FreeDHCP-Path-MTU-Plateau-Table 25 short array
+ATTRIBUTE FreeDHCP-Interface-MTU-Size 26 short
+ATTRIBUTE FreeDHCP-All-Subnets-Are-Local 27 byte
+ATTRIBUTE FreeDHCP-Broadcast-Address 28 ipaddr
+ATTRIBUTE FreeDHCP-Perform-Mask-Discovery 29 byte
+ATTRIBUTE FreeDHCP-Provide-Mask-To-Others 30 byte
+ATTRIBUTE FreeDHCP-Perform-Router-Discovery 31 byte
+ATTRIBUTE FreeDHCP-Router-Solicitation-Address 32 ipaddr
+# first is destination address, second is router.
+ATTRIBUTE FreeDHCP-Static-Routes 33 ipaddr array
+ATTRIBUTE FreeDHCP-Trailer-Encapsulation 34 byte
+ATTRIBUTE FreeDHCP-ARP-Cache-Timeout 35 integer
+ATTRIBUTE FreeDHCP-Ethernet-Encapsulation 36 byte
+ATTRIBUTE FreeDHCP-Default-TCP-TTL 37 byte
+ATTRIBUTE FreeDHCP-Keep-Alive-Interval 38 integer
+ATTRIBUTE FreeDHCP-Keep-Alive-Garbage 39 byte
+ATTRIBUTE FreeDHCP-NIS-Domain-Name 40 string
+ATTRIBUTE FreeDHCP-NIS-Servers 41 ipaddr array
+ATTRIBUTE FreeDHCP-NTP-Servers 42 ipaddr array
+# N Vendor Specific Information
+ATTRIBUTE FreeDHCP-Vendor 43 octets # tlv
+ATTRIBUTE FreeDHCP-NETBIOS-Name-Servers 44 ipaddr array
+ATTRIBUTE FreeDHCP-NETBIOS-Dgm-Dist-Servers 45 ipaddr array
+ATTRIBUTE FreeDHCP-NETBIOS-Node-Type 46 byte
+# N NETBIOS Scope
+ATTRIBUTE FreeDHCP-NETBIOS 47 octets
+ATTRIBUTE FreeDHCP-X-Window-Font-Server 48 ipaddr array
+ATTRIBUTE FreeDHCP-X-Window-Display-Mgr 49 ipaddr array
+ATTRIBUTE FreeDHCP-Requested-IP-Address 50 ipaddr
+ATTRIBUTE FreeDHCP-IP-Address-Lease-Time 51 integer
+# Overload "sname" or "file"
+ATTRIBUTE FreeDHCP-Overload 52 byte
+ATTRIBUTE FreeDHCP-Message-Type 53 byte
+ATTRIBUTE FreeDHCP-FreeDHCP-Server-Identifier 54 ipaddr
+
+# Array of 1-byte numbers indicating which options the client
+# would like to see in the response.
+ATTRIBUTE FreeDHCP-Parameter-Request-List 55 byte array
+ATTRIBUTE FreeDHCP-FreeDHCP-Error-Message 56 octets
+ATTRIBUTE FreeDHCP-FreeDHCP-Maximum-Msg-Size 57 short
+ATTRIBUTE FreeDHCP-Renewal-Time 58 integer
+ATTRIBUTE FreeDHCP-Rebinding-Time 59 integer
+ATTRIBUTE FreeDHCP-Vendor-Class-Identifier 60 string
+
+# Client Identifier
+# First octets is FreeDHCP-Hardware-Type, rest are type-specific data,
+# e.g. MAC address.
+ATTRIBUTE FreeDHCP-Client-Identifier 61 octets
+ATTRIBUTE FreeDHCP-Netware-Domain-Name 62 octets
+ATTRIBUTE FreeDHCP-Netware-Sub-Options 63 octets
+ATTRIBUTE FreeDHCP-NIS-Client-Domain-Name 64 octets
+ATTRIBUTE FreeDHCP-NIS-Server-Address 65 ipaddr
+ATTRIBUTE FreeDHCP-TFTP-Server-Name 66 string
+ATTRIBUTE FreeDHCP-Boot-File-Name 67 string
+# Home Agent Addresses
+ATTRIBUTE FreeDHCP-Home-Agent-Address 68 octets
+ATTRIBUTE FreeDHCP-SMTP-Server-Address 69 ipaddr array
+ATTRIBUTE FreeDHCP-POP3-Server-Address 70 ipaddr array
+ATTRIBUTE FreeDHCP-NNTP-Server-Address 71 ipaddr array
+ATTRIBUTE FreeDHCP-WWW-Server-Address 72 ipaddr array
+ATTRIBUTE FreeDHCP-Finger-Server-Address 73 ipaddr array
+ATTRIBUTE FreeDHCP-IRC-Server-Address 74 ipaddr array
+ATTRIBUTE FreeDHCP-StreetTalk-Server-Address 75 ipaddr array
+ATTRIBUTE FreeDHCP-STDA-Server-Address 76 ipaddr array
+# User Class Information
+ATTRIBUTE FreeDHCP-User-Class 77 octets
+# directory agent information
+ATTRIBUTE FreeDHCP-Directory-Agent 78 octets
+# service location agent scope
+ATTRIBUTE FreeDHCP-Service-Scope 79 octets
+# Rapid Commit
+ATTRIBUTE FreeDHCP-Rapid-Commit 80 octets
+# Fully Qualified Domain Name
+ATTRIBUTE FreeDHCP-Client-FQDN 81 string
+# Relay Agent Information
+ATTRIBUTE FreeDHCP-Relay-Agent-Information 82 tlv
+
+ATTRIBUTE FreeDHCP-Agent-Circuit-Id 82.1 octets
+ATTRIBUTE FreeDHCP-Agent-Remote-Id 82.2 octets
+
+ATTRIBUTE FreeDHCP-Relay-Circuit-Id 82.1 octets
+ATTRIBUTE FreeDHCP-Relay-Remote-Id 82.2 octets
+
+# 3 is reserved and shouldn't be used for anything
+ATTRIBUTE FreeDHCP-Docsis-Device-Class 82.4 integer
+ATTRIBUTE FreeDHCP-Relay-Link-Selection 82.5 ipaddr
+ATTRIBUTE FreeDHCP-Subscriber-Id 82.6 string
+
+# AGH! RADIUS inside of DHCP!
+ATTRIBUTE FreeDHCP-RADIUS-Attributes 82.7 octets
+
+# Horribly complicated
+ATTRIBUTE FreeDHCP-Authentication-Information 82.8 octets
+ATTRIBUTE FreeDHCP-Vendor-Specific-Information 82.9 octets
+ATTRIBUTE FreeDHCP-Relay-Agent-Flags 82.10 byte
+ATTRIBUTE FreeDHCP-Server-Identifier-Override 82.11 ipaddr
+
+# Internet Storage Name Service
+ATTRIBUTE FreeDHCP-iSNS 83 octets
+# Novell Directory Services
+ATTRIBUTE FreeDHCP-NDS-Servers 85 octets
+# Novell Directory Services
+ATTRIBUTE FreeDHCP-NDS-Tree-Name 86 octets
+# Novell Directory Services
+ATTRIBUTE FreeDHCP-NDS-Context 87 octets
+# Authentication
+ATTRIBUTE FreeDHCP-Authentication 90 octets
+
+ATTRIBUTE FreeDHCP-Client-Last-Txn-Time 91 octets
+
+ATTRIBUTE FreeDHCP-associated-ip 92 octets
+# Client System Architecture
+ATTRIBUTE FreeDHCP-Client-System 93 octets
+# Client Network Device Interface
+ATTRIBUTE FreeDHCP-Client-NDI 94 octets
+# Lightweight Directory Access Protocol
+ATTRIBUTE FreeDHCP-LDAP 95 octets
+# UUID/GUID-based Client Identifier
+ATTRIBUTE FreeDHCP-UUID/GUID 97 octets
+# Open Group's User Authentication
+ATTRIBUTE FreeDHCP-User-Auth 98 octets
+# NetInfo Parent-Server Address
+ATTRIBUTE FreeDHCP-Netinfo-Address 112 octets
+# NetInfo Parent-Server Tag
+ATTRIBUTE FreeDHCP-Netinfo-Tag 113 octets
+# URL
+ATTRIBUTE FreeDHCP-URL 114 octets
+# DHCP Auto-Configuration
+ATTRIBUTE FreeDHCP-Auto-Config 116 byte
+# Name Service Search
+ATTRIBUTE FreeDHCP-Name-Service-Search 117 octets
+# Subnet Selection Option
+ATTRIBUTE FreeDHCP-Subnet-Selection-Option 118 octets
+# DNS domain serach list
+ATTRIBUTE FreeDHCP-Domain-Search 119 octets
+# SIP-Servers DHCP Option
+ATTRIBUTE FreeDHCP-SIP-Servers-FreeDHCP-Option 120 octets
+# Classless Static Route Option
+ATTRIBUTE FreeDHCP-Classless-Static-Route 121 octets
+# CableLabs Client Configuration
+ATTRIBUTE FreeDHCP-CCC 122 octets
+# 16 GeoConf Option
+ATTRIBUTE FreeDHCP-GeoConf-Option 123 octets
+
+# Vendor Class
+#
+# String name that defines the vendor space used for the TLV's
+# in option 125.
+#
+ATTRIBUTE FreeDHCP-V-I-Vendor-Class 124 octets
+# Vendor-Specific
+ATTRIBUTE FreeDHCP-V-I-Vendor-Specific 125 octets # tlv
+ATTRIBUTE FreeDHCP-Etherboot 128 ether
+# (for IP Phone software load)
+ATTRIBUTE FreeDHCP-TFTP-Server-IP-Address 128 octets
+
+ATTRIBUTE FreeDHCP-Call-Server-IP-address 129 octets
+
+ATTRIBUTE FreeDHCP-Ethernet-Interface 130 octets
+
+ATTRIBUTE FreeDHCP-Vendor-Discrimination-Str 130 octets
+
+ATTRIBUTE FreeDHCP-Remote-Stats-Svr-IP-Address 131 octets
+
+ATTRIBUTE FreeDHCP-IEEE-802.1Q-L2-Priority 132 octets
+
+ATTRIBUTE FreeDHCP-IEEE-802.1P-VLAN-ID 133 octets
+
+ATTRIBUTE FreeDHCP-Diffserv-Code-Point 134 octets
+
+ATTRIBUTE FreeDHCP-HTTP-Proxy 135 octets
+
+ATTRIBUTE FreeDHCP-Cisco-TFTP-Server-IP-Addresses 150 ipaddr array
+
+ATTRIBUTE FreeDHCP-End-Of-Options 255 byte
+
+VALUE FreeDHCP-Opcode Client-Message 1
+VALUE FreeDHCP-Opcode Server-Message 2
+
+VALUE FreeDHCP-Message-Type FreeDHCP-Discover 1
+VALUE FreeDHCP-Message-Type FreeDHCP-Offer 2
+VALUE FreeDHCP-Message-Type FreeDHCP-Request 3
+VALUE FreeDHCP-Message-Type FreeDHCP-Decline 4
+VALUE FreeDHCP-Message-Type FreeDHCP-Ack 5
+VALUE FreeDHCP-Message-Type FreeDHCP-NAK 6
+VALUE FreeDHCP-Message-Type FreeDHCP-Release 7
+VALUE FreeDHCP-Message-Type FreeDHCP-Inform 8
+VALUE FreeDHCP-Message-Type FreeDHCP-Force-Renew 9
+
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Subnet-Mask 1
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Time-Offset 2
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Router-Address 3
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Time-Server 4
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-IEN-116-Name-Server 5
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Domain-Name-Server 6
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Log-Server 7
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Quotes-Server 8
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-LPR-Server 9
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Impress-Server 10
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-RLP-Server 11
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Hostname 12
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Boot-File-Size 13
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Merit-Dump-File 14
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Domain-Name 15
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Swap-Server 16
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Root-Path 17
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Bootp-Extensions-Path 18
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-IP-Forward-Enable 19
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Source-Route-Enable 20
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Policy-Filter 21
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Max-Datagram-Reassembly-Sz 22
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Default-IP-TTL 23
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Path-MTU-Aging-Timeout 24
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Path-MTU-Plateau-Table 25
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Interface-MTU-Size 26
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-All-Subnets-Are-Local 27
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Broadcast-Address 28
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Perform-Mask-Discovery 29
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Provide-Mask-To-Others 30
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Perform-Router-Discovery 31
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Router-Solicitation-Address 32
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Static-Routes 33
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Trailer-Encapsulation 34
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-ARP-Cache-Timeout 35
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Ethernet-Encapsulation 36
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Default-TCP-TTL 37
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Keep-Alive-Interval 38
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Keep-Alive-Garbage 39
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-NIS-Domain-Name 40
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-NIS-Servers 41
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-NTP-Servers 42
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Vendor 43
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-NETBIOS-Name-Servers 44
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-NETBIOS-Dgm-Dist-Servers 45
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-NETBIOS-Node-Type 46
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-NETBIOS 47
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-X-Window-Font-Server 48
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-X-Window-Display-Mgr 49
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Requested-IP-Address 50
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-IP-Address-Lease-Time 51
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Overload 52
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Message-Type 53
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-FreeDHCP-Server-Identifier 54
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Parameter-Request-List 55
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-FreeDHCP-Error-Message 56
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-FreeDHCP-Maximum-Msg-Size 57
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Renewal-Time 58
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Rebinding-Time 59
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Class-Identifier 60
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Client-Identifier 61
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Netware-Domain-Name 62
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Netware-Sub-Options 63
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-NIS-Client-Domain-Name 64
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-NIS-Server-Address 65
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-TFTP-Server-Name 66
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Boot-File-Name 67
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Home-Agent-Address 68
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-SMTP-Server-Address 69
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-POP3-Server-Address 70
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-NNTP-Server-Address 71
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-WWW-Server-Address 72
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Finger-Server-Address 73
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-IRC-Server-Address 74
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-StreetTalk-Server-Address 75
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-STDA-Server-Address 76
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-User-Class 77
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Directory-Agent 78
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Service-Scope 79
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Rapid-Commit 80
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Client-FQDN 81
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Relay-Agent-Information 82
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-iSNS 83
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-NDS-Servers 85
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-NDS-Tree-Name 86
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-NDS-Context 87
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Authentication 90
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Client-Last-Txn-Time 91
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-associated-ip 92
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Client-System 93
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Client-NDI 94
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-LDAP 95
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-UUID/GUID 97
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-User-Auth 98
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Netinfo-Address 112
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Netinfo-Tag 113
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-URL 114
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Auto-Config 116
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Name-Service-Search 117
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Subnet-Selection-Option 118
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Domain-Search 119
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-SIP-Servers-FreeDHCP-Option 120
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Classless-Static-Route 121
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-CCC 122
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-GeoConf-Option 123
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-V-I-Vendor-Class 124
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-V-I-Vendor-Specific 125
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Etherboot 128
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-TFTP-Server-IP-Address 128
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Call-Server-IP-address 129
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Ethernet-Interface 130
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Vendor-Discrimination-Str 130
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Remote-Stats-Svr-IP-Address 131
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-IEEE-802.1P-VLAN-ID 132
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-IEEE-802.1Q-L2-Priority 133
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-Diffserv-Code-Point 134
+VALUE FreeDHCP-Parameter-Request-List FreeDHCP-HTTP-Proxy 135
+
+END-VENDOR FreeDHCP
diff --git a/share/dictionary.freeradius b/share/dictionary.freeradius
new file mode 100644
index 0000000..0ac6182
--- /dev/null
+++ b/share/dictionary.freeradius
@@ -0,0 +1,202 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# The FreeRADIUS Vendor-Specific dictionary.
+#
+# Version: $Id$
+#
+
+VENDOR FreeRADIUS 11344
+
+BEGIN-VENDOR FreeRADIUS
+
+ATTRIBUTE FreeRADIUS-Proxied-To 1 ipaddr
+ATTRIBUTE FreeRADIUS-Acct-Session-Start-Time 2 date
+
+#
+# This attribute is really a bitmask.
+#
+ATTRIBUTE FreeRADIUS-Statistics-Type 127 integer
+
+VALUE FreeRADIUS-Statistics-Type None 0
+VALUE FreeRADIUS-Statistics-Type Authentication 1
+VALUE FreeRADIUS-Statistics-Type Accounting 2
+VALUE FreeRADIUS-Statistics-Type Proxy-Authentication 4
+VALUE FreeRADIUS-Statistics-Type Proxy-Accounting 8
+VALUE FreeRADIUS-Statistics-Type Internal 0x10
+VALUE FreeRADIUS-Statistics-Type Client 0x20
+VALUE FreeRADIUS-Statistics-Type Server 0x40
+VALUE FreeRADIUS-Statistics-Type Home-Server 0x80
+
+VALUE FreeRADIUS-Statistics-Type Auth-Acct 0x03
+VALUE FreeRADIUS-Statistics-Type Proxy-Auth-Acct 0x0c
+
+VALUE FreeRADIUS-Statistics-Type All 0x1f
+
+#
+# Global authentication statistics for packets received by the server.
+#
+ATTRIBUTE FreeRADIUS-Total-Access-Requests 128 integer
+ATTRIBUTE FreeRADIUS-Total-Access-Accepts 129 integer
+ATTRIBUTE FreeRADIUS-Total-Access-Rejects 130 integer
+ATTRIBUTE FreeRADIUS-Total-Access-Challenges 131 integer
+ATTRIBUTE FreeRADIUS-Total-Auth-Responses 132 integer
+ATTRIBUTE FreeRADIUS-Total-Auth-Duplicate-Requests 133 integer
+ATTRIBUTE FreeRADIUS-Total-Auth-Malformed-Requests 134 integer
+ATTRIBUTE FreeRADIUS-Total-Auth-Invalid-Requests 135 integer
+ATTRIBUTE FreeRADIUS-Total-Auth-Dropped-Requests 136 integer
+ATTRIBUTE FreeRADIUS-Total-Auth-Unknown-Types 137 integer
+
+#
+# Global statistics for auth packets sent by the server to all home servers
+#
+ATTRIBUTE FreeRADIUS-Total-Proxy-Access-Requests 138 integer
+ATTRIBUTE FreeRADIUS-Total-Proxy-Access-Accepts 139 integer
+ATTRIBUTE FreeRADIUS-Total-Proxy-Access-Rejects 140 integer
+ATTRIBUTE FreeRADIUS-Total-Proxy-Access-Challenges 141 integer
+ATTRIBUTE FreeRADIUS-Total-Proxy-Auth-Responses 142 integer
+ATTRIBUTE FreeRADIUS-Total-Proxy-Auth-Duplicate-Requests 143 integer
+ATTRIBUTE FreeRADIUS-Total-Proxy-Auth-Malformed-Requests 144 integer
+ATTRIBUTE FreeRADIUS-Total-Proxy-Auth-Invalid-Requests 145 integer
+ATTRIBUTE FreeRADIUS-Total-Proxy-Auth-Dropped-Requests 146 integer
+ATTRIBUTE FreeRADIUS-Total-Proxy-Auth-Unknown-Types 147 integer
+
+#
+# Global accounting statistics for packets received by the server.
+#
+ATTRIBUTE FreeRADIUS-Total-Accounting-Requests 148 integer
+ATTRIBUTE FreeRADIUS-Total-Accounting-Responses 149 integer
+ATTRIBUTE FreeRADIUS-Total-Acct-Duplicate-Requests 150 integer
+ATTRIBUTE FreeRADIUS-Total-Acct-Malformed-Requests 151 integer
+ATTRIBUTE FreeRADIUS-Total-Acct-Invalid-Requests 152 integer
+ATTRIBUTE FreeRADIUS-Total-Acct-Dropped-Requests 153 integer
+ATTRIBUTE FreeRADIUS-Total-Acct-Unknown-Types 154 integer
+
+#
+# Global statistics for acct packets sent by the server to all home servers
+#
+ATTRIBUTE FreeRADIUS-Total-Proxy-Accounting-Requests 155 integer
+ATTRIBUTE FreeRADIUS-Total-Proxy-Accounting-Responses 156 integer
+ATTRIBUTE FreeRADIUS-Total-Proxy-Acct-Duplicate-Requests 157 integer
+ATTRIBUTE FreeRADIUS-Total-Proxy-Acct-Malformed-Requests 158 integer
+ATTRIBUTE FreeRADIUS-Total-Proxy-Acct-Invalid-Requests 159 integer
+ATTRIBUTE FreeRADIUS-Total-Proxy-Acct-Dropped-Requests 160 integer
+ATTRIBUTE FreeRADIUS-Total-Proxy-Acct-Unknown-Types 161 integer
+
+#
+# Internal queues. Different packet types are put into different queues.
+#
+ATTRIBUTE FreeRADIUS-Queue-Len-Internal 162 integer
+ATTRIBUTE FreeRADIUS-Queue-Len-Proxy 163 integer
+ATTRIBUTE FreeRADIUS-Queue-Len-Auth 164 integer
+ATTRIBUTE FreeRADIUS-Queue-Len-Acct 165 integer
+ATTRIBUTE FreeRADIUS-Queue-Len-Detail 166 integer
+
+ATTRIBUTE FreeRADIUS-Stats-Client-IP-Address 167 ipaddr
+ATTRIBUTE FreeRADIUS-Stats-Client-Number 168 integer
+ATTRIBUTE FreeRADIUS-Stats-Client-Netmask 169 integer
+
+ATTRIBUTE FreeRADIUS-Stats-Server-IP-Address 170 ipaddr
+ATTRIBUTE FreeRADIUS-Stats-Server-Port 171 integer
+
+ATTRIBUTE FreeRADIUS-Stats-Server-Outstanding-Requests 172 integer
+ATTRIBUTE FreeRADIUS-Stats-Server-State 173 integer
+
+VALUE FreeRADIUS-Stats-Server-State Alive 0
+VALUE FreeRADIUS-Stats-Server-State Zombie 1
+VALUE FreeRADIUS-Stats-Server-State Dead 2
+VALUE FreeRADIUS-Stats-Server-State Idle 3
+VALUE FreeRADIUS-Stats-Server-State Admin-Down 4
+VALUE FreeRADIUS-Stats-Server-State Connection-Fail 5
+
+#
+# When a home server is marked "dead" or "alive"
+#
+ATTRIBUTE FreeRADIUS-Stats-Server-Time-Of-Death 174 date
+ATTRIBUTE FreeRADIUS-Stats-Server-Time-Of-Life 175 date
+
+#
+# When this server was started. If start == hup, it hasn't been
+# hup'd yet. This is friendlier than having hup == 0 on start.
+#
+ATTRIBUTE FreeRADIUS-Stats-Start-Time 176 date
+ATTRIBUTE FreeRADIUS-Stats-HUP-Time 177 date
+
+#
+# Exponential moving average of home server response time
+# Window-1 is the average is calculated over "window" packets.
+# Window-10 is the average is calculated over "10 * window" packets.
+#
+# Both Window-1 and Window-10 are times in microseconds
+# (1/1000000 of a second).
+#
+ATTRIBUTE FreeRADIUS-Server-EMA-Window 178 integer
+ATTRIBUTE FreeRADIUS-Server-EMA-USEC-Window-1 179 integer
+ATTRIBUTE FreeRADIUS-Server-EMA-USEC-Window-10 180 integer
+
+ATTRIBUTE FreeRADIUS-Queue-PPS-In 181 integer
+ATTRIBUTE FreeRADIUS-Queue-PPS-Out 182 integer
+ATTRIBUTE FreeRADIUS-Queue-Use-Percentage 183 integer
+
+ATTRIBUTE FreeRADIUS-Stats-Last-Packet-Recv 184 date
+ATTRIBUTE FreeRADIUS-Stats-Last-Packet-Sent 185 date
+
+#
+# EAP-FAST TLVs
+#
+ATTRIBUTE FreeRADIUS-EAP-FAST-TLV 186 tlv
+ATTRIBUTE FreeRADIUS-EAP-FAST-Result 186.3 short
+ATTRIBUTE FreeRADIUS-EAP-FAST-NAK 186.4 octets
+ATTRIBUTE FreeRADIUS-EAP-FAST-Error 186.5 integer
+ATTRIBUTE FreeRADIUS-EAP-FAST-Vendor-Specific 186.7 octets
+ATTRIBUTE FreeRADIUS-EAP-FAST-EAP-Payload 186.9 octets
+ATTRIBUTE FreeRADIUS-EAP-FAST-Intermediate-Result 186.10 octets
+
+ATTRIBUTE FreeRADIUS-EAP-FAST-PAC 186.11 tlv
+ATTRIBUTE FreeRADIUS-EAP-FAST-PAC-Key 186.11.1 octets
+
+ATTRIBUTE FreeRADIUS-EAP-FAST-PAC-Opaque-TLV 186.11.2 tlv
+ATTRIBUTE FreeRADIUS-EAP-FAST-PAC-Opaque-PAC-Key 186.11.2.1 octets
+ATTRIBUTE FreeRADIUS-EAP-FAST-PAC-Opaque-PAC-Lifetime 186.11.2.3 integer
+ATTRIBUTE FreeRADIUS-EAP-FAST-PAC-Opaque-I-ID 186.11.2.5 octets
+ATTRIBUTE FreeRADIUS-EAP-FAST-PAC-Opaque-PAC-Type 186.11.2.10 short
+
+ATTRIBUTE FreeRADIUS-EAP-FAST-PAC-Lifetime 186.11.3 integer
+ATTRIBUTE FreeRADIUS-EAP-FAST-PAC-A-ID 186.11.4 octets
+ATTRIBUTE FreeRADIUS-EAP-FAST-PAC-I-ID 186.11.5 octets
+ATTRIBUTE FreeRADIUS-EAP-FAST-PAC-A-ID-Info 186.11.7 octets
+ATTRIBUTE FreeRADIUS-EAP-FAST-PAC-Acknowledge 186.11.8 short
+ATTRIBUTE FreeRADIUS-EAP-FAST-PAC-Info-TLV 186.11.9 tlv
+ATTRIBUTE FreeRADIUS-EAP-FAST-PAC-Info-PAC-Lifetime 186.11.9.3 integer
+ATTRIBUTE FreeRADIUS-EAP-FAST-PAC-Info-A-ID 186.11.9.4 octets
+ATTRIBUTE FreeRADIUS-EAP-FAST-PAC-Info-I-ID 186.11.9.5 octets
+ATTRIBUTE FreeRADIUS-EAP-FAST-PAC-Info-A-ID-Info 186.11.9.7 octets
+ATTRIBUTE FreeRADIUS-EAP-FAST-PAC-Info-PAC-Type 186.11.9.10 short
+
+ATTRIBUTE FreeRADIUS-EAP-FAST-PAC-Type 186.11.10 short
+
+ATTRIBUTE FreeRADIUS-EAP-FAST-Crypto-Binding 186.12 octets
+
+ATTRIBUTE FreeRADIUS-EAP-FAST-Trusted-Root 186.18 octets
+ATTRIBUTE FreeRADIUS-EAP-FAST-Request-Action 186.19 short
+ATTRIBUTE FreeRADIUS-EAP-FAST-PKCS 186.20 octets
+
+ATTRIBUTE FreeRADIUS-Stats-Error 187 string
+
+ATTRIBUTE FreeRADIUS-Stats-Client-IPv6-Address 188 ipv6addr
+ATTRIBUTE FreeRADIUS-Stats-Server-IPv6-Address 189 ipv6addr
+
+# 190 is reserved
+
+ATTRIBUTE FreeRADIUS-Total-Auth-Conflicts 191 integer
+ATTRIBUTE FreeRADIUS-Total-Acct-Conflicts 192 integer
+
+#
+# Worker thread activity
+#
+ATTRIBUTE FreeRADIUS-Stats-Threads-Active 193 integer
+ATTRIBUTE FreeRADIUS-Stats-Threads-Total 194 integer
+ATTRIBUTE FreeRADIUS-Stats-Threads-Max 195 integer
+
+END-VENDOR FreeRADIUS
diff --git a/share/dictionary.freeradius.evs5 b/share/dictionary.freeradius.evs5
new file mode 100644
index 0000000..0f96158
--- /dev/null
+++ b/share/dictionary.freeradius.evs5
@@ -0,0 +1,22 @@
+# -*- text -*-
+# Copyright (C) 2022 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# The FreeRADIUS Extended-Vendor-Specific-5 dictionary.
+#
+# Version: $Id$
+#
+
+BEGIN-VENDOR FreeRADIUS format=Extended-Vendor-Specific-5
+
+#
+# The next two attributes are for sending EAPoL keys to a RADIUS server.
+#
+# See:
+#
+# https://w1.fi/cgit/hostap/commit/?id=b94371af8402f60218716552e571ca72cff4e3c0
+#
+ATTRIBUTE FreeRADIUS-802.1X-Anonce 1 octets # really 32 octets
+ATTRIBUTE FreeRADIUS-802.1X-EAPoL-Key-Msg 2 octets
+
+END-VENDOR FreeRADIUS
diff --git a/share/dictionary.freeradius.internal b/share/dictionary.freeradius.internal
new file mode 100644
index 0000000..bc6008c
--- /dev/null
+++ b/share/dictionary.freeradius.internal
@@ -0,0 +1,890 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Non Protocol Attributes used by FreeRADIUS
+#
+# $Id$
+#
+
+# The attributes number ranges are allocates as follows:
+#
+# Range: 500-999
+# server-side attributes which can go in a reply list
+
+# These attributes CAN go in the reply item list.
+ATTRIBUTE Fall-Through 500 integer
+ATTRIBUTE Relax-Filter 501 integer
+ATTRIBUTE Exec-Program 502 string
+ATTRIBUTE Exec-Program-Wait 503 string
+
+# These attributes CANNOT go in the reply item list.
+
+#
+# Range: 1000+
+# Attributes which cannot go in a reply list.
+#
+#
+# Range: 1000-1199
+# Miscellaneous server attributes.
+#
+#
+# Non-Protocol Attributes
+# These attributes are used internally by the server
+#
+ATTRIBUTE Auth-Type 1000 integer
+ATTRIBUTE Menu 1001 string
+ATTRIBUTE Termination-Menu 1002 string
+ATTRIBUTE Prefix 1003 string
+ATTRIBUTE Suffix 1004 string
+ATTRIBUTE Group 1005 string
+ATTRIBUTE Crypt-Password 1006 string
+#ATTRIBUTE Connect-Rate 1007 integer
+ATTRIBUTE Add-Prefix 1008 string
+ATTRIBUTE Add-Suffix 1009 string
+ATTRIBUTE Expiration 1010 date
+ATTRIBUTE Autz-Type 1011 integer
+ATTRIBUTE Acct-Type 1012 integer
+ATTRIBUTE Session-Type 1013 integer
+ATTRIBUTE Post-Auth-Type 1014 integer
+ATTRIBUTE Pre-Proxy-Type 1015 integer
+ATTRIBUTE Post-Proxy-Type 1016 integer
+ATTRIBUTE Pre-Acct-Type 1017 integer
+
+#
+# This is the EAP type of authentication, which is set
+# by the EAP module, for informational purposes only.
+#
+ATTRIBUTE EAP-Type 1018 integer
+ATTRIBUTE EAP-TLS-Require-Client-Cert 1019 integer
+ATTRIBUTE EAP-Id 1020 integer
+ATTRIBUTE EAP-Code 1021 integer
+ATTRIBUTE EAP-MD5-Password 1022 string
+ATTRIBUTE PEAP-Version 1023 integer
+ATTRIBUTE Client-Shortname 1024 string virtual
+ATTRIBUTE Load-Balance-Key 1025 string
+ATTRIBUTE Raw-Attribute 1026 octets
+ATTRIBUTE TNC-VLAN-Access 1027 string
+ATTRIBUTE TNC-VLAN-Isolate 1028 string
+ATTRIBUTE User-Category 1029 string
+ATTRIBUTE Group-Name 1030 string
+ATTRIBUTE Huntgroup-Name 1031 string
+ATTRIBUTE Simultaneous-Use 1034 integer
+ATTRIBUTE Strip-User-Name 1035 integer
+ATTRIBUTE Hint 1040 string
+ATTRIBUTE Pam-Auth 1041 string
+ATTRIBUTE Login-Time 1042 string
+ATTRIBUTE Stripped-User-Name 1043 string
+ATTRIBUTE Current-Time 1044 string
+ATTRIBUTE Realm 1045 string
+ATTRIBUTE No-Such-Attribute 1046 string
+ATTRIBUTE Packet-Type 1047 integer virtual
+ATTRIBUTE Proxy-To-Realm 1048 string
+ATTRIBUTE Replicate-To-Realm 1049 string
+ATTRIBUTE Acct-Session-Start-Time 1050 date
+ATTRIBUTE Acct-Unique-Session-Id 1051 string
+ATTRIBUTE Client-IP-Address 1052 ipaddr virtual
+ATTRIBUTE LDAP-UserDN 1053 string
+ATTRIBUTE NS-MTA-MD5-Password 1054 string
+ATTRIBUTE SQL-User-Name 1055 string
+ATTRIBUTE LM-Password 1057 octets
+ATTRIBUTE NT-Password 1058 octets
+ATTRIBUTE SMB-Account-CTRL 1059 integer
+ATTRIBUTE SMB-Account-CTRL-TEXT 1061 string
+ATTRIBUTE User-Profile 1062 string
+ATTRIBUTE Digest-Realm 1063 string
+ATTRIBUTE Digest-Nonce 1064 string
+ATTRIBUTE Digest-Method 1065 string
+ATTRIBUTE Digest-URI 1066 string
+ATTRIBUTE Digest-QOP 1067 string
+ATTRIBUTE Digest-Algorithm 1068 string
+ATTRIBUTE Digest-Body-Digest 1069 string
+ATTRIBUTE Digest-CNonce 1070 string
+ATTRIBUTE Digest-Nonce-Count 1071 string
+ATTRIBUTE Digest-User-Name 1072 string
+ATTRIBUTE Pool-Name 1073 string
+# LDAP-Group is now dynamically created
+ATTRIBUTE Module-Success-Message 1075 string
+ATTRIBUTE Module-Failure-Message 1076 string
+# X99-Fast 1077 integer
+ATTRIBUTE Rewrite-Rule 1078 string
+# SQL-Group is now dynamically created
+ATTRIBUTE Response-Packet-Type 1080 integer virtual
+ATTRIBUTE Digest-HA1 1081 string
+ATTRIBUTE MS-CHAP-Use-NTLM-Auth 1082 integer
+ATTRIBUTE NTLM-User-Name 1083 string
+ATTRIBUTE MS-CHAP-User-Name 1083 string
+ATTRIBUTE Packet-Src-IP-Address 1084 ipaddr virtual
+ATTRIBUTE Packet-Dst-IP-Address 1085 ipaddr virtual
+ATTRIBUTE Packet-Src-Port 1086 integer virtual
+ATTRIBUTE Packet-Dst-Port 1087 integer virtual
+ATTRIBUTE Packet-Authentication-Vector 1088 octets virtual
+ATTRIBUTE Time-Of-Day 1089 string
+ATTRIBUTE Request-Processing-Stage 1090 string virtual
+ATTRIBUTE SHA2-Password 1092 octets
+ATTRIBUTE SHA-Password 1093 octets
+ATTRIBUTE SSHA-Password 1094 octets
+ATTRIBUTE SHA1-Password 1093 octets
+ATTRIBUTE SSHA1-Password 1094 octets
+ATTRIBUTE MD5-Password 1095 octets
+ATTRIBUTE SMD5-Password 1096 octets
+ATTRIBUTE Packet-Src-IPv6-Address 1097 ipv6addr virtual
+ATTRIBUTE Packet-Dst-IPv6-Address 1098 ipv6addr virtual
+ATTRIBUTE Virtual-Server 1099 string virtual
+ATTRIBUTE Cleartext-Password 1100 string
+ATTRIBUTE Password-With-Header 1101 string
+ATTRIBUTE Inner-Tunnel-User-Name 1102 string
+#
+# EAP-IKEv2 is experimental.
+#
+ATTRIBUTE EAP-IKEv2-IDType 1103 integer
+
+VALUE EAP-IKEv2-IDType IPV4_ADDR 1
+VALUE EAP-IKEv2-IDType FQDN 2
+VALUE EAP-IKEv2-IDType RFC822_ADDR 3
+VALUE EAP-IKEv2-IDType IPV6_ADDR 5
+VALUE EAP-IKEv2-IDType DER_ASN1_DN 9
+VALUE EAP-IKEv2-IDType DER_ASN1_GN 10
+VALUE EAP-IKEv2-IDType KEY_ID 11
+
+ATTRIBUTE EAP-IKEv2-ID 1104 string
+ATTRIBUTE EAP-IKEv2-Secret 1105 string secret
+ATTRIBUTE EAP-IKEv2-AuthType 1106 integer
+
+VALUE EAP-IKEv2-AuthType none 0
+VALUE EAP-IKEv2-AuthType secret 1
+VALUE EAP-IKEv2-AuthType cert 2
+VALUE EAP-IKEv2-AuthType both 3
+
+ATTRIBUTE Send-Disconnect-Request 1107 integer
+ATTRIBUTE Send-CoA-Request 1107 integer
+
+VALUE Send-CoA-Request No 0
+VALUE Send-CoA-Request Yes 1
+
+ATTRIBUTE Module-Return-Code 1108 integer virtual
+
+VALUE Module-Return-Code reject 0
+VALUE Module-Return-Code fail 1
+VALUE Module-Return-Code ok 2
+VALUE Module-Return-Code handled 3
+VALUE Module-Return-Code invalid 4
+VALUE Module-Return-Code userlock 5
+VALUE Module-Return-Code notfound 6
+VALUE Module-Return-Code noop 7
+VALUE Module-Return-Code updated 8
+
+ATTRIBUTE Packet-Original-Timestamp 1109 date
+ATTRIBUTE SQL-Table-Name 1110 string
+ATTRIBUTE Home-Server-Pool 1111 string
+
+# For delayed evaluation of maps
+ATTRIBUTE Attribute-Map 1112 string
+
+# See sites-available/coa-relay
+ATTRIBUTE CoA-Packet-Type 1113 string
+ATTRIBUTE CoA-Packet-DST-IP-Address 1114 ipaddr
+ATTRIBUTE CoA-Packet-DST-Port 1115 integer
+ATTRIBUTE CoA-Acct-Session-Id 1116 string
+ATTRIBUTE CoA-Packet-DST-IPv6-Address 1117 ipv6addr
+
+ATTRIBUTE FreeRADIUS-Client-IP-Address 1120 ipaddr
+ATTRIBUTE FreeRADIUS-Client-IPv6-Address 1121 ipv6addr
+# The rest of the FreeRADIUS-Client-* attributes are at 1150...
+
+ATTRIBUTE FreeRADIUS-Client-Require-MA 1122 integer
+
+VALUE FreeRADIUS-Client-Require-MA no 0
+VALUE FreeRADIUS-Client-Require-MA yes 1
+
+ATTRIBUTE FreeRADIUS-Client-Secret 1123 string secret
+ATTRIBUTE FreeRADIUS-Client-Shortname 1124 string
+ATTRIBUTE FreeRADIUS-Client-NAS-Type 1125 string
+ATTRIBUTE FreeRADIUS-Client-Virtual-Server 1126 string
+
+# For session resumption
+ATTRIBUTE Allow-Session-Resumption 1127 integer
+
+VALUE Allow-Session-Resumption no 0
+VALUE Allow-Session-Resumption yes 1
+
+ATTRIBUTE EAP-Session-Resumed 1128 integer
+
+VALUE EAP-Session-Resumed no 0
+VALUE EAP-Session-Resumed yes 1
+
+#
+# Expose EAP keys in the reply.
+#
+ATTRIBUTE EAP-MSK 1129 octets
+ATTRIBUTE EAP-EMSK 1130 octets
+
+#
+# For send/recv CoA packets (like Auth-Type, Acct-Type, etc.)
+#
+ATTRIBUTE Recv-CoA-Type 1131 integer
+ATTRIBUTE Send-CoA-Type 1132 integer
+
+ATTRIBUTE MS-CHAP-Password 1133 string
+ATTRIBUTE Packet-Transmit-Counter 1134 integer
+ATTRIBUTE Cached-Session-Policy 1135 string
+ATTRIBUTE MS-CHAP-New-Cleartext-Password 1136 string
+ATTRIBUTE MS-CHAP-New-NT-Password 1137 octets
+
+# For default policies
+
+ATTRIBUTE Stripped-User-Domain 1138 string
+ATTRIBUTE Called-Station-SSID 1139 string
+
+ATTRIBUTE OTP-Challenge 1145 string
+ATTRIBUTE EAP-Session-Id 1146 octets
+ATTRIBUTE Chbind-Response-Code 1147 integer
+
+VALUE Chbind-Response-Code success 2
+VALUE Chbind-Response-Code failure 3
+
+ATTRIBUTE Acct-Input-Octets64 1148 integer64
+ATTRIBUTE Acct-Output-Octets64 1149 integer64
+
+ATTRIBUTE FreeRADIUS-Client-IP-Prefix 1150 ipv4prefix
+ATTRIBUTE FreeRADIUS-Client-IPv6-Prefix 1151 ipv6prefix
+ATTRIBUTE FreeRADIUS-Response-Delay 1152 integer
+ATTRIBUTE FreeRADIUS-Client-Src-IP-Address 1153 ipaddr
+ATTRIBUTE FreeRADIUS-Client-Src-IPv6-Address 1154 ipv6addr
+ATTRIBUTE FreeRADIUS-Response-Delay-USec 1155 integer
+
+ATTRIBUTE REST-HTTP-Header 1160 string
+ATTRIBUTE REST-HTTP-Body 1161 string
+ATTRIBUTE REST-HTTP-Status-Code 1162 integer
+
+ATTRIBUTE Cache-Expires 1170 date
+ATTRIBUTE Cache-Created 1171 date
+ATTRIBUTE Cache-TTL 1172 signed
+ATTRIBUTE Cache-Status-Only 1173 integer
+ATTRIBUTE Cache-Merge 1174 integer
+ATTRIBUTE Cache-Entry-Hits 1175 integer
+ATTRIBUTE Cache-Read-Only 1176 integer
+
+VALUE Cache-Status-Only no 0
+VALUE Cache-Status-Only yes 1
+
+VALUE Cache-Merge no 0
+VALUE Cache-Merge yes 1
+
+VALUE Cache-Read-Only no 0
+VALUE Cache-Read-Only yes 1
+
+ATTRIBUTE SSHA2-224-Password 1177 octets
+ATTRIBUTE SSHA2-256-Password 1178 octets
+ATTRIBUTE SSHA2-384-Password 1179 octets
+ATTRIBUTE SSHA2-512-Password 1180 octets
+
+ATTRIBUTE PBKDF2-Password 1181 octets
+ATTRIBUTE SSHA3-224-Password 1182 octets
+ATTRIBUTE SSHA3-256-Password 1183 octets
+ATTRIBUTE SSHA3-384-Password 1184 octets
+ATTRIBUTE SSHA3-512-Password 1185 octets
+
+ATTRIBUTE MS-CHAP-Peer-Challenge 1192 octets
+ATTRIBUTE Home-Server-Name 1193 string
+ATTRIBUTE Originating-Realm-Key 1194 string
+ATTRIBUTE Proxy-To-Originating-Realm 1195 string
+
+ATTRIBUTE TOTP-Secret 1194 string # base32 encoded
+ATTRIBUTE TOTP-Key 1195 octets # raw key
+ATTRIBUTE TOTP-Password 1196 string
+
+ATTRIBUTE Proxy-Tunneled-Request-As-EAP 1197 integer
+VALUE Proxy-Tunneled-Request-As-EAP No 0
+VALUE Proxy-Tunneled-Request-As-EAP Yes 1
+ATTRIBUTE Temp-Home-Server-String 1198 string
+
+#
+# Range: 1200-1279
+# EAP-SIM (and other EAP type) weirdness.
+#
+# For EAP-SIM, some attribute definitions for database interface
+#
+ATTRIBUTE EAP-Sim-Subtype 1200 integer
+
+ATTRIBUTE EAP-Sim-Rand1 1201 octets
+ATTRIBUTE EAP-Sim-Rand2 1202 octets
+ATTRIBUTE EAP-Sim-Rand3 1203 octets
+
+ATTRIBUTE EAP-Sim-SRES1 1204 octets
+ATTRIBUTE EAP-Sim-SRES2 1205 octets
+ATTRIBUTE EAP-Sim-SRES3 1206 octets
+
+VALUE EAP-Sim-Subtype Start 10
+VALUE EAP-Sim-Subtype Challenge 11
+VALUE EAP-Sim-Subtype Notification 12
+VALUE EAP-Sim-Subtype Re-authentication 13
+
+# this attribute is used internally by the client code.
+ATTRIBUTE EAP-Sim-State 1207 integer
+
+ATTRIBUTE EAP-Sim-IMSI 1208 string
+ATTRIBUTE EAP-Sim-HMAC 1209 string
+ATTRIBUTE EAP-Sim-KEY 1210 octets
+ATTRIBUTE EAP-Sim-EXTRA 1211 octets
+
+ATTRIBUTE EAP-Sim-KC1 1212 octets
+ATTRIBUTE EAP-Sim-KC2 1213 octets
+ATTRIBUTE EAP-Sim-KC3 1214 octets
+
+ATTRIBUTE EAP-Sim-Ki 1215 octets
+ATTRIBUTE EAP-Sim-Algo-Version 1216 integer
+
+ATTRIBUTE Outer-Realm-Name 1218 string
+ATTRIBUTE Inner-Realm-Name 1219 string
+
+ATTRIBUTE EAP-Pwd-Password-Hash 1220 octets
+ATTRIBUTE EAP-Pwd-Password-Salt 1221 octets
+ATTRIBUTE EAP-Pwd-Password-Prep 1222 byte
+
+#
+# Range: 1280 - 1535
+# EAP-type specific attributes
+#
+# These are used mostly for radeapclient, and aren't
+# that useful for anyone else.
+#
+# egrep VALUE dictionary.freeradius.internal | grep EAP-Type | awk '{print "ATTRIBUTE EAP-Type-" $3 " " 1280+$4 " octets"}' > foo;./format.pl foo
+#
+ATTRIBUTE EAP-Type-Base 1280 octets
+ATTRIBUTE EAP-Type-VALUE 1280 octets
+ATTRIBUTE EAP-Type-None 1280 octets
+ATTRIBUTE EAP-Type-Identity 1281 octets
+ATTRIBUTE EAP-Type-Notification 1282 octets
+ATTRIBUTE EAP-Type-NAK 1283 octets
+ATTRIBUTE EAP-Type-MD5-Challenge 1284 octets
+ATTRIBUTE EAP-Type-One-Time-Password 1285 octets
+ATTRIBUTE EAP-Type-Generic-Token-Card 1286 octets
+ATTRIBUTE EAP-Type-RSA-Public-Key 1289 octets
+ATTRIBUTE EAP-Type-DSS-Unilateral 1290 octets
+ATTRIBUTE EAP-Type-KEA 1291 octets
+ATTRIBUTE EAP-Type-KEA-Validate 1292 octets
+ATTRIBUTE EAP-Type-EAP-TLS 1293 octets
+ATTRIBUTE EAP-Type-Defender-Token 1294 octets
+ATTRIBUTE EAP-Type-RSA-SecurID-EAP 1295 octets
+ATTRIBUTE EAP-Type-Arcot-Systems-EAP 1296 octets
+ATTRIBUTE EAP-Type-Cisco-LEAP 1297 octets
+ATTRIBUTE EAP-Type-Nokia-IP-Smart-Card 1298 octets
+ATTRIBUTE EAP-Type-SIM 1298 octets
+ATTRIBUTE EAP-Type-SRP-SHA1 1299 octets
+ATTRIBUTE EAP-Type-EAP-TTLS 1301 octets
+ATTRIBUTE EAP-Type-Remote-Access-Service 1302 octets
+ATTRIBUTE EAP-Type-AKA 1303 octets
+ATTRIBUTE EAP-Type-EAP-3Com-Wireless 1304 octets
+ATTRIBUTE EAP-Type-PEAP 1305 octets
+ATTRIBUTE EAP-Type-MS-EAP-Authentication 1306 octets
+ATTRIBUTE EAP-Type-MAKE 1307 octets
+ATTRIBUTE EAP-Type-CRYPTOCard 1308 octets
+ATTRIBUTE EAP-Type-EAP-MSCHAP-V2 1309 octets
+ATTRIBUTE EAP-Type-DynamID 1310 octets
+ATTRIBUTE EAP-Type-Rob-EAP 1311 octets
+ATTRIBUTE EAP-Type-SecurID-EAP 1312 octets
+ATTRIBUTE EAP-Type-MS-Authentication-TLV 1313 octets
+ATTRIBUTE EAP-Type-SentriNET 1314 octets
+ATTRIBUTE EAP-Type-EAP-Actiontec-Wireless 1315 octets
+ATTRIBUTE EAP-Type-Cogent-Biomentric-EAP 1316 octets
+ATTRIBUTE EAP-Type-AirFortress-EAP 1317 octets
+ATTRIBUTE EAP-Type-EAP-HTTP-Digest 1318 octets
+ATTRIBUTE EAP-Type-SecuriSuite-EAP 1319 octets
+ATTRIBUTE EAP-Type-DeviceConnect-EAP 1320 octets
+ATTRIBUTE EAP-Type-EAP-SPEKE 1321 octets
+ATTRIBUTE EAP-Type-EAP-MOBAC 1322 octets
+ATTRIBUTE EAP-Type-EAP-FAST 1323 octets
+ATTRIBUTE EAP-Type-Zonelabs 1324 octets
+ATTRIBUTE EAP-Type-EAP-Link 1325 octets
+ATTRIBUTE EAP-Type-EAP-PAX 1326 octets
+ATTRIBUTE EAP-Type-EAP-PSK 1327 octets
+ATTRIBUTE EAP-Type-EAP-SAKE 1328 octets
+ATTRIBUTE EAP-Type-EAP-IKEv2 1329 octets
+ATTRIBUTE EAP-Type-EAP-AKA2 1330 octets
+ATTRIBUTE EAP-Type-EAP-GPSK 1331 octets
+ATTRIBUTE EAP-Type-EAP-PWD 1332 octets
+ATTRIBUTE EAP-Type-EAP-EVEv1 1333 octets
+
+ATTRIBUTE EAP-Type-Microsoft-MS-CHAPv2 1306 octets
+ATTRIBUTE EAP-Type-Cisco-MS-CHAPv2 1309 octets
+ATTRIBUTE EAP-Type-MS-CHAP-V2 1306 octets
+
+#
+# Range: 1536 - 1791
+# EAP Sim sub-types.
+#
+
+# these are PW_EAP_SIM_X + 1536
+ATTRIBUTE EAP_Sim-Base 1536 octets
+ATTRIBUTE EAP-Sim-RAND 1537 octets
+ATTRIBUTE EAP-Sim-PADDING 1542 octets
+ATTRIBUTE EAP-Sim-NONCE_MT 1543 octets
+ATTRIBUTE EAP-Sim-PERMANENT_ID_REQ 1546 octets
+ATTRIBUTE EAP-Sim-MAC 1547 octets
+ATTRIBUTE EAP-Sim-NOTIFICATION 1548 octets
+ATTRIBUTE EAP-Sim-ANY_ID_REQ 1549 octets
+ATTRIBUTE EAP-Sim-IDENTITY 1550 octets
+ATTRIBUTE EAP-Sim-VERSION_LIST 1551 octets
+ATTRIBUTE EAP-Sim-SELECTED_VERSION 1552 octets
+ATTRIBUTE EAP-Sim-FULLAUTH_ID_REQ 1553 octets
+ATTRIBUTE EAP-Sim-COUNTER 1555 octets
+ATTRIBUTE EAP-Sim-COUNTER_TOO_SMALL 1556 octets
+ATTRIBUTE EAP-Sim-NONCE_S 1557 octets
+ATTRIBUTE EAP-Sim-IV 1665 octets
+ATTRIBUTE EAP-Sim-ENCR_DATA 1666 octets
+ATTRIBUTE EAP-Sim-NEXT_PSEUDONUM 1668 octets
+ATTRIBUTE EAP-Sim-NEXT_REAUTH_ID 1669 octets
+ATTRIBUTE EAP-Sim-CHECKCODE 1670 octets
+
+#
+# Range: 1800-1899
+# Temporary attributes, for local storage.
+#
+ATTRIBUTE Tmp-String-0 1800 string
+ATTRIBUTE Tmp-String-1 1801 string
+ATTRIBUTE Tmp-String-2 1802 string
+ATTRIBUTE Tmp-String-3 1803 string
+ATTRIBUTE Tmp-String-4 1804 string
+ATTRIBUTE Tmp-String-5 1805 string
+ATTRIBUTE Tmp-String-6 1806 string
+ATTRIBUTE Tmp-String-7 1807 string
+ATTRIBUTE Tmp-String-8 1808 string
+ATTRIBUTE Tmp-String-9 1809 string
+
+ATTRIBUTE Tmp-Integer-0 1810 integer
+ATTRIBUTE Tmp-Integer-1 1811 integer
+ATTRIBUTE Tmp-Integer-2 1812 integer
+ATTRIBUTE Tmp-Integer-3 1813 integer
+ATTRIBUTE Tmp-Integer-4 1814 integer
+ATTRIBUTE Tmp-Integer-5 1815 integer
+ATTRIBUTE Tmp-Integer-6 1816 integer
+ATTRIBUTE Tmp-Integer-7 1817 integer
+ATTRIBUTE Tmp-Integer-8 1818 integer
+ATTRIBUTE Tmp-Integer-9 1819 integer
+
+ATTRIBUTE Tmp-IP-Address-0 1820 ipaddr
+ATTRIBUTE Tmp-IP-Address-1 1821 ipaddr
+ATTRIBUTE Tmp-IP-Address-2 1822 ipaddr
+ATTRIBUTE Tmp-IP-Address-3 1823 ipaddr
+ATTRIBUTE Tmp-IP-Address-4 1824 ipaddr
+ATTRIBUTE Tmp-IP-Address-5 1825 ipaddr
+ATTRIBUTE Tmp-IP-Address-6 1826 ipaddr
+ATTRIBUTE Tmp-IP-Address-7 1827 ipaddr
+ATTRIBUTE Tmp-IP-Address-8 1828 ipaddr
+ATTRIBUTE Tmp-IP-Address-9 1829 ipaddr
+
+ATTRIBUTE Tmp-Octets-0 1830 octets
+ATTRIBUTE Tmp-Octets-1 1831 octets
+ATTRIBUTE Tmp-Octets-2 1832 octets
+ATTRIBUTE Tmp-Octets-3 1833 octets
+ATTRIBUTE Tmp-Octets-4 1834 octets
+ATTRIBUTE Tmp-Octets-5 1835 octets
+ATTRIBUTE Tmp-Octets-6 1836 octets
+ATTRIBUTE Tmp-Octets-7 1837 octets
+ATTRIBUTE Tmp-Octets-8 1838 octets
+ATTRIBUTE Tmp-Octets-9 1839 octets
+
+ATTRIBUTE Tmp-Date-0 1840 date
+ATTRIBUTE Tmp-Date-1 1841 date
+ATTRIBUTE Tmp-Date-2 1842 date
+ATTRIBUTE Tmp-Date-3 1843 date
+ATTRIBUTE Tmp-Date-4 1844 date
+ATTRIBUTE Tmp-Date-5 1845 date
+ATTRIBUTE Tmp-Date-6 1846 date
+ATTRIBUTE Tmp-Date-7 1847 date
+ATTRIBUTE Tmp-Date-8 1848 date
+ATTRIBUTE Tmp-Date-9 1849 date
+
+ATTRIBUTE Tmp-Integer64-0 1871 integer64
+ATTRIBUTE Tmp-Integer64-1 1872 integer64
+ATTRIBUTE Tmp-Integer64-2 1873 integer64
+ATTRIBUTE Tmp-Integer64-3 1874 integer64
+ATTRIBUTE Tmp-Integer64-4 1875 integer64
+ATTRIBUTE Tmp-Integer64-5 1876 integer64
+ATTRIBUTE Tmp-Integer64-6 1877 integer64
+ATTRIBUTE Tmp-Integer64-7 1878 integer64
+ATTRIBUTE Tmp-Integer64-8 1879 integer64
+ATTRIBUTE Tmp-Integer64-9 1880 integer64
+#
+# These attributes shouldn't be used anywhere. They are defined here
+# only for casting of values in conditional expressions.
+#
+# The order and number need to be consistent with the typedefs used
+# in the server source.
+#
+ATTRIBUTE Tmp-Cast-String 1851 string
+ATTRIBUTE Tmp-Cast-Integer 1852 integer
+ATTRIBUTE Tmp-Cast-Ipaddr 1853 ipaddr
+ATTRIBUTE Tmp-Cast-Date 1854 date
+ATTRIBUTE Tmp-Cast-Abinary 1855 abinary
+ATTRIBUTE Tmp-Cast-Octets 1856 octets
+ATTRIBUTE Tmp-Cast-Ifid 1857 ifid
+ATTRIBUTE Tmp-Cast-IPv6Addr 1858 ipv6addr
+ATTRIBUTE Tmp-Cast-IPv6Prefix 1859 ipv6prefix
+ATTRIBUTE Tmp-Cast-Byte 1860 byte
+ATTRIBUTE Tmp-Cast-Short 1861 short
+ATTRIBUTE Tmp-Cast-Ethernet 1862 ether
+ATTRIBUTE Tmp-Cast-Signed 1863 signed
+# don't use or define these
+ATTRIBUTE Tmp-Cast-Integer64 1869 integer64
+ATTRIBUTE Tmp-Cast-IPv4Prefix 1870 ipv4prefix
+# don't use or define VSA or MAX
+
+# Range: 1900-1909
+# WiMAX server-side attributes.
+#
+# These are NOT sent in a packet, but are otherwise
+# available for testing and validation. The various
+# things that *are* sent in a packet are derived from
+# these attributes.
+#
+ATTRIBUTE WiMAX-MN-NAI 1900 string
+ATTRIBUTE WiMAX-SIM-Ki 1901 octets
+ATTRIBUTE WiMAX-SIM-OPc 1902 octets
+ATTRIBUTE WiMAX-SIM-AMF 1903 octets
+ATTRIBUTE WiMAX-SIM-SQN 1904 octets
+ATTRIBUTE WiMAX-SIM-RAND 1905 octets
+
+ATTRIBUTE TLS-Cert-Serial 1910 string
+ATTRIBUTE TLS-Cert-Expiration 1911 string
+ATTRIBUTE TLS-Cert-Issuer 1912 string
+ATTRIBUTE TLS-Cert-Subject 1913 string
+ATTRIBUTE TLS-Cert-Common-Name 1914 string
+ATTRIBUTE TLS-Cert-Subject-Alt-Name-Email 1915 string
+ATTRIBUTE TLS-Cert-Subject-Alt-Name-Dns 1916 string
+ATTRIBUTE TLS-Cert-Subject-Alt-Name-Upn 1917 string
+ATTRIBUTE TLS-Cert-Valid-Since 1918 string
+ATTRIBUTE TLS-Session-Information 1919 string
+ATTRIBUTE TLS-Client-Cert-Serial 1920 string
+ATTRIBUTE TLS-Client-Cert-Expiration 1921 string
+ATTRIBUTE TLS-Client-Cert-Issuer 1922 string
+ATTRIBUTE TLS-Client-Cert-Subject 1923 string
+ATTRIBUTE TLS-Client-Cert-Common-Name 1924 string
+ATTRIBUTE TLS-Client-Cert-Filename 1925 string
+ATTRIBUTE TLS-Client-Cert-Subject-Alt-Name-Email 1926 string
+ATTRIBUTE TLS-Client-Cert-X509v3-Extended-Key-Usage 1927 string
+ATTRIBUTE TLS-Client-Cert-X509v3-Subject-Key-Identifier 1928 string
+ATTRIBUTE TLS-Client-Cert-X509v3-Authority-Key-Identifier 1929 string
+ATTRIBUTE TLS-Client-Cert-X509v3-Basic-Constraints 1930 string
+ATTRIBUTE TLS-Client-Cert-Subject-Alt-Name-Dns 1931 string
+ATTRIBUTE TLS-Client-Cert-Subject-Alt-Name-Upn 1932 string
+ATTRIBUTE TLS-PSK-Identity 1933 string
+ATTRIBUTE TLS-Client-Cert-X509v3-Extended-Key-Usage-OID 1936 string
+ATTRIBUTE TLS-Client-Cert-Valid-Since 1937 string
+ATTRIBUTE TLS-Cache-Method 1938 integer
+VALUE TLS-Cache-Method save 1
+VALUE TLS-Cache-Method load 2
+VALUE TLS-Cache-Method clear 3
+VALUE TLS-Cache-Method refresh 4
+
+
+ATTRIBUTE TLS-Client-Cert-X509v3-Certificate-Policies 1939 string
+
+# 1940 - 1959: reserved for TLS session caching, mostly in 4.0
+
+ATTRIBUTE TLS-Session-ID 1940 octets
+ATTRIBUTE TLS-Session-Data 1942 octets
+
+# Set by EAP-TLS code
+ATTRIBUTE TLS-OCSP-Cert-Valid 1943 integer
+VALUE TLS-OCSP-Cert-Valid unknown 3
+VALUE TLS-OCSP-Cert-Valid skipped 2
+VALUE TLS-OCSP-Cert-Valid yes 1
+VALUE TLS-OCSP-Cert-Valid no 0
+
+ATTRIBUTE TLS-Cache-Filename 1946 string
+
+ATTRIBUTE TLS-Session-Version 1947 string
+ATTRIBUTE TLS-Session-Cipher-Suite 1948 string
+
+ATTRIBUTE TLS-Session-Cert-File 1949 string
+ATTRIBUTE TLS-Session-Cert-Private-Key-File 1950 string
+
+ATTRIBUTE TLS-Server-Name-Indication 1951 string
+
+#
+# Range: 1960-2099
+# Free
+#
+# Range: 2100-2199
+# SoH attributes; FIXME: these should really be protocol attributes
+# so that the SoH radius request can be proxied, but from which
+# vendor? Sigh...
+#
+ATTRIBUTE SoH-MS-Machine-OS-vendor 2100 integer
+VALUE SoH-MS-Machine-OS-vendor Microsoft 311
+
+ATTRIBUTE SoH-MS-Machine-OS-version 2101 integer
+ATTRIBUTE SoH-MS-Machine-OS-release 2102 integer
+ATTRIBUTE SoH-MS-Machine-OS-build 2103 integer
+ATTRIBUTE SoH-MS-Machine-SP-version 2104 integer
+ATTRIBUTE SoH-MS-Machine-SP-release 2105 integer
+
+ATTRIBUTE SoH-MS-Machine-Processor 2106 integer
+VALUE SoH-MS-Machine-Processor x86 0
+VALUE SoH-MS-Machine-Processor i64 6
+VALUE SoH-MS-Machine-Processor x86_64 9
+
+ATTRIBUTE SoH-MS-Machine-Name 2107 string
+ATTRIBUTE SoH-MS-Correlation-Id 2108 octets
+ATTRIBUTE SoH-MS-Machine-Role 2109 integer
+VALUE SoH-MS-Machine-Role client 1
+VALUE SoH-MS-Machine-Role dc 2
+VALUE SoH-MS-Machine-Role server 3
+
+ATTRIBUTE SoH-Supported 2119 integer
+VALUE SoH-Supported no 0
+VALUE SoH-Supported yes 1
+
+ATTRIBUTE SoH-MS-Windows-Health-Status 2120 string
+ATTRIBUTE SoH-MS-Health-Other 2129 string
+
+#
+# Range: 2200-2219
+# Utilities bundled with the server
+#
+ATTRIBUTE Radclient-Test-Name 2200 string
+
+#
+# Range: 2220-2999
+# Free
+#
+# Range: 3000-3999
+# Site-local attributes (see raddb/dictionary.in)
+# Do NOT define attributes in this range!
+#
+# Range: 4000-65535
+# Unused
+#
+# Range: 65536-
+# Invalid. Don't use.
+#
+
+#
+# Non-Protocol Integer Translations
+#
+
+VALUE Auth-Type Local 1
+VALUE Auth-Type Reject 4
+
+#
+# FreeRADIUS extensions (most originally from Cistron)
+#
+VALUE Auth-Type Accept 254
+
+#
+# Authorization type, too.
+#
+VALUE Autz-Type Local 1
+
+#
+# And accounting
+#
+VALUE Acct-Type Local 1
+
+#
+# And Session handling
+#
+VALUE Session-Type Local 1
+
+#
+# And Post-Auth
+VALUE Post-Auth-Type Local 1
+VALUE Post-Auth-Type Reject 2
+VALUE Post-Auth-Type Challenge 3
+VALUE Post-Auth-Type Client-Lost 4
+
+#
+# And Post-Proxy
+VALUE Post-Proxy-Type Fail 1
+VALUE Post-Proxy-Type Fail-Authentication 2
+VALUE Post-Proxy-Type Fail-Accounting 3
+VALUE Post-Proxy-Type Fail-CoA 4
+VALUE Post-Proxy-Type Fail-Disconnect 5
+
+#
+# Experimental Non-Protocol Integer Translations for FreeRADIUS
+#
+VALUE Fall-Through No 0
+VALUE Fall-Through Yes 1
+
+VALUE Relax-Filter No 0
+VALUE Relax-Filter Yes 1
+
+VALUE Strip-User-Name No 0
+VALUE Strip-User-Name Yes 1
+
+VALUE Packet-Type Access-Request 1
+VALUE Packet-Type Access-Accept 2
+VALUE Packet-Type Access-Reject 3
+VALUE Packet-Type Accounting-Request 4
+VALUE Packet-Type Accounting-Response 5
+VALUE Packet-Type Accounting-Status 6
+VALUE Packet-Type Password-Request 7
+VALUE Packet-Type Password-Accept 8
+VALUE Packet-Type Password-Reject 9
+VALUE Packet-Type Accounting-Message 10
+VALUE Packet-Type Access-Challenge 11
+VALUE Packet-Type Status-Server 12
+VALUE Packet-Type Status-Client 13
+
+#
+# The following packet types are described in RFC 2882,
+# but they are NOT part of the RADIUS standard. Instead,
+# they are informational about vendor-specific extensions
+# to the RADIUS standard.
+#
+VALUE Packet-Type Resource-Free-Request 21
+VALUE Packet-Type Resource-Free-Response 22
+VALUE Packet-Type Resource-Query-Request 23
+VALUE Packet-Type Resource-Query-Response 24
+VALUE Packet-Type Alternate-Resource-Reclaim-Request 25
+VALUE Packet-Type NAS-Reboot-Request 26
+VALUE Packet-Type NAS-Reboot-Response 27
+VALUE Packet-Type Next-Passcode 29
+VALUE Packet-Type New-Pin 30
+VALUE Packet-Type Terminate-Session 31
+VALUE Packet-Type Password-Expired 32
+VALUE Packet-Type Event-Request 33
+VALUE Packet-Type Event-Response 34
+
+# RFC 3576 allocates packet types 40-45
+
+VALUE Packet-Type Disconnect-Request 40
+VALUE Packet-Type Disconnect-ACK 41
+VALUE Packet-Type Disconnect-NAK 42
+VALUE Packet-Type CoA-Request 43
+VALUE Packet-Type CoA-ACK 44
+VALUE Packet-Type CoA-NAK 45
+
+VALUE Packet-Type IP-Address-Allocate 50
+VALUE Packet-Type IP-Address-Release 51
+
+VALUE Response-Packet-Type Access-Request 1
+VALUE Response-Packet-Type Access-Accept 2
+VALUE Response-Packet-Type Access-Reject 3
+VALUE Response-Packet-Type Accounting-Request 4
+VALUE Response-Packet-Type Accounting-Response 5
+VALUE Response-Packet-Type Accounting-Status 6
+VALUE Response-Packet-Type Password-Request 7
+VALUE Response-Packet-Type Password-Accept 8
+VALUE Response-Packet-Type Password-Reject 9
+VALUE Response-Packet-Type Accounting-Message 10
+VALUE Response-Packet-Type Access-Challenge 11
+VALUE Response-Packet-Type Status-Server 12
+VALUE Response-Packet-Type Status-Client 13
+
+VALUE Response-Packet-Type Disconnect-Request 40
+VALUE Response-Packet-Type Disconnect-ACK 41
+VALUE Response-Packet-Type Disconnect-NAK 42
+VALUE Response-Packet-Type CoA-Request 43
+VALUE Response-Packet-Type CoA-ACK 44
+VALUE Response-Packet-Type CoA-NAK 45
+#
+# Special value
+#
+VALUE Response-Packet-Type Do-Not-Respond 256
+
+#
+# EAP Sub-types, inside of Request and Response packets
+#
+# http://www.iana.org/assignments/ppp-numbers
+# "PPP EAP REQUEST/RESPONSE TYPES"
+#
+#
+# See dictionary.microsoft, MS-Acct-EAP-Type for similar definitions
+#
+VALUE EAP-Type None 0
+VALUE EAP-Type Identity 1
+VALUE EAP-Type Notification 2
+VALUE EAP-Type NAK 3
+VALUE EAP-Type MD5-Challenge 4
+VALUE EAP-Type EAP-MD5 4
+VALUE EAP-Type MD5 4
+VALUE EAP-Type One-Time-Password 5
+VALUE EAP-Type OTP 5
+VALUE EAP-Type Generic-Token-Card 6
+VALUE EAP-Type EAP-GTC 6
+VALUE EAP-Type GTC 6
+VALUE EAP-Type RSA-Public-Key 9
+VALUE EAP-Type DSS-Unilateral 10
+VALUE EAP-Type KEA 11
+VALUE EAP-Type KEA-Validate 12
+VALUE EAP-Type EAP-TLS 13
+VALUE EAP-Type TLS 13
+VALUE EAP-Type Defender-Token 14
+VALUE EAP-Type RSA-SecurID-EAP 15
+VALUE EAP-Type Arcot-Systems-EAP 16
+VALUE EAP-Type Cisco-LEAP 17
+VALUE EAP-Type LEAP 17
+VALUE EAP-Type Nokia-IP-Smart-Card 18
+VALUE EAP-Type EAP-SIM 18
+VALUE EAP-Type SIM 18
+VALUE EAP-Type SRP-SHA1 19
+# 20 is unassigned
+VALUE EAP-Type EAP-TTLS 21
+VALUE EAP-Type TTLS 21
+VALUE EAP-Type Remote-Access-Service 22
+VALUE EAP-Type EAP-AKA 23
+VALUE EAP-Type AKA 23
+VALUE EAP-Type 3Com-Wireless 24
+VALUE EAP-Type PEAP 25
+VALUE EAP-Type Microsoft-MS-CHAPv2 26
+VALUE EAP-Type MAKE 27
+VALUE EAP-Type CRYPTOCard 28
+VALUE EAP-Type Cisco-MS-CHAPv2 29
+VALUE EAP-Type DynamID 30
+VALUE EAP-Type Rob-EAP 31
+VALUE EAP-Type SecurID-EAP 32
+VALUE EAP-Type MS-Authentication-TLV 33
+VALUE EAP-Type SentriNET 34
+VALUE EAP-Type Actiontec-Wireless 35
+VALUE EAP-Type Cogent-Biomentric-EAP 36
+VALUE EAP-Type AirFortress-EAP 37
+VALUE EAP-Type HTTP-Digest 38
+VALUE EAP-Type TNC 38
+VALUE EAP-Type SecuriSuite-EAP 39
+VALUE EAP-Type DeviceConnect-EAP 40
+VALUE EAP-Type SPEKE 41
+VALUE EAP-Type MOBAC 42
+VALUE EAP-Type EAP-FAST 43
+VALUE EAP-Type FAST 43
+VALUE EAP-Type Zonelabs 44
+VALUE EAP-Type Link 45
+VALUE EAP-Type PAX 46
+VALUE EAP-Type PSK 47
+VALUE EAP-Type SAKE 48
+VALUE EAP-Type EAP-IKEv2 49
+VALUE EAP-Type IKEv2 49
+VALUE EAP-Type AKA2 50
+VALUE EAP-Type GPSK 51
+VALUE EAP-Type PWD 52
+VALUE EAP-Type EKEv1 53
+
+#
+# And this is what most people mean by MS-CHAPv2
+#
+VALUE EAP-Type EAP-MSCHAPv2 26
+VALUE EAP-Type MSCHAPv2 26
+
+#
+# This says TLS, but it's only valid for TTLS & PEAP.
+# EAP-TLS *always* requires a client certificate.
+#
+VALUE EAP-TLS-Require-Client-Cert No 0
+VALUE EAP-TLS-Require-Client-Cert Yes 1
+
+#
+# These are the EAP-Code values.
+#
+VALUE EAP-Code Request 1
+VALUE EAP-Code Response 2
+VALUE EAP-Code Success 3
+VALUE EAP-Code Failure 4
+
+#
+# For MS-CHAP, do we run ntlm_auth, or not.
+#
+VALUE MS-CHAP-Use-NTLM-Auth No 0
+VALUE MS-CHAP-Use-NTLM-Auth Yes 1
diff --git a/share/dictionary.freeswitch b/share/dictionary.freeswitch
new file mode 100644
index 0000000..0592e4c
--- /dev/null
+++ b/share/dictionary.freeswitch
@@ -0,0 +1,112 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# cparker@segv.org
+#
+# Version: $Id$
+#
+
+VENDOR Freeswitch 27880
+
+#
+# Standard attribute
+#
+BEGIN-VENDOR Freeswitch
+
+ATTRIBUTE Freeswitch-AVPair 1 string
+ATTRIBUTE Freeswitch-CLID 2 string
+ATTRIBUTE Freeswitch-Dialplan 3 string
+ATTRIBUTE Freeswitch-Src 4 string
+ATTRIBUTE Freeswitch-Dst 5 string
+ATTRIBUTE Freeswitch-Src-Channel 6 string
+ATTRIBUTE Freeswitch-Dst-Channel 7 string
+ATTRIBUTE Freeswitch-Ani 8 string
+ATTRIBUTE Freeswitch-Aniii 9 string
+ATTRIBUTE Freeswitch-Lastapp 10 string
+ATTRIBUTE Freeswitch-Lastdata 11 string
+ATTRIBUTE Freeswitch-Disposition 12 string
+ATTRIBUTE Freeswitch-Hangupcause 13 integer
+ATTRIBUTE Freeswitch-Billusec 15 integer
+ATTRIBUTE Freeswitch-AMAFlags 16 integer
+ATTRIBUTE Freeswitch-RDNIS 17 string
+ATTRIBUTE Freeswitch-Context 18 string
+ATTRIBUTE Freeswitch-Source 19 string
+ATTRIBUTE Freeswitch-Callstartdate 20 string
+ATTRIBUTE Freeswitch-Callanswerdate 21 string
+ATTRIBUTE Freeswitch-Calltransferdate 22 string
+ATTRIBUTE Freeswitch-Callenddate 23 string
+ATTRIBUTE Freeswitch-Signalbond 24 string
+
+#
+# Freeswitch-Hangupcause
+#
+VALUE Freeswitch-Hangupcause None 0
+VALUE Freeswitch-Hangupcause Unallocated-Number 1
+VALUE Freeswitch-Hangupcause No-Route-Transit-Net 2
+VALUE Freeswitch-Hangupcause No-Route-Destination 3
+VALUE Freeswitch-Hangupcause Channel-Unacceptable 6
+VALUE Freeswitch-Hangupcause Call-Awarded-Delivery 7
+VALUE Freeswitch-Hangupcause Normal-Clearing 16
+VALUE Freeswitch-Hangupcause User-Busy 17
+VALUE Freeswitch-Hangupcause No-User-Response 18
+VALUE Freeswitch-Hangupcause No-Answer 19
+VALUE Freeswitch-Hangupcause Subscriber-Absent 20
+VALUE Freeswitch-Hangupcause Call-Rejected 21
+VALUE Freeswitch-Hangupcause Number-Changed 22
+VALUE Freeswitch-Hangupcause Redirecto-To-New-Destination 23
+VALUE Freeswitch-Hangupcause Exchange-Routing-Error 25
+VALUE Freeswitch-Hangupcause Destination-Out-Of-Order 27
+VALUE Freeswitch-Hangupcause Invalid-Number-Format 28
+VALUE Freeswitch-Hangupcause Facility-Rejected 29
+VALUE Freeswitch-Hangupcause Response-To-Status-Enquiry 30
+VALUE Freeswitch-Hangupcause Normal-Unspecified 31
+VALUE Freeswitch-Hangupcause Normal-Circuit-Congestion 34
+VALUE Freeswitch-Hangupcause Network-Out-Of-Order 38
+VALUE Freeswitch-Hangupcause Normal-Temporary-Failure 41
+VALUE Freeswitch-Hangupcause Switch-Congestion 42
+VALUE Freeswitch-Hangupcause Access-Info-Discarded 43
+VALUE Freeswitch-Hangupcause Requested-Chan-Unavail 44
+VALUE Freeswitch-Hangupcause Pre-Empted 45
+VALUE Freeswitch-Hangupcause Facility-Not-Subscribed 50
+VALUE Freeswitch-Hangupcause Outgoing-Call-Barred 52
+VALUE Freeswitch-Hangupcause Incoming-Call-Barred 54
+VALUE Freeswitch-Hangupcause Bearercapability-Notauth 57
+VALUE Freeswitch-Hangupcause Bearercapability-Notavail 58
+VALUE Freeswitch-Hangupcause Service-Unavailable 63
+VALUE Freeswitch-Hangupcause Bearercapability-Notimpl 65
+VALUE Freeswitch-Hangupcause Chan-Not-Implemented 66
+VALUE Freeswitch-Hangupcause Facility-Not-Implemented 69
+VALUE Freeswitch-Hangupcause Service-Not-Implemented 79
+VALUE Freeswitch-Hangupcause Invalid-Call-Reference 81
+VALUE Freeswitch-Hangupcause Incompatible-Destination 88
+VALUE Freeswitch-Hangupcause Invalid-Msg-Unspecified 95
+VALUE Freeswitch-Hangupcause Mandatory-IE-Missing 96
+VALUE Freeswitch-Hangupcause Message-Type-Nonexist 97
+VALUE Freeswitch-Hangupcause Wrong-Message 98
+VALUE Freeswitch-Hangupcause IE-Nonexist 99
+VALUE Freeswitch-Hangupcause Invalid-IE-Contents 100
+VALUE Freeswitch-Hangupcause Wrong-Call-State 101
+VALUE Freeswitch-Hangupcause Recovery-On-Timer-Expire 102
+VALUE Freeswitch-Hangupcause Mandatory-IE-Length-Error 103
+VALUE Freeswitch-Hangupcause Protocol-Error 111
+VALUE Freeswitch-Hangupcause Interworking 127
+VALUE Freeswitch-Hangupcause Success 142
+VALUE Freeswitch-Hangupcause Originator-Cancel 487
+VALUE Freeswitch-Hangupcause Crash 500
+VALUE Freeswitch-Hangupcause System-Shutdown 501
+VALUE Freeswitch-Hangupcause Lose-Race 502
+VALUE Freeswitch-Hangupcause Manager-Request 503
+VALUE Freeswitch-Hangupcause Blind-Transfer 600
+VALUE Freeswitch-Hangupcause Attended-Transfer 601
+VALUE Freeswitch-Hangupcause Allotted-Timeout 602
+VALUE Freeswitch-Hangupcause User-Challenge 603
+VALUE Freeswitch-Hangupcause Media-Timeout 604
+VALUE Freeswitch-Hangupcause Picked-Off 605
+VALUE Freeswitch-Hangupcause User-Not-Registered 606
+
+#
+#
+#
+
+END-VENDOR Freeswitch
diff --git a/share/dictionary.gandalf b/share/dictionary.gandalf
new file mode 100644
index 0000000..2070013
--- /dev/null
+++ b/share/dictionary.gandalf
@@ -0,0 +1,103 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Version: 1.00 24-July-2003 Blaise St-Laurent <bstlaurent@okiok.com>
+#
+# Notes: Dictionary was made specifically for the Gandalf XpressWay
+# RLAN with Link Authentication through RADIUS
+#
+# $Id$
+#
+VENDOR Gandalf 64
+
+BEGIN-VENDOR Gandalf
+
+ATTRIBUTE Gandalf-Remote-LAN-Name 0 string
+ATTRIBUTE Gandalf-Operational-Modes 1 integer
+ATTRIBUTE Gandalf-Compression-Status 2 integer
+ATTRIBUTE Gandalf-Min-Outgoing-Bearer 3 integer
+ATTRIBUTE Gandalf-Authentication-String 5 string
+ATTRIBUTE Gandalf-PPP-Authentication 6 integer
+ATTRIBUTE Gandalf-PPP-NCP-Type 7 integer
+ATTRIBUTE Gandalf-Fwd-Multicast-In 8 integer
+ATTRIBUTE Gandalf-Fwd-Broadcast-In 9 integer
+ATTRIBUTE Gandalf-Fwd-Unicast-In 10 integer
+ATTRIBUTE Gandalf-Fwd-Multicast-Out 11 integer
+ATTRIBUTE Gandalf-Fwd-Broadcast-Out 12 integer
+ATTRIBUTE Gandalf-Fwd-Unicast-Out 13 integer
+ATTRIBUTE Gandalf-Around-The-Corner 14 integer
+ATTRIBUTE Gandalf-Channel-Group-Name-1 15 string
+ATTRIBUTE Gandalf-Dial-Prefix-Name-1 16 string
+ATTRIBUTE Gandalf-Phone-Number-1 17 string
+ATTRIBUTE Gandalf-Calling-Line-ID-1 18 string
+ATTRIBUTE Gandalf-Channel-Group-Name-2 19 string
+ATTRIBUTE Gandalf-Dial-Prefix-Name-2 20 string
+ATTRIBUTE Gandalf-Phone-Number-2 21 string
+ATTRIBUTE Gandalf-Calling-Line-ID-2 22 string
+ATTRIBUTE Gandalf-IPX-Spoofing-State 23 integer
+ATTRIBUTE Gandalf-IPX-Watchdog-Spoof 24 integer
+ATTRIBUTE Gandalf-SAP-Group-Name-1 25 string
+ATTRIBUTE Gandalf-SAP-Group-Name-2 26 string
+ATTRIBUTE Gandalf-SAP-Group-Name-3 27 string
+ATTRIBUTE Gandalf-SAP-Group-Name-4 28 string
+ATTRIBUTE Gandalf-SAP-Group-Name-5 29 string
+ATTRIBUTE Gandalf-Hunt-Group 30 string
+ATTRIBUTE Gandalf-Modem-Mode 31 integer
+ATTRIBUTE Gandalf-Modem-Required-1 32 integer
+ATTRIBUTE Gandalf-Modem-Required-2 33 integer
+
+VALUE Gandalf-Operational-Modes Disabled 1
+VALUE Gandalf-Operational-Modes Called-Only 2
+VALUE Gandalf-Operational-Modes Calling-Called 3
+VALUE Gandalf-Operational-Modes Calling-Only 4
+
+VALUE Gandalf-Compression-Status Disabled 1
+VALUE Gandalf-Compression-Status Enabled 2
+
+VALUE Gandalf-Min-Outgoing-Bearer Unrestricted-64K 1
+VALUE Gandalf-Min-Outgoing-Bearer Digital-56K 2
+VALUE Gandalf-Min-Outgoing-Bearer 3100Hz-Audio 3
+
+VALUE Gandalf-PPP-Authentication CHAP 1
+VALUE Gandalf-PPP-Authentication PAP 2
+VALUE Gandalf-PPP-Authentication PAP-Sending-on-Incoming-Calls 3
+
+VALUE Gandalf-PPP-NCP-Type BCP 2
+VALUE Gandalf-PPP-NCP-Type IPCP 3
+
+VALUE Gandalf-Fwd-Multicast-In Disabled 1
+VALUE Gandalf-Fwd-Multicast-In Enabled 2
+
+VALUE Gandalf-Fwd-Broadcast-In Disabled 1
+VALUE Gandalf-Fwd-Broadcast-In Enabled 2
+
+VALUE Gandalf-Fwd-Unicast-In Disabled 1
+VALUE Gandalf-Fwd-Unicast-In Enabled 2
+
+VALUE Gandalf-Fwd-Multicast-Out Disabled 1
+VALUE Gandalf-Fwd-Multicast-Out Enabled 2
+
+VALUE Gandalf-Fwd-Broadcast-Out Disabled 1
+VALUE Gandalf-Fwd-Broadcast-Out Enabled 2
+
+VALUE Gandalf-Fwd-Unicast-Out Disabled 1
+VALUE Gandalf-Fwd-Unicast-Out Enabled 2
+
+VALUE Gandalf-IPX-Spoofing-State Forward 1
+VALUE Gandalf-IPX-Spoofing-State Spoof 2
+VALUE Gandalf-IPX-Spoofing-State Filter-all-outgoing-RIP-SAP 3
+
+VALUE Gandalf-IPX-Watchdog-Spoof Disabled 1
+VALUE Gandalf-IPX-Watchdog-Spoof Enabled 2
+
+VALUE Gandalf-Modem-Mode Disabled 1
+VALUE Gandalf-Modem-Mode Enabled 2
+
+VALUE Gandalf-Modem-Required-1 Disabled 1
+VALUE Gandalf-Modem-Required-1 Enabled 2
+
+VALUE Gandalf-Modem-Required-2 Disabled 1
+VALUE Gandalf-Modem-Required-2 Enabled 2
+
+END-VENDOR Gandalf
diff --git a/share/dictionary.garderos b/share/dictionary.garderos
new file mode 100644
index 0000000..c401784
--- /dev/null
+++ b/share/dictionary.garderos
@@ -0,0 +1,25 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# dictionary.garderos
+#
+# Version: $Id$
+#
+# For documentation on Garderos attributes, see:
+#
+# http://www.garderos.com
+
+VENDOR Garderos 16108
+
+#
+# Standard attribute
+#
+BEGIN-VENDOR Garderos
+
+ATTRIBUTE Garderos-Location-Name 1 string
+ATTRIBUTE Garderos-Service-Name 2 string
+ATTRIBUTE Garderos-MSISDN 3 string
+ATTRIBUTE Garderos-Proxy 4 string
+
+END-VENDOR Garderos
diff --git a/share/dictionary.gemtek b/share/dictionary.gemtek
new file mode 100644
index 0000000..201d1cb
--- /dev/null
+++ b/share/dictionary.gemtek
@@ -0,0 +1,20 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Gemtek Systems VSA's
+
+VENDOR Gemtek 10529
+
+BEGIN-VENDOR Gemtek
+
+# Attributes for volume accounting limit.
+
+ATTRIBUTE Acct-Session-Input-Octets 21 integer
+ATTRIBUTE Acct-Session-Input-Gigawords 22 integer
+ATTRIBUTE Acct-Session-Output-Octets 23 integer
+ATTRIBUTE Acct-Session-Output-Gigawords 24 integer
+ATTRIBUTE Acct-Session-Octets 25 integer
+ATTRIBUTE Acct-Session-Gigawords 26 integer
+
+END-VENDOR Gemtek
diff --git a/share/dictionary.h3c b/share/dictionary.h3c
new file mode 100644
index 0000000..be9eeee
--- /dev/null
+++ b/share/dictionary.h3c
@@ -0,0 +1,95 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Dictionary for Huawei-3Com. See also dictionary.huawei
+#
+# http://www.h3c.com
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR H3C 25506
+
+BEGIN-VENDOR H3C
+
+ATTRIBUTE H3C-Input-Peak-Rate 1 integer
+ATTRIBUTE H3C-Input-Average-Rate 2 integer
+ATTRIBUTE H3C-Input-Basic-Rate 3 integer
+ATTRIBUTE H3C-Output-Peak-Rate 4 integer
+ATTRIBUTE H3C-Output-Average-Rate 5 integer
+ATTRIBUTE H3C-Output-Basic-Rate 6 integer
+ATTRIBUTE H3C-Remanent-Volume 15 integer
+ATTRIBUTE H3C-ISP-ID 17 string
+ATTRIBUTE H3C-Command 20 integer
+
+VALUE H3C-Command Trigger-Request 1
+VALUE H3C-Command Terminate-Request 2
+VALUE H3C-Command SetPolicy 3
+VALUE H3C-Command Result 4
+VALUE H3C-Command PortalClear 5
+
+ATTRIBUTE H3C-Control-Identifier 24 integer
+ATTRIBUTE H3C-Result-Code 25 integer
+ATTRIBUTE H3C-Connect_Id 26 integer
+ATTRIBUTE H3C-Portal-URL 27 string
+ATTRIBUTE H3C-Ftp-Directory 28 string
+ATTRIBUTE H3C-Exec-Privilege 29 integer
+
+VALUE H3C-Exec-Privilege Visit 0
+VALUE H3C-Exec-Privilege Monitor 1
+VALUE H3C-Exec-Privilege System 2
+VALUE H3C-Exec-Privilege Manage 3
+
+ATTRIBUTE H3C-NAT-IP-Address 32 ipaddr
+ATTRIBUTE H3C-NAT-Start-Port 33 integer
+ATTRIBUTE H3C-NAT-End-Port 34 integer
+ATTRIBUTE H3C-NAS-Startup-Timestamp 59 integer
+ATTRIBUTE H3C-Ip-Host-Addr 60 string
+ATTRIBUTE H3C-User-Notify 61 string
+ATTRIBUTE H3C-User-HeartBeat 62 string
+ATTRIBUTE H3C-IPv4-Multicast-Receive-Group 98 ipaddr
+ATTRIBUTE H3C-IPv6-Multicast-Receive-Group 100 ipv6addr
+ATTRIBUTE H3C-MLD-Access-Limit 101 integer
+ATTRIBUTE H3C-L2TP-Local-Name 102 string
+ATTRIBUTE H3C-IGMP-Access-Limit 103 integer
+ATTRIBUTE H3C-VPN-Instance 104 string
+ATTRIBUTE H3C-ANCP-Profile 105 string
+ATTRIBUTE H3C-Up-Priority 106 integer
+ATTRIBUTE H3C-Down-Priority 107 integer
+ATTRIBUTE H3C-Longitude-Latitude 111 string
+ATTRIBUTE H3C-Client-Primary-DNS 135 ipaddr
+ATTRIBUTE H3C-Client-Secondary-DNS 136 ipaddr
+ATTRIBUTE H3C-User-Group 140 string
+ATTRIBUTE H3C-Security-Level 141 integer
+ATTRIBUTE H3C-Acct-IPv6-Input-Octets 144 integer
+ATTRIBUTE H3C-Acct-IPv6-Output-Octets 145 integer
+ATTRIBUTE H3C-Acct-IPv6-Input-Packets 146 integer
+ATTRIBUTE H3C-Acct-IPv6-Output-Packets 147 integer
+ATTRIBUTE H3C-Acct-IPv6-Input-Gigawords 146 integer
+ATTRIBUTE H3C-Acct-IPv6-Output-Gigawords 147 integer
+ATTRIBUTE H3C-User-Role 155 string
+ATTRIBUTE H3C-Input-Interval-Octets 201 integer
+ATTRIBUTE H3C-Output-Interval-Octets 202 integer
+ATTRIBUTE H3C-Input-Interval-Packets 203 integer
+ATTRIBUTE H3C-Output-Interval-Packets 204 integer
+ATTRIBUTE H3C-Input-Interval-Gigawords 205 integer
+ATTRIBUTE H3C-Output-Interval-Gigawords 206 integer
+ATTRIBUTE H3C-Backup-NAS-IP 207 ipaddr
+ATTRIBUTE H3C-Av-Pair 210 string
+ATTRIBUTE H3C-Accounting-Level 215 integer
+ATTRIBUTE H3C-Ita-Policy 216 string
+ATTRIBUTE H3C-NAS-Port-Name 230 string
+ATTRIBUTE H3C-Auth-Detail-Result 246 integer
+ATTRIBUTE H3C-Input-Committed-Burst-Size 247 integer
+ATTRIBUTE H3C-Output-Committed-Burst-Size 248 integer
+ATTRIBUTE H3C-Authentication-Type 249 integer
+ATTRIBUTE H3C-WEB-URL 250 string
+ATTRIBUTE H3C-Subscriber-ID 251 string
+ATTRIBUTE H3C-Subscriber-Profile 252 string
+ATTRIBUTE H3C-Product-ID 255 string
+
+END-VENDOR H3C
diff --git a/share/dictionary.hillstone b/share/dictionary.hillstone
new file mode 100644
index 0000000..b1cf2e2
--- /dev/null
+++ b/share/dictionary.hillstone
@@ -0,0 +1,51 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# From yqsi@hillstonenet.com 2015/11/2
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR Hillstone 28557
+
+BEGIN-VENDOR Hillstone
+
+ATTRIBUTE Hillstone-User-vsys-id 1 integer
+ATTRIBUTE Hillstone-User-Type 2 integer
+ATTRIBUTE Hillstone-User-Admin-Privilege 3 integer
+ATTRIBUTE Hillstone-User-Login-Type 4 integer
+ATTRIBUTE Hillstone-User-Mobile-Number 5 string
+ATTRIBUTE Hillstone-User-Mobile-Operator 6 integer
+ATTRIBUTE Hillstone-User-Policy-dst-ip-begin 7 ipaddr
+ATTRIBUTE Hillstone-User-Policy-dst-ip-end 8 ipaddr
+ATTRIBUTE Hillstone-User-Role-Bame 9 string
+ATTRIBUTE Hillstone-VPN-DHCP-Gateway 100 string
+ATTRIBUTE Hillstone-VPN-DHCP-Mask 101 string
+ATTRIBUTE Hillstone-VPN-DHCP-Pool 102 string
+ATTRIBUTE Hillstone-VPN-WINS 103 string
+ATTRIBUTE Hillstone-VPN-DNS 104 string
+ATTRIBUTE Hillstone-VPN-Split-Route 105 string
+ATTRIBUTE Hillstone-VPN-Tunnel-IP 106 string
+ATTRIBUTE Hillstone-VPN-SNAT 107 integer
+
+VALUE Hillstone-User-Type HS-User-l2tp 1
+VALUE Hillstone-User-Type HS-User-8021x 2
+VALUE Hillstone-User-Type HS-User-smartvpn 4
+VALUE Hillstone-User-Type HS-User-normal 8
+VALUE Hillstone-User-Type HS-User-Admin 16
+
+VALUE Hillstone-User-Login-Type HS-Admin-Console 1
+VALUE Hillstone-User-Login-Type HS-Admin-Telnet 2
+VALUE Hillstone-User-Login-Type HS-Admin-SSH 4
+VALUE Hillstone-User-Login-Type HS-Admin-HTTP 8
+VALUE Hillstone-User-Login-Type HS-Admin-HTTPS 16
+
+VALUE Hillstone-User-Mobile-Operator HS-Mobile-ChinaMobile 1
+VALUE Hillstone-User-Mobile-Operator HS-Mobile-ChinaUnicom 2
+VALUE Hillstone-User-Mobile-Operator HS-Mobile-ChinaTelecom 3
+
+END-VENDOR Hillstone
diff --git a/share/dictionary.hp b/share/dictionary.hp
new file mode 100644
index 0000000..b4bafec
--- /dev/null
+++ b/share/dictionary.hp
@@ -0,0 +1,103 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# HP ProCurve VSA's
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR HP 11
+
+#
+# Attributes supported by HP ProCurve wired networking devices
+#
+BEGIN-VENDOR HP
+
+# Management authorization
+ATTRIBUTE HP-Privilege-Level 1 integer
+ATTRIBUTE HP-Command-String 2 string
+ATTRIBUTE HP-Command-Exception 3 integer
+
+# Dynamic port-access attributes
+ATTRIBUTE HP-Port-Client-Limit-Dot1x 10 integer
+ATTRIBUTE HP-Port-Client-Limit-MA 11 integer
+ATTRIBUTE HP-Port-Client-Limit-WA 12 integer
+ATTRIBUTE HP-Port-Auth-Mode-Dot1x 13 integer
+ATTRIBUTE HP-Port-MA-Port-Mode 14 integer
+ATTRIBUTE HP-Port-Bounce-Host 23 integer
+ATTRIBUTE HP-Captive-Portal-URL 24 string
+ATTRIBUTE HP-User-Role 25 string
+ATTRIBUTE HP-Management-Protocol 26 integer
+ATTRIBUTE HP-CPPM-Role 27 string
+ATTRIBUTE HP-CPPM-Secondary-Role 28 string
+
+# Client QoS attributes
+ATTRIBUTE HP-Port-Priority-Regeneration-Table 40 string
+
+# Access control
+ATTRIBUTE HP-Cos 40 string
+#ATTRIBUTE HP-Rate-Limit 46 integer
+
+ATTRIBUTE HP-Bandwidth-Max-Ingress 46 integer
+ATTRIBUTE HP-Bandwidth-Max-Egress 48 integer
+
+ATTRIBUTE HP-Ip-Filter-Raw 61 string
+
+# Client ACL attributes
+ATTRIBUTE HP-Nas-Filter-Rule 61 string
+ATTRIBUTE HP-Access-Profile 62 string
+ATTRIBUTE HP-Nas-Rules-IPv6 63 integer
+
+# VLAN assignment attributes
+ATTRIBUTE HP-Egress-VLANID 64 integer
+ATTRIBUTE HP-Egress-VLAN-Name 65 string
+ATTRIBUTE HP-Bonjour-Inbound-Profile 66 string
+ATTRIBUTE HP-Bonjour-Outbound-Profile 67 string
+
+# AAA for REST
+ATTRIBUTE HP-URI-String 80 string
+ATTRIBUTE HP-URI-Json-String 81 string
+ATTRIBUTE HP-URI-Access 82 string
+ATTRIBUTE HP-URI-Exception 83 integer
+
+ATTRIBUTE HP-VC-groups 192 string
+
+# See http://wiki.freeradius.org/vendor/HP#Capability-advertisements
+ATTRIBUTE HP-Capability-Advert 255 octets
+
+# HP-Port-Auth-Mode-Dot1x Attribute Values
+VALUE HP-Port-Auth-Mode-Dot1x Port-Based 1
+VALUE HP-Port-Auth-Mode-Dot1x User-Based 2
+
+# HP-Command-Exception Attribute Values
+VALUE HP-Command-Exception Permit-List 0
+VALUE HP-Command-Exception Deny-List 1
+
+# HP-Management-Protocol
+VALUE HP-Management-Protocol HTTP 5
+VALUE HP-Management-Protocol HTTPS 6
+
+#
+# Conflicting attributes are commented out.
+#
+#ATTRIBUTE HP-Management-Role 26 integer
+
+# HP-Management-Role
+#VALUE HP-Management-Role SuperUser 1
+#VALUE HP-Management-Role Monitor 2
+#VALUE HP-Management-Role HelpDeskManager 16
+#VALUE HP-Management-Role NetworkAdministrator 17
+#VALUE HP-Management-Role SystemAdministrator 18
+#VALUE HP-Management-Role WebUserAdminstrator 19
+
+# Privilege attributes for HP-GbE2c, HP 1:10Gb, and HP 10Gb
+# Ethernet Blade Switches
+#
+VALUE Service-Type HP-Oper 252
+VALUE Service-Type HP-User 255
+
+END-VENDOR HP
diff --git a/share/dictionary.huawei b/share/dictionary.huawei
new file mode 100644
index 0000000..8af0011
--- /dev/null
+++ b/share/dictionary.huawei
@@ -0,0 +1,243 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Dictionary for Huawei. See also dictionary.h3c
+#
+# $Id$
+#
+# https://support.huawei.com/enterprise/en/doc/EDOC1100055480/6a2e56b2/description-of-radius-attributes
+#
+##############################################################################
+
+VENDOR Huawei 2011
+
+BEGIN-VENDOR Huawei
+
+ATTRIBUTE Huawei-Input-Burst-Size 1 integer
+ATTRIBUTE Huawei-Input-Average-Rate 2 integer
+ATTRIBUTE Huawei-Input-Peak-Rate 3 integer
+ATTRIBUTE Huawei-Output-Burst-Size 4 integer
+ATTRIBUTE Huawei-Output-Average-Rate 5 integer
+ATTRIBUTE Huawei-Output-Peak-Rate 6 integer
+ATTRIBUTE Huawei-In-Kb-Before-T-Switch 7 integer
+ATTRIBUTE Huawei-Out-Kb-Before-T-Switch 8 integer
+ATTRIBUTE Huawei-In-Pkt-Before-T-Switch 9 integer
+ATTRIBUTE Huawei-Out-Pkt-Before-T-Switch 10 integer
+ATTRIBUTE Huawei-In-Kb-After-T-Switch 11 integer
+ATTRIBUTE Huawei-Out-Kb-After-T-Switch 12 integer
+ATTRIBUTE Huawei-In-Pkt-After-T-Switch 13 integer
+ATTRIBUTE Huawei-Out-Pkt-After-T-Switch 14 integer
+ATTRIBUTE Huawei-Remanent-Volume 15 integer
+ATTRIBUTE Huawei-Tariff-Switch-Interval 16 integer
+ATTRIBUTE Huawei-ISP-ID 17 string
+ATTRIBUTE Huawei-Max-Users-Per-Logic-Port 18 integer
+ATTRIBUTE Huawei-Command 20 integer
+ATTRIBUTE Huawei-Priority 22 integer
+ATTRIBUTE Huawei-Control-Identifier 24 integer
+
+ATTRIBUTE Huawei-Result-Code 25 integer
+
+# > 0 indicates an error.
+VALUE Huawei-Result-Code Succeeded 0
+
+ATTRIBUTE Huawei-Connect-ID 26 integer
+ATTRIBUTE Huawei-PortalURL 27 string
+ATTRIBUTE Huawei-FTP-Directory 28 string
+ATTRIBUTE Huawei-Exec-Privilege 29 integer
+ATTRIBUTE Huawei-IP-Address 30 integer
+ATTRIBUTE Huawei-Qos-Profile-Name 31 string
+ATTRIBUTE Huawei-SIP-Server 32 string
+ATTRIBUTE Huawei-User-Password 33 string
+ATTRIBUTE Huawei-Command-Mode 34 string
+ATTRIBUTE Huawei-Renewal-Time 35 integer
+ATTRIBUTE Huawei-Rebinding-Time 36 integer
+ATTRIBUTE Huawei-IGMP-Enable 37 integer
+ATTRIBUTE Huawei-Destnation-IP-Addr 39 string
+ATTRIBUTE Huawei-Destnation-Volume 40 string
+ATTRIBUTE Huawei-Startup-Stamp 59 integer
+ATTRIBUTE Huawei-IPHost-Addr 60 string
+ATTRIBUTE Huawei-Up-Priority 61 integer
+ATTRIBUTE Huawei-Down-Priority 62 integer
+ATTRIBUTE Huawei-Tunnel-VPN-Instance 63 string
+ATTRIBUTE Huawei-VT-Name 64 integer
+ATTRIBUTE Huawei-User-Date 65 string
+ATTRIBUTE Huawei-User-Class 66 string
+ATTRIBUTE Huawei-PPP-NCP-Type 70 integer
+ATTRIBUTE Huawei-VSI-Name 71 string
+ATTRIBUTE Huawei-Subnet-Mask 72 ipaddr
+ATTRIBUTE Huawei-Gateway-Address 73 ipaddr
+ATTRIBUTE Huawei-Lease-Time 74 integer
+ATTRIBUTE Huawei-Primary-WINS 75 ipaddr
+ATTRIBUTE Huawei-Secondary-WINS 76 ipaddr
+ATTRIBUTE Huawei-Input-Peak-Burst-Size 77 integer
+ATTRIBUTE Huawei-Output-Peak-Burst-Size 78 integer
+ATTRIBUTE Huawei-Reduced-CIR 79 integer
+ATTRIBUTE Huawei-Tunnel-Session-Limit 80 integer
+ATTRIBUTE Huawei-Zone-Name 81 string
+ATTRIBUTE Huawei-Data-Filter 82 string
+ATTRIBUTE Huawei-Access-Service 83 string
+ATTRIBUTE Huawei-Accounting-Level 84 integer
+ATTRIBUTE Huawei-Portal-Mode 85 integer
+
+VALUE Huawei-Portal-Mode PADM 0
+VALUE Huawei-Portal-Mode Redirectional 1
+VALUE Huawei-Portal-Mode Non-captive 2
+
+ATTRIBUTE Huawei-DPI-Policy-Name 86 string
+ATTRIBUTE huawei-Policy-Route 87 ipaddr
+ATTRIBUTE Huawei-Framed-Pool 88 string
+ATTRIBUTE Huawei-L2TP-Terminate-Cause 89 string
+ATTRIBUTE Huawei-Multi-Account-Mode 90 integer
+ATTRIBUTE Huawei-Queue-Profile 91 string
+ATTRIBUTE Huawei-Layer4-Session-Limit 92 integer
+ATTRIBUTE Huawei-Multicast-Profile 93 string
+ATTRIBUTE Huawei-VPN-Instance 94 string
+ATTRIBUTE Huawei-Policy-Name 95 string
+ATTRIBUTE Huawei-Tunnel-Group-Name 96 string
+ATTRIBUTE Huawei-Multicast-Source-Group 97 string
+ATTRIBUTE Huawei-Multicast-Receive-Group 98 ipaddr
+ATTRIBUTE Huawei-User-Multicast-Type 99 integer
+ATTRIBUTE Huawei-Reduced-PIR 100 integer
+ATTRIBUTE Huawei-LI-ID 101 string
+ATTRIBUTE Huawei-LI-Md-Address 102 ipaddr
+ATTRIBUTE Huawei-LI-Md-Port 103 integer
+ATTRIBUTE Huawei-LI-Md-VpnInstance 104 string
+ATTRIBUTE Huawei-Service-Chg-Cmd 105 integer
+ATTRIBUTE Huawei-Acct-Packet-Type 106 integer
+ATTRIBUTE Huawei-Call-Reference 107 integer
+ATTRIBUTE Huawei-PSTN-Port 108 integer
+ATTRIBUTE Huawei-Voip-Service-Type 109 integer
+ATTRIBUTE Huawei-Acct-Connection-Time 110 integer
+ATTRIBUTE Huawei-Error-Reason 112 integer
+ATTRIBUTE Huawei-Remain-Monney 113 integer
+ATTRIBUTE Huawei-Org-GK-ipaddr 123 ipaddr
+ATTRIBUTE Huawei-Org-GW-ipaddr 124 ipaddr
+ATTRIBUTE Huawei-Dst-GK-ipaddr 125 ipaddr
+ATTRIBUTE Huawei-Dst-GW-ipaddr 126 ipaddr
+ATTRIBUTE Huawei-Access-Num 127 string
+ATTRIBUTE Huawei-Remain-Time 128 integer
+ATTRIBUTE Huawei-Codec-Type 131 integer
+ATTRIBUTE Huawei-Transfer-Num 132 string
+ATTRIBUTE Huawei-New-User-Name 133 string
+ATTRIBUTE Huawei-Transfer-Station-Id 134 string
+ATTRIBUTE Huawei-Primary-DNS 135 ipaddr
+ATTRIBUTE Huawei-Secondary-DNS 136 ipaddr
+ATTRIBUTE Huawei-ONLY-Account-Type 137 integer
+ATTRIBUTE Huawei-Domain-Name 138 string
+ATTRIBUTE Huawei-ANCP-Profile 139 string
+ATTRIBUTE Huawei-HTTP-Redirect-URL 140 string
+ATTRIBUTE Huawei-Loopback-Address 141 string
+ATTRIBUTE Huawei-QoS-Profile-Type 142 integer
+
+VALUE Huawei-QoS-Profile-Type Original 0
+VALUE Huawei-QoS-Profile-Type L2TP-Inbound 1
+VALUE Huawei-QoS-Profile-Type L2TP-Outbound 2
+VALUE Huawei-QoS-Profile-Type L2TP 3
+
+ATTRIBUTE Huawei-Max-List-Num 143 integer
+ATTRIBUTE Huawei-Acct-IPv6-Input-Octets 144 integer
+ATTRIBUTE Huawei-Acct-IPv6-Output-Octets 145 integer
+ATTRIBUTE Huawei-Acct-IPv6-Input-Packets 146 integer
+ATTRIBUTE Huawei-Acct-IPv6-Output-Packets 147 integer
+ATTRIBUTE Huawei-Acct-IPv6-Input-Gigawords 148 integer
+ATTRIBUTE Huawei-Acct-IPv6-Output-Gigawords 149 integer
+ATTRIBUTE Huawei-DHCPv6-Option37 150 string
+ATTRIBUTE Huawei-DHCPv6-Option38 151 string
+ATTRIBUTE Huawei-User-Mac 153 string
+ATTRIBUTE Huawei-DNS-Server-IPv6-address 154 ipv6addr
+ATTRIBUTE Huawei-DHCPv4-Option121 155 string
+ATTRIBUTE Huawei-DHCPv4-Option43 156 string
+ATTRIBUTE Huawei-Framed-Pool-Group 157 string
+ATTRIBUTE Huawei-Framed-IPv6-Address 158 ipv6addr
+ATTRIBUTE Huawei-Acct-Update-Address 159 integer
+ATTRIBUTE Huawei-NAT-Policy-Name 160 string
+ATTRIBUTE Huawei-NAT-Public-Address 161 ipaddr
+ATTRIBUTE Huawei-NAT-Start-Port 162 integer
+ATTRIBUTE Huawei-NAT-End-Port 163 integer
+ATTRIBUTE Huawei-NAT-Port-Forwarding 164 integer
+ATTRIBUTE Huawei-NAT-Port-Range-Update 165 integer
+ATTRIBUTE Huawei-DS-Lite-Tunnel-Name 166 string
+ATTRIBUTE Huawei-PCP-Server-Name 167 string # manual says text?
+ATTRIBUTE Huawei-Public-IP-Addr-State 168 integer
+
+VALUE Huawei-Public-IP-Addr-State Safe 0
+VALUE Huawei-Public-IP-Addr-State Warning 1
+VALUE Huawei-Public-IP-Addr-State Danger 2
+
+ATTRIBUTE Huawei-Auth-Type 180 integer
+
+VALUE Huawei-Auth-Type PPP 1
+VALUE Huawei-Auth-Type Web 2
+VALUE Huawei-Auth-Type Dot1x 3
+VALUE Huawei-Auth-Type Fast 4
+VALUE Huawei-Auth-Type Bind 5
+VALUE Huawei-Auth-Type WLAN 6
+VALUE Huawei-Auth-Type Administrative 7
+VALUE Huawei-Auth-Type Tunnel 8
+VALUE Huawei-Auth-Type MIP 9
+VALUE Huawei-Auth-Type None 10
+
+ATTRIBUTE Huawei-Acct-Terminate-Subcause 181 string
+ATTRIBUTE Huawei-Down-QOS-Profile-Name 182 string
+ATTRIBUTE Huawei-Port-Mirror 183 integer
+
+VALUE Huawei-Port-Mirror Disable 0
+VALUE Huawei-Port-Mirror Uplink-Enable 1
+VALUE Huawei-Port-Mirror Downlink-Enable 2
+VALUE Huawei-Port-Mirror Enable 3
+
+ATTRIBUTE Huawei-Account-Info 184 string
+ATTRIBUTE Huawei-Service-Info 185 string
+ATTRIBUTE Huawei-DHCP-Option 187 octets
+ATTRIBUTE Huawei-AVpair 188 string
+ATTRIBUTE Huawei-Delegated-IPv6-Prefix-Pool 191 string
+ATTRIBUTE Huawei-IPv6-Prefix-Lease 192 octets
+ATTRIBUTE Huawei-IPv6-Address-Lease 193 octets
+ATTRIBUTE Huawei-IPv6-Policy-Route 194 ipv6prefix # manual says string?
+ATTRIBUTE Huawei-MNG-IPv6 196 integer
+
+VALUE Huawei-MNG-IPv6 Unsupported 0
+VALUE Huawei-MNG-IPv6 Supported 1
+
+#
+# Huawei supports supplying a DPSK by setting the Attribute HW-DPSK-Info
+#
+# https://support.huawei.com/hedex/hdx.do?docid=EDOC1100192518&id=EN-US_CONCEPT_0277881327
+#
+ATTRIBUTE Huawei-DPSK-Info 206 string
+
+ATTRIBUTE Huawei-Flow-Info 211 string
+ATTRIBUTE Huawei-Flow-Id 212 integer
+ATTRIBUTE Huawei-DHCP-Server-IP 214 ipaddr
+ATTRIBUTE Huawei-Application-Type 215 integer
+
+VALUE Huawei-Application-Type Fixed 1
+VALUE Huawei-Application-Type Nomadic 2
+VALUE Huawei-Application-Type Portable 3
+VALUE Huawei-Application-Type Simple-Mobile 4
+VALUE Huawei-Application-Type Full-Mobile 5
+
+ATTRIBUTE Huawei-Indication-Flag 216 octets # integer??
+ATTRIBUTE Huawei-Original_NAS-IP_Address 217 ipaddr
+ATTRIBUTE Huawei-User-Priority 218 integer
+
+VALUE Huawei-User-Priority Common 0
+VALUE Huawei-User-Priority Copper 1
+VALUE Huawei-User-Priority Silver 2
+VALUE Huawei-User-Priority Gold 3
+
+ATTRIBUTE Huawei-ACS-Url 219 string
+ATTRIBUTE Huawei-Provision-Code 220 string
+ATTRIBUTE Huawei-Application-Scene 221 octets
+ATTRIBUTE Huawei-MS-Maximum-MAC-Study-Number 222 octets # ether??
+ATTRIBUTE Huawei-GGSN-Vendor 232 string
+ATTRIBUTE Huawei-GGSN-Version 233 string
+ATTRIBUTE Huawei-Ext-Specific 238 string
+ATTRIBUTE Huawei-Web-URL 253 string
+ATTRIBUTE Huawei-Version 254 string
+ATTRIBUTE Huawei-Product-ID 255 string
+
+END-VENDOR Huawei
diff --git a/share/dictionary.iana b/share/dictionary.iana
new file mode 100644
index 0000000..9f936c5
--- /dev/null
+++ b/share/dictionary.iana
@@ -0,0 +1,48 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Mostly values which have been allocated by IANA under
+# "expert review", but which don't have an RFC associated with them.
+#
+# $Id$
+#
+
+# draft-sterman-aaa-sip-00.txt
+#
+# This is bad... at some point the IETF will allocate these.
+#
+ATTRIBUTE Digest-Response 206 string
+ATTRIBUTE Digest-Attributes 207 octets # stupid format
+
+#
+# Integer Translations
+#
+VALUE Service-Type Voice 12
+VALUE Service-Type Fax 13
+VALUE Service-Type Modem-Relay 14
+VALUE Service-Type IAPP-Register 15
+VALUE Service-Type IAPP-AP-Check 16
+
+VALUE Framed-Protocol GPRS-PDP-Context 7
+
+VALUE NAS-Port-Type Wireless-CDMA2000 22
+VALUE NAS-Port-Type Wireless-UMTS 23
+VALUE NAS-Port-Type Wireless-1X-EV 24
+VALUE NAS-Port-Type IAPP 25
+
+VALUE NAS-Port-Type FTTP 26
+VALUE NAS-Port-Type Wireless-802.16 27
+VALUE NAS-Port-Type Wireless-802.20 28
+VALUE NAS-Port-Type Wireless-802.22 29
+
+VALUE NAS-Port-Type xPON 35
+VALUE NAS-Port-Type Wireless-XGP 36
+
+VALUE Framed-Protocol PPTP 9
+
+#
+# https://freeradius.org/rfc/acct_status_type_subsystem.html
+#
+VALUE Acct-Status-Type Subsystem-On 18
+VALUE Acct-Status-Type Subsystem-Off 19
diff --git a/share/dictionary.iea b/share/dictionary.iea
new file mode 100644
index 0000000..26ed2fd
--- /dev/null
+++ b/share/dictionary.iea
@@ -0,0 +1,19 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# IEA Software, Inc.
+# RADIUS VSA Dictionary
+# http://www.iea-software.com
+
+VENDOR IEA-Software 24023
+BEGIN-VENDOR IEA-Software
+
+# AirMarshal Attributes [1-30]
+ATTRIBUTE AM-Interrupt-HTMLFile 1 string
+ATTRIBUTE AM-Interrupt-Interval 2 integer
+ATTRIBUTE AM-Interrupt-Timeout 3 integer
+ATTRIBUTE AM-Status-HTMLFile 4 string
+ATTRIBUTE AM-HTTP-Proxy-Port 5 integer
+
+END-VENDOR IEA-Software
diff --git a/share/dictionary.infinera b/share/dictionary.infinera
new file mode 100644
index 0000000..8dac69c
--- /dev/null
+++ b/share/dictionary.infinera
@@ -0,0 +1,12 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+VENDOR Infinera 8708
+
+BEGIN-VENDOR Infinera
+
+ATTRIBUTE Infinera-User-Category 1 string
+ATTRIBUTE Infinera-ENM-User-Category 2 string
+
+END-VENDOR Infinera
diff --git a/share/dictionary.infoblox b/share/dictionary.infoblox
new file mode 100644
index 0000000..46759c5
--- /dev/null
+++ b/share/dictionary.infoblox
@@ -0,0 +1,21 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# InfoBlox Inc. VSAs
+#
+VENDOR Infoblox 7779
+
+BEGIN-VENDOR Infoblox
+
+ATTRIBUTE Infoblox-windows-group 1 string
+ATTRIBUTE Infoblox-variable-1 2 string
+ATTRIBUTE Infoblox-variable-2 3 string
+ATTRIBUTE Infoblox-variable-3 4 string
+ATTRIBUTE Infoblox-variable-4 5 string
+ATTRIBUTE Infoblox-variable-5 6 string
+ATTRIBUTE Infoblox-Version 7 string
+ATTRIBUTE Infoblox-Product-Name 8 string
+ATTRIBUTE Infoblox-Group-Info 9 string
+
+END-VENDOR Infoblox
diff --git a/share/dictionary.infonet b/share/dictionary.infonet
new file mode 100644
index 0000000..d27a30c
--- /dev/null
+++ b/share/dictionary.infonet
@@ -0,0 +1,50 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Accounting VSAs by
+# "Bernard Lhoas from Infonet" <Bernard_Lhoas@infonet.com>
+#
+# Version: @(#)dictionary.infonet 1.00
+#
+
+VENDOR infonet 4453
+
+#
+# Standard attribute
+#
+# I would like to change the attribute number of Infonet-Account-Number
+# but we are already using it in production and changing could get
+# messy. Same with Infonet-Type. -Clark
+BEGIN-VENDOR infonet
+
+ATTRIBUTE Infonet-Proxy 238 string
+ATTRIBUTE Infonet-Config 239 string
+ATTRIBUTE Infonet-MCS-Country 240 string
+ATTRIBUTE Infonet-MCS-Region 241 string
+ATTRIBUTE Infonet-MCS-Off-Peak 242 string
+ATTRIBUTE Infonet-MCS-Overflow 243 string
+ATTRIBUTE Infonet-MCS-Port 244 string
+ATTRIBUTE Infonet-MCS-Port-Count 245 string
+ATTRIBUTE Infonet-Account-Number 247 string
+ATTRIBUTE Infonet-Type 248 string
+
+#
+# Infonet-Specific Attributes
+#
+# Note: Only Attributes < 256 will go on the wire. They are known as
+# "wire attributes".
+# Attributes > 256 don't get sent to a NAS and don't get forwarded
+# to a proxy site. This includes accounting packets as well as
+# auth packets.
+#
+ATTRIBUTE Infonet-Pool-Request 252 string
+ATTRIBUTE Infonet-Surcharge-Type 254 integer
+ATTRIBUTE Infonet-NAS-Location 255 string
+ATTRIBUTE Infonet-Random-IP-Pool 246 string
+#
+ATTRIBUTE Infonet-Realm-Type 249 string
+ATTRIBUTE Infonet-LoginHost-Dest 250 string
+ATTRIBUTE Infonet-Tunnel-Decision-IP 251 string
+
+END-VENDOR infonet
diff --git a/share/dictionary.ipunplugged b/share/dictionary.ipunplugged
new file mode 100644
index 0000000..d34dff8
--- /dev/null
+++ b/share/dictionary.ipunplugged
@@ -0,0 +1,29 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# ipUnplugged
+# http://www.ipunplugged.com/
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR ipUnplugged 5925
+
+BEGIN-VENDOR ipUnplugged
+
+ATTRIBUTE IPU-MIP-Spi 51 integer
+ATTRIBUTE IPU-MIP-Key 52 string
+ATTRIBUTE IPU-MIP-Alg-Type 53 integer
+ATTRIBUTE IPU-MIP-Alg-Mode 54 integer
+ATTRIBUTE IPU-MIP-Replay-Prot 55 integer
+ATTRIBUTE IPU-IKE-Remote-Addr 61 ipaddr
+ATTRIBUTE IPU-IKE-Local-Addr 62 ipaddr
+ATTRIBUTE IPU-IKE-Auth 63 string
+ATTRIBUTE IPU-IKE-Conf-Name 64 string
+ATTRIBUTE IPU-IKE-Cmd 65 string
+
+END-VENDOR ipUnplugged
diff --git a/share/dictionary.issanni b/share/dictionary.issanni
new file mode 100644
index 0000000..9b734f1
--- /dev/null
+++ b/share/dictionary.issanni
@@ -0,0 +1,44 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# UTStarcom Issanni DSL router.
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR Issanni 5948
+
+BEGIN-VENDOR Issanni
+#
+# UTStarcom Issanni DSL router.
+#
+ATTRIBUTE Issanni-SoftFlow-Template 1 string
+ATTRIBUTE Issanni-NAT-Support 2 string
+ATTRIBUTE Issanni-Routing-Context 3 string
+ATTRIBUTE Issanni-Tunnel-Name 4 string
+ATTRIBUTE Issanni-IP-Pool-Name 5 string
+ATTRIBUTE Issanni-PPPoE-URL 6 string
+ATTRIBUTE Issanni-PPPoE-MOTM 7 string
+ATTRIBUTE Issanni-Service 8 string
+ATTRIBUTE Issanni-Pri-DNS 9 ipaddr
+ATTRIBUTE Issanni-Sec-DNS 10 ipaddr
+ATTRIBUTE Issanni-Pri-NBNS 11 ipaddr
+ATTRIBUTE Issanni-Sec-NBNS 12 ipaddr
+ATTRIBUTE Issanni-Traffic-Class 13 string
+ATTRIBUTE Issanni-Tunnel-Type 14 integer
+ATTRIBUTE Issanni-NAT-Type 15 integer
+ATTRIBUTE Issanni-QOS-Class 16 string
+ATTRIBUTE Issanni-Interface-Name 17 string
+
+VALUE Issanni-Tunnel-Type IP-IP 1
+VALUE Issanni-Tunnel-Type ESP 2
+VALUE Issanni-Tunnel-Type L2TP 3
+
+VALUE Issanni-NAT-Type NAT 1
+VALUE Issanni-NAT-Type NAPT 2
+
+END-VENDOR Issanni
diff --git a/share/dictionary.itk b/share/dictionary.itk
new file mode 100644
index 0000000..0751f33
--- /dev/null
+++ b/share/dictionary.itk
@@ -0,0 +1,45 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# http://www.digieurope.com/
+# $Id$
+#
+VENDOR ITK 1195
+
+BEGIN-VENDOR ITK
+
+ATTRIBUTE ITK-Auth-Serv-IP 100 ipaddr
+ATTRIBUTE ITK-Auth-Serv-Prot 101 integer
+ATTRIBUTE ITK-Provider-Id 102 integer
+ATTRIBUTE ITK-Usergroup 103 integer
+ATTRIBUTE ITK-Banner 104 string
+ATTRIBUTE ITK-Username-Prompt 105 string
+ATTRIBUTE ITK-Password-Prompt 106 string
+ATTRIBUTE ITK-Welcome-Message 107 string
+ATTRIBUTE ITK-Prompt 108 string
+ATTRIBUTE ITK-IP-Pool 109 integer
+ATTRIBUTE ITK-Tunnel-IP 110 ipaddr
+ATTRIBUTE ITK-Tunnel-Prot 111 integer
+ATTRIBUTE ITK-Acct-Serv-IP 112 ipaddr
+ATTRIBUTE ITK-Acct-Serv-Prot 113 integer
+ATTRIBUTE ITK-Filter-Rule 114 string
+ATTRIBUTE ITK-Channel-Binding 115 integer
+ATTRIBUTE ITK-Start-Delay 116 integer
+ATTRIBUTE ITK-NAS-Name 117 string
+ATTRIBUTE ITK-ISDN-Prot 118 integer
+ATTRIBUTE ITK-PPP-Auth-Type 119 integer
+ATTRIBUTE ITK-Dialout-Type 120 integer
+ATTRIBUTE ITK-Ftp-Auth-IP 121 ipaddr
+ATTRIBUTE ITK-Users-Default-Entry 122 string
+ATTRIBUTE ITK-Users-Default-Pw 123 string
+ATTRIBUTE ITK-Auth-Req-Type 124 string
+ATTRIBUTE ITK-Modem-Pool-Id 125 integer
+ATTRIBUTE ITK-Modem-Init-String 126 string
+ATTRIBUTE ITK-PPP-Client-Server-Mode 127 integer
+ATTRIBUTE ITK-PPP-Compression-Prot 128 string
+ATTRIBUTE ITK-Username 129 string
+ATTRIBUTE ITK-Dest-No 130 string
+ATTRIBUTE ITK-DDI 131 string
+
+END-VENDOR ITK
diff --git a/share/dictionary.juniper b/share/dictionary.juniper
new file mode 100644
index 0000000..15b6e6f
--- /dev/null
+++ b/share/dictionary.juniper
@@ -0,0 +1,79 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# dictionary.juniper
+#
+# As posted to the list by Eric Kilfoil <ekilfoil@uslec.net>
+#
+# Version: $Id$
+#
+
+VENDOR Juniper 2636
+
+BEGIN-VENDOR Juniper
+
+ATTRIBUTE Juniper-Local-User-Name 1 string
+ATTRIBUTE Juniper-Allow-Commands 2 string
+ATTRIBUTE Juniper-Deny-Commands 3 string
+ATTRIBUTE Juniper-Allow-Configuration 4 string
+ATTRIBUTE Juniper-Deny-Configuration 5 string
+
+ATTRIBUTE Juniper-Interactive-Command 8 string
+ATTRIBUTE Juniper-Configuration-Change 9 string
+ATTRIBUTE Juniper-User-Permissions 10 string
+ATTRIBUTE Juniper-Junosspace-Profile 11 String
+ATTRIBUTE Juniper-Junosspace-Profiles 11 String
+
+ATTRIBUTE Juniper-CTP-Group 21 integer
+ATTRIBUTE Juniper-CTPView-APP-Group 22 integer
+ATTRIBUTE Juniper-CTPView-OS-Group 23 integer
+
+ATTRIBUTE Juniper-Primary-Dns 31 ipaddr
+ATTRIBUTE Juniper-Primary-Wins 32 ipaddr
+ATTRIBUTE Juniper-Secondary-Dns 33 ipaddr
+ATTRIBUTE Juniper-Secondary-Wins 34 ipaddr
+ATTRIBUTE Juniper-Interface-id 35 string
+ATTRIBUTE Juniper-Ip-Pool-Name 36 string
+ATTRIBUTE Juniper-Keep-Alive 37 integer
+ATTRIBUTE Juniper-CoS-Traffic-Control-Profile 38 string
+ATTRIBUTE Juniper-CoS-Parameter 39 string
+ATTRIBUTE Juniper-encapsulation-overhead 40 integer
+ATTRIBUTE Juniper-cell-overhead 41 integer
+ATTRIBUTE Juniper-tx-connect-speed 42 integer
+ATTRIBUTE Juniper-rx-connect-speed 43 integer
+ATTRIBUTE Juniper-Firewall-filter-name 44 string
+ATTRIBUTE Juniper-Policer-Parameter 45 string
+ATTRIBUTE Juniper-Local-Group-Name 46 string
+ATTRIBUTE Juniper-Local-Interface 47 string
+ATTRIBUTE Juniper-Switching-Filter 48 string
+ATTRIBUTE Juniper-VoIP-Vlan 49 string
+ATTRIBUTE Juniper-CWA-Redirect 50 string
+
+ATTRIBUTE Juniper-AV-Pair 52 string
+
+ATTRIBUTE Juniper-DHCPv4-Options 55 octets
+ATTRIBUTE Juniper-DHCPv6-Options 207 octets
+ATTRIBUTE Juniper-DHCPv4-Packet-Header 208 octets
+ATTRIBUTE Juniper-DHCPv6-Packet-Header 209 octets
+ATTRIBUTE Juniper-Acct-Request-Reason 210 uint32
+
+
+VALUE Juniper-CTPView-APP-Group Net_View 1
+VALUE Juniper-CTPView-APP-Group Net_Admin 2
+VALUE Juniper-CTPView-APP-Group Global_Admin 3
+
+VALUE Juniper-CTP-Group Read_Only 1
+VALUE Juniper-CTP-Group Admin 2
+VALUE Juniper-CTP-Group Privileged_Admin 3
+VALUE Juniper-CTP-Group Auditor 4
+
+VALUE Juniper-CTPView-OS-Group Web_Manager 1
+VALUE Juniper-CTPView-OS-Group System_Admin 2
+VALUE Juniper-CTPView-OS-Group Auditor 3
+
+VALUE Juniper-Acct-Request-Reason IPv4-Active 0x0004
+VALUE Juniper-Acct-Request-Reason IPv6-Active 0x0010
+VALUE Juniper-Acct-Request-Reason Session-Active 0x0040
+
+END-VENDOR Juniper
diff --git a/share/dictionary.karlnet b/share/dictionary.karlnet
new file mode 100644
index 0000000..5ad94e5
--- /dev/null
+++ b/share/dictionary.karlnet
@@ -0,0 +1,2076 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# KarlNet Vendor-specific information
+
+VENDOR KarlNet 762
+
+# Sets the remote client's Station Name
+BEGIN-VENDOR KarlNet
+
+ATTRIBUTE KarlNet-TurboCell-Name 151 string
+
+# Sets the remote client's Data Transmit Rate
+ATTRIBUTE KarlNet-TurboCell-TxRate 152 integer
+
+# 0x00 // Use the locally defined Data Rate
+VALUE KarlNet-TurboCell-TxRate TxRate-Local 0
+# 0x08 // Use the maximum data rate possible
+VALUE KarlNet-TurboCell-TxRate TxRate-MaxSpeed 8
+
+VALUE KarlNet-TurboCell-TxRate TxRate-11k 11
+VALUE KarlNet-TurboCell-TxRate TxRate-12k 12
+VALUE KarlNet-TurboCell-TxRate TxRate-13k 13
+VALUE KarlNet-TurboCell-TxRate TxRate-14k 14
+VALUE KarlNet-TurboCell-TxRate TxRate-15k 15
+VALUE KarlNet-TurboCell-TxRate TxRate-16k 16
+VALUE KarlNet-TurboCell-TxRate TxRate-17k 17
+VALUE KarlNet-TurboCell-TxRate TxRate-18k 18
+VALUE KarlNet-TurboCell-TxRate TxRate-19k 19
+VALUE KarlNet-TurboCell-TxRate TxRate-20k 20
+VALUE KarlNet-TurboCell-TxRate TxRate-21k 21
+VALUE KarlNet-TurboCell-TxRate TxRate-22k 22
+VALUE KarlNet-TurboCell-TxRate TxRate-23k 23
+VALUE KarlNet-TurboCell-TxRate TxRate-24k 24
+VALUE KarlNet-TurboCell-TxRate TxRate-25k 25
+VALUE KarlNet-TurboCell-TxRate TxRate-26k 26
+VALUE KarlNet-TurboCell-TxRate TxRate-27k 27
+VALUE KarlNet-TurboCell-TxRate TxRate-28k 28
+VALUE KarlNet-TurboCell-TxRate TxRate-29k 29
+VALUE KarlNet-TurboCell-TxRate TxRate-30k 30
+VALUE KarlNet-TurboCell-TxRate TxRate-31k 31
+VALUE KarlNet-TurboCell-TxRate TxRate-32k 32
+VALUE KarlNet-TurboCell-TxRate TxRate-33k 33
+VALUE KarlNet-TurboCell-TxRate TxRate-34k 34
+VALUE KarlNet-TurboCell-TxRate TxRate-35k 35
+VALUE KarlNet-TurboCell-TxRate TxRate-36k 36
+VALUE KarlNet-TurboCell-TxRate TxRate-37k 37
+VALUE KarlNet-TurboCell-TxRate TxRate-38k 38
+VALUE KarlNet-TurboCell-TxRate TxRate-39k 39
+VALUE KarlNet-TurboCell-TxRate TxRate-40k 40
+VALUE KarlNet-TurboCell-TxRate TxRate-41k 41
+VALUE KarlNet-TurboCell-TxRate TxRate-42k 42
+VALUE KarlNet-TurboCell-TxRate TxRate-43k 43
+VALUE KarlNet-TurboCell-TxRate TxRate-44k 44
+VALUE KarlNet-TurboCell-TxRate TxRate-45k 45
+VALUE KarlNet-TurboCell-TxRate TxRate-46k 46
+VALUE KarlNet-TurboCell-TxRate TxRate-47k 47
+VALUE KarlNet-TurboCell-TxRate TxRate-48k 48
+VALUE KarlNet-TurboCell-TxRate TxRate-49k 49
+VALUE KarlNet-TurboCell-TxRate TxRate-50k 50
+VALUE KarlNet-TurboCell-TxRate TxRate-51k 51
+VALUE KarlNet-TurboCell-TxRate TxRate-52k 52
+VALUE KarlNet-TurboCell-TxRate TxRate-53k 53
+VALUE KarlNet-TurboCell-TxRate TxRate-54k 54
+VALUE KarlNet-TurboCell-TxRate TxRate-55k 55
+VALUE KarlNet-TurboCell-TxRate TxRate-56k 56
+VALUE KarlNet-TurboCell-TxRate TxRate-57k 57
+VALUE KarlNet-TurboCell-TxRate TxRate-58k 58
+VALUE KarlNet-TurboCell-TxRate TxRate-59k 59
+VALUE KarlNet-TurboCell-TxRate TxRate-60k 60
+VALUE KarlNet-TurboCell-TxRate TxRate-61k 61
+VALUE KarlNet-TurboCell-TxRate TxRate-62k 62
+VALUE KarlNet-TurboCell-TxRate TxRate-63k 63
+VALUE KarlNet-TurboCell-TxRate TxRate-64k 64
+VALUE KarlNet-TurboCell-TxRate TxRate-65k 65
+VALUE KarlNet-TurboCell-TxRate TxRate-66k 66
+VALUE KarlNet-TurboCell-TxRate TxRate-67k 67
+VALUE KarlNet-TurboCell-TxRate TxRate-68k 68
+VALUE KarlNet-TurboCell-TxRate TxRate-69k 69
+VALUE KarlNet-TurboCell-TxRate TxRate-70k 70
+VALUE KarlNet-TurboCell-TxRate TxRate-71k 71
+VALUE KarlNet-TurboCell-TxRate TxRate-72k 72
+VALUE KarlNet-TurboCell-TxRate TxRate-73k 73
+VALUE KarlNet-TurboCell-TxRate TxRate-74k 74
+VALUE KarlNet-TurboCell-TxRate TxRate-75k 75
+VALUE KarlNet-TurboCell-TxRate TxRate-76k 76
+VALUE KarlNet-TurboCell-TxRate TxRate-77k 77
+VALUE KarlNet-TurboCell-TxRate TxRate-78k 78
+VALUE KarlNet-TurboCell-TxRate TxRate-79k 79
+VALUE KarlNet-TurboCell-TxRate TxRate-80k 80
+VALUE KarlNet-TurboCell-TxRate TxRate-81k 81
+VALUE KarlNet-TurboCell-TxRate TxRate-82k 82
+VALUE KarlNet-TurboCell-TxRate TxRate-83k 83
+VALUE KarlNet-TurboCell-TxRate TxRate-84k 84
+VALUE KarlNet-TurboCell-TxRate TxRate-85k 85
+VALUE KarlNet-TurboCell-TxRate TxRate-86k 86
+VALUE KarlNet-TurboCell-TxRate TxRate-87k 87
+VALUE KarlNet-TurboCell-TxRate TxRate-88k 88
+VALUE KarlNet-TurboCell-TxRate TxRate-89k 89
+VALUE KarlNet-TurboCell-TxRate TxRate-90k 90
+VALUE KarlNet-TurboCell-TxRate TxRate-91k 91
+VALUE KarlNet-TurboCell-TxRate TxRate-92k 92
+VALUE KarlNet-TurboCell-TxRate TxRate-93k 93
+VALUE KarlNet-TurboCell-TxRate TxRate-94k 94
+VALUE KarlNet-TurboCell-TxRate TxRate-95k 95
+VALUE KarlNet-TurboCell-TxRate TxRate-96k 96
+VALUE KarlNet-TurboCell-TxRate TxRate-97k 97
+VALUE KarlNet-TurboCell-TxRate TxRate-98k 98
+VALUE KarlNet-TurboCell-TxRate TxRate-99k 99
+VALUE KarlNet-TurboCell-TxRate TxRate-100k 100
+VALUE KarlNet-TurboCell-TxRate TxRate-101k 101
+VALUE KarlNet-TurboCell-TxRate TxRate-102k 102
+VALUE KarlNet-TurboCell-TxRate TxRate-103k 103
+VALUE KarlNet-TurboCell-TxRate TxRate-104k 104
+VALUE KarlNet-TurboCell-TxRate TxRate-105k 105
+VALUE KarlNet-TurboCell-TxRate TxRate-106k 106
+VALUE KarlNet-TurboCell-TxRate TxRate-107k 107
+VALUE KarlNet-TurboCell-TxRate TxRate-108k 108
+VALUE KarlNet-TurboCell-TxRate TxRate-109k 109
+VALUE KarlNet-TurboCell-TxRate TxRate-110k 110
+VALUE KarlNet-TurboCell-TxRate TxRate-111k 111
+VALUE KarlNet-TurboCell-TxRate TxRate-112k 112
+VALUE KarlNet-TurboCell-TxRate TxRate-113k 113
+VALUE KarlNet-TurboCell-TxRate TxRate-114k 114
+VALUE KarlNet-TurboCell-TxRate TxRate-115k 115
+VALUE KarlNet-TurboCell-TxRate TxRate-116k 116
+VALUE KarlNet-TurboCell-TxRate TxRate-117k 117
+VALUE KarlNet-TurboCell-TxRate TxRate-118k 118
+VALUE KarlNet-TurboCell-TxRate TxRate-119k 119
+VALUE KarlNet-TurboCell-TxRate TxRate-120k 120
+VALUE KarlNet-TurboCell-TxRate TxRate-121k 121
+VALUE KarlNet-TurboCell-TxRate TxRate-122k 122
+VALUE KarlNet-TurboCell-TxRate TxRate-123k 123
+VALUE KarlNet-TurboCell-TxRate TxRate-124k 124
+VALUE KarlNet-TurboCell-TxRate TxRate-125k 125
+VALUE KarlNet-TurboCell-TxRate TxRate-126k 126
+VALUE KarlNet-TurboCell-TxRate TxRate-127k 127
+VALUE KarlNet-TurboCell-TxRate TxRate-128k 128
+VALUE KarlNet-TurboCell-TxRate TxRate-129k 129
+VALUE KarlNet-TurboCell-TxRate TxRate-130k 130
+VALUE KarlNet-TurboCell-TxRate TxRate-131k 131
+VALUE KarlNet-TurboCell-TxRate TxRate-132k 132
+VALUE KarlNet-TurboCell-TxRate TxRate-133k 133
+VALUE KarlNet-TurboCell-TxRate TxRate-134k 134
+VALUE KarlNet-TurboCell-TxRate TxRate-135k 135
+VALUE KarlNet-TurboCell-TxRate TxRate-136k 136
+VALUE KarlNet-TurboCell-TxRate TxRate-137k 137
+VALUE KarlNet-TurboCell-TxRate TxRate-138k 138
+VALUE KarlNet-TurboCell-TxRate TxRate-139k 139
+VALUE KarlNet-TurboCell-TxRate TxRate-140k 140
+VALUE KarlNet-TurboCell-TxRate TxRate-141k 141
+VALUE KarlNet-TurboCell-TxRate TxRate-142k 142
+VALUE KarlNet-TurboCell-TxRate TxRate-143k 143
+VALUE KarlNet-TurboCell-TxRate TxRate-144k 144
+VALUE KarlNet-TurboCell-TxRate TxRate-145k 145
+VALUE KarlNet-TurboCell-TxRate TxRate-146k 146
+VALUE KarlNet-TurboCell-TxRate TxRate-147k 147
+VALUE KarlNet-TurboCell-TxRate TxRate-148k 148
+VALUE KarlNet-TurboCell-TxRate TxRate-149k 149
+VALUE KarlNet-TurboCell-TxRate TxRate-150k 150
+VALUE KarlNet-TurboCell-TxRate TxRate-151k 151
+VALUE KarlNet-TurboCell-TxRate TxRate-152k 152
+VALUE KarlNet-TurboCell-TxRate TxRate-153k 153
+VALUE KarlNet-TurboCell-TxRate TxRate-154k 154
+VALUE KarlNet-TurboCell-TxRate TxRate-155k 155
+VALUE KarlNet-TurboCell-TxRate TxRate-156k 156
+VALUE KarlNet-TurboCell-TxRate TxRate-157k 157
+VALUE KarlNet-TurboCell-TxRate TxRate-158k 158
+VALUE KarlNet-TurboCell-TxRate TxRate-159k 159
+VALUE KarlNet-TurboCell-TxRate TxRate-160k 160
+VALUE KarlNet-TurboCell-TxRate TxRate-161k 161
+VALUE KarlNet-TurboCell-TxRate TxRate-162k 162
+VALUE KarlNet-TurboCell-TxRate TxRate-163k 163
+VALUE KarlNet-TurboCell-TxRate TxRate-164k 164
+VALUE KarlNet-TurboCell-TxRate TxRate-165k 165
+VALUE KarlNet-TurboCell-TxRate TxRate-166k 166
+VALUE KarlNet-TurboCell-TxRate TxRate-167k 167
+VALUE KarlNet-TurboCell-TxRate TxRate-168k 168
+VALUE KarlNet-TurboCell-TxRate TxRate-169k 169
+VALUE KarlNet-TurboCell-TxRate TxRate-170k 170
+VALUE KarlNet-TurboCell-TxRate TxRate-171k 171
+VALUE KarlNet-TurboCell-TxRate TxRate-172k 172
+VALUE KarlNet-TurboCell-TxRate TxRate-173k 173
+VALUE KarlNet-TurboCell-TxRate TxRate-174k 174
+VALUE KarlNet-TurboCell-TxRate TxRate-175k 175
+VALUE KarlNet-TurboCell-TxRate TxRate-176k 176
+VALUE KarlNet-TurboCell-TxRate TxRate-177k 177
+VALUE KarlNet-TurboCell-TxRate TxRate-178k 178
+VALUE KarlNet-TurboCell-TxRate TxRate-179k 179
+VALUE KarlNet-TurboCell-TxRate TxRate-180k 180
+VALUE KarlNet-TurboCell-TxRate TxRate-181k 181
+VALUE KarlNet-TurboCell-TxRate TxRate-182k 182
+VALUE KarlNet-TurboCell-TxRate TxRate-183k 183
+VALUE KarlNet-TurboCell-TxRate TxRate-184k 184
+VALUE KarlNet-TurboCell-TxRate TxRate-185k 185
+VALUE KarlNet-TurboCell-TxRate TxRate-186k 186
+VALUE KarlNet-TurboCell-TxRate TxRate-187k 187
+VALUE KarlNet-TurboCell-TxRate TxRate-188k 188
+VALUE KarlNet-TurboCell-TxRate TxRate-189k 189
+VALUE KarlNet-TurboCell-TxRate TxRate-190k 190
+VALUE KarlNet-TurboCell-TxRate TxRate-191k 191
+VALUE KarlNet-TurboCell-TxRate TxRate-192k 192
+VALUE KarlNet-TurboCell-TxRate TxRate-193k 193
+VALUE KarlNet-TurboCell-TxRate TxRate-194k 194
+VALUE KarlNet-TurboCell-TxRate TxRate-195k 195
+VALUE KarlNet-TurboCell-TxRate TxRate-196k 196
+VALUE KarlNet-TurboCell-TxRate TxRate-197k 197
+VALUE KarlNet-TurboCell-TxRate TxRate-198k 198
+VALUE KarlNet-TurboCell-TxRate TxRate-199k 199
+VALUE KarlNet-TurboCell-TxRate TxRate-200k 200
+VALUE KarlNet-TurboCell-TxRate TxRate-201k 201
+VALUE KarlNet-TurboCell-TxRate TxRate-202k 202
+VALUE KarlNet-TurboCell-TxRate TxRate-203k 203
+VALUE KarlNet-TurboCell-TxRate TxRate-204k 204
+VALUE KarlNet-TurboCell-TxRate TxRate-205k 205
+VALUE KarlNet-TurboCell-TxRate TxRate-206k 206
+VALUE KarlNet-TurboCell-TxRate TxRate-207k 207
+VALUE KarlNet-TurboCell-TxRate TxRate-208k 208
+VALUE KarlNet-TurboCell-TxRate TxRate-209k 209
+VALUE KarlNet-TurboCell-TxRate TxRate-210k 210
+VALUE KarlNet-TurboCell-TxRate TxRate-211k 211
+VALUE KarlNet-TurboCell-TxRate TxRate-212k 212
+VALUE KarlNet-TurboCell-TxRate TxRate-213k 213
+VALUE KarlNet-TurboCell-TxRate TxRate-214k 214
+VALUE KarlNet-TurboCell-TxRate TxRate-215k 215
+VALUE KarlNet-TurboCell-TxRate TxRate-216k 216
+VALUE KarlNet-TurboCell-TxRate TxRate-217k 217
+VALUE KarlNet-TurboCell-TxRate TxRate-218k 218
+VALUE KarlNet-TurboCell-TxRate TxRate-219k 219
+VALUE KarlNet-TurboCell-TxRate TxRate-220k 220
+VALUE KarlNet-TurboCell-TxRate TxRate-221k 221
+VALUE KarlNet-TurboCell-TxRate TxRate-222k 222
+VALUE KarlNet-TurboCell-TxRate TxRate-223k 223
+VALUE KarlNet-TurboCell-TxRate TxRate-224k 224
+VALUE KarlNet-TurboCell-TxRate TxRate-225k 225
+VALUE KarlNet-TurboCell-TxRate TxRate-226k 226
+VALUE KarlNet-TurboCell-TxRate TxRate-227k 227
+VALUE KarlNet-TurboCell-TxRate TxRate-228k 228
+VALUE KarlNet-TurboCell-TxRate TxRate-229k 229
+VALUE KarlNet-TurboCell-TxRate TxRate-230k 230
+VALUE KarlNet-TurboCell-TxRate TxRate-231k 231
+VALUE KarlNet-TurboCell-TxRate TxRate-232k 232
+VALUE KarlNet-TurboCell-TxRate TxRate-233k 233
+VALUE KarlNet-TurboCell-TxRate TxRate-234k 234
+VALUE KarlNet-TurboCell-TxRate TxRate-235k 235
+VALUE KarlNet-TurboCell-TxRate TxRate-236k 236
+VALUE KarlNet-TurboCell-TxRate TxRate-237k 237
+VALUE KarlNet-TurboCell-TxRate TxRate-238k 238
+VALUE KarlNet-TurboCell-TxRate TxRate-239k 239
+VALUE KarlNet-TurboCell-TxRate TxRate-240k 240
+VALUE KarlNet-TurboCell-TxRate TxRate-241k 241
+VALUE KarlNet-TurboCell-TxRate TxRate-242k 242
+VALUE KarlNet-TurboCell-TxRate TxRate-243k 243
+VALUE KarlNet-TurboCell-TxRate TxRate-244k 244
+VALUE KarlNet-TurboCell-TxRate TxRate-245k 245
+VALUE KarlNet-TurboCell-TxRate TxRate-246k 246
+VALUE KarlNet-TurboCell-TxRate TxRate-247k 247
+VALUE KarlNet-TurboCell-TxRate TxRate-248k 248
+VALUE KarlNet-TurboCell-TxRate TxRate-249k 249
+VALUE KarlNet-TurboCell-TxRate TxRate-250k 250
+VALUE KarlNet-TurboCell-TxRate TxRate-251k 251
+VALUE KarlNet-TurboCell-TxRate TxRate-252k 252
+VALUE KarlNet-TurboCell-TxRate TxRate-253k 253
+VALUE KarlNet-TurboCell-TxRate TxRate-254k 254
+VALUE KarlNet-TurboCell-TxRate TxRate-255k 255
+VALUE KarlNet-TurboCell-TxRate TxRate-256k 256
+VALUE KarlNet-TurboCell-TxRate TxRate-257k 257
+VALUE KarlNet-TurboCell-TxRate TxRate-258k 258
+VALUE KarlNet-TurboCell-TxRate TxRate-259k 259
+VALUE KarlNet-TurboCell-TxRate TxRate-260k 260
+VALUE KarlNet-TurboCell-TxRate TxRate-261k 261
+VALUE KarlNet-TurboCell-TxRate TxRate-262k 262
+VALUE KarlNet-TurboCell-TxRate TxRate-263k 263
+VALUE KarlNet-TurboCell-TxRate TxRate-264k 264
+VALUE KarlNet-TurboCell-TxRate TxRate-265k 265
+VALUE KarlNet-TurboCell-TxRate TxRate-266k 266
+VALUE KarlNet-TurboCell-TxRate TxRate-267k 267
+VALUE KarlNet-TurboCell-TxRate TxRate-268k 268
+VALUE KarlNet-TurboCell-TxRate TxRate-269k 269
+VALUE KarlNet-TurboCell-TxRate TxRate-270k 270
+VALUE KarlNet-TurboCell-TxRate TxRate-271k 271
+VALUE KarlNet-TurboCell-TxRate TxRate-272k 272
+VALUE KarlNet-TurboCell-TxRate TxRate-273k 273
+VALUE KarlNet-TurboCell-TxRate TxRate-274k 274
+VALUE KarlNet-TurboCell-TxRate TxRate-275k 275
+VALUE KarlNet-TurboCell-TxRate TxRate-276k 276
+VALUE KarlNet-TurboCell-TxRate TxRate-277k 277
+VALUE KarlNet-TurboCell-TxRate TxRate-278k 278
+VALUE KarlNet-TurboCell-TxRate TxRate-279k 279
+VALUE KarlNet-TurboCell-TxRate TxRate-280k 280
+VALUE KarlNet-TurboCell-TxRate TxRate-281k 281
+VALUE KarlNet-TurboCell-TxRate TxRate-282k 282
+VALUE KarlNet-TurboCell-TxRate TxRate-283k 283
+VALUE KarlNet-TurboCell-TxRate TxRate-284k 284
+VALUE KarlNet-TurboCell-TxRate TxRate-285k 285
+VALUE KarlNet-TurboCell-TxRate TxRate-286k 286
+VALUE KarlNet-TurboCell-TxRate TxRate-287k 287
+VALUE KarlNet-TurboCell-TxRate TxRate-288k 288
+VALUE KarlNet-TurboCell-TxRate TxRate-289k 289
+VALUE KarlNet-TurboCell-TxRate TxRate-290k 290
+VALUE KarlNet-TurboCell-TxRate TxRate-291k 291
+VALUE KarlNet-TurboCell-TxRate TxRate-292k 292
+VALUE KarlNet-TurboCell-TxRate TxRate-293k 293
+VALUE KarlNet-TurboCell-TxRate TxRate-294k 294
+VALUE KarlNet-TurboCell-TxRate TxRate-295k 295
+VALUE KarlNet-TurboCell-TxRate TxRate-296k 296
+VALUE KarlNet-TurboCell-TxRate TxRate-297k 297
+VALUE KarlNet-TurboCell-TxRate TxRate-298k 298
+VALUE KarlNet-TurboCell-TxRate TxRate-299k 299
+VALUE KarlNet-TurboCell-TxRate TxRate-300k 300
+VALUE KarlNet-TurboCell-TxRate TxRate-301k 301
+VALUE KarlNet-TurboCell-TxRate TxRate-302k 302
+VALUE KarlNet-TurboCell-TxRate TxRate-303k 303
+VALUE KarlNet-TurboCell-TxRate TxRate-304k 304
+VALUE KarlNet-TurboCell-TxRate TxRate-305k 305
+VALUE KarlNet-TurboCell-TxRate TxRate-306k 306
+VALUE KarlNet-TurboCell-TxRate TxRate-307k 307
+VALUE KarlNet-TurboCell-TxRate TxRate-308k 308
+VALUE KarlNet-TurboCell-TxRate TxRate-309k 309
+VALUE KarlNet-TurboCell-TxRate TxRate-310k 310
+VALUE KarlNet-TurboCell-TxRate TxRate-311k 311
+VALUE KarlNet-TurboCell-TxRate TxRate-312k 312
+VALUE KarlNet-TurboCell-TxRate TxRate-313k 313
+VALUE KarlNet-TurboCell-TxRate TxRate-314k 314
+VALUE KarlNet-TurboCell-TxRate TxRate-315k 315
+VALUE KarlNet-TurboCell-TxRate TxRate-316k 316
+VALUE KarlNet-TurboCell-TxRate TxRate-317k 317
+VALUE KarlNet-TurboCell-TxRate TxRate-318k 318
+VALUE KarlNet-TurboCell-TxRate TxRate-319k 319
+VALUE KarlNet-TurboCell-TxRate TxRate-320k 320
+VALUE KarlNet-TurboCell-TxRate TxRate-321k 321
+VALUE KarlNet-TurboCell-TxRate TxRate-322k 322
+VALUE KarlNet-TurboCell-TxRate TxRate-323k 323
+VALUE KarlNet-TurboCell-TxRate TxRate-324k 324
+VALUE KarlNet-TurboCell-TxRate TxRate-325k 325
+VALUE KarlNet-TurboCell-TxRate TxRate-326k 326
+VALUE KarlNet-TurboCell-TxRate TxRate-327k 327
+VALUE KarlNet-TurboCell-TxRate TxRate-328k 328
+VALUE KarlNet-TurboCell-TxRate TxRate-329k 329
+VALUE KarlNet-TurboCell-TxRate TxRate-330k 330
+VALUE KarlNet-TurboCell-TxRate TxRate-331k 331
+VALUE KarlNet-TurboCell-TxRate TxRate-332k 332
+VALUE KarlNet-TurboCell-TxRate TxRate-333k 333
+VALUE KarlNet-TurboCell-TxRate TxRate-334k 334
+VALUE KarlNet-TurboCell-TxRate TxRate-335k 335
+VALUE KarlNet-TurboCell-TxRate TxRate-336k 336
+VALUE KarlNet-TurboCell-TxRate TxRate-337k 337
+VALUE KarlNet-TurboCell-TxRate TxRate-338k 338
+VALUE KarlNet-TurboCell-TxRate TxRate-339k 339
+VALUE KarlNet-TurboCell-TxRate TxRate-340k 340
+VALUE KarlNet-TurboCell-TxRate TxRate-341k 341
+VALUE KarlNet-TurboCell-TxRate TxRate-342k 342
+VALUE KarlNet-TurboCell-TxRate TxRate-343k 343
+VALUE KarlNet-TurboCell-TxRate TxRate-344k 344
+VALUE KarlNet-TurboCell-TxRate TxRate-345k 345
+VALUE KarlNet-TurboCell-TxRate TxRate-346k 346
+VALUE KarlNet-TurboCell-TxRate TxRate-347k 347
+VALUE KarlNet-TurboCell-TxRate TxRate-348k 348
+VALUE KarlNet-TurboCell-TxRate TxRate-349k 349
+VALUE KarlNet-TurboCell-TxRate TxRate-350k 350
+VALUE KarlNet-TurboCell-TxRate TxRate-351k 351
+VALUE KarlNet-TurboCell-TxRate TxRate-352k 352
+VALUE KarlNet-TurboCell-TxRate TxRate-353k 353
+VALUE KarlNet-TurboCell-TxRate TxRate-354k 354
+VALUE KarlNet-TurboCell-TxRate TxRate-355k 355
+VALUE KarlNet-TurboCell-TxRate TxRate-356k 356
+VALUE KarlNet-TurboCell-TxRate TxRate-357k 357
+VALUE KarlNet-TurboCell-TxRate TxRate-358k 358
+VALUE KarlNet-TurboCell-TxRate TxRate-359k 359
+VALUE KarlNet-TurboCell-TxRate TxRate-360k 360
+VALUE KarlNet-TurboCell-TxRate TxRate-361k 361
+VALUE KarlNet-TurboCell-TxRate TxRate-362k 362
+VALUE KarlNet-TurboCell-TxRate TxRate-363k 363
+VALUE KarlNet-TurboCell-TxRate TxRate-364k 364
+VALUE KarlNet-TurboCell-TxRate TxRate-365k 365
+VALUE KarlNet-TurboCell-TxRate TxRate-366k 366
+VALUE KarlNet-TurboCell-TxRate TxRate-367k 367
+VALUE KarlNet-TurboCell-TxRate TxRate-368k 368
+VALUE KarlNet-TurboCell-TxRate TxRate-369k 369
+VALUE KarlNet-TurboCell-TxRate TxRate-370k 370
+VALUE KarlNet-TurboCell-TxRate TxRate-371k 371
+VALUE KarlNet-TurboCell-TxRate TxRate-372k 372
+VALUE KarlNet-TurboCell-TxRate TxRate-373k 373
+VALUE KarlNet-TurboCell-TxRate TxRate-374k 374
+VALUE KarlNet-TurboCell-TxRate TxRate-375k 375
+VALUE KarlNet-TurboCell-TxRate TxRate-376k 376
+VALUE KarlNet-TurboCell-TxRate TxRate-377k 377
+VALUE KarlNet-TurboCell-TxRate TxRate-378k 378
+VALUE KarlNet-TurboCell-TxRate TxRate-379k 379
+VALUE KarlNet-TurboCell-TxRate TxRate-380k 380
+VALUE KarlNet-TurboCell-TxRate TxRate-381k 381
+VALUE KarlNet-TurboCell-TxRate TxRate-382k 382
+VALUE KarlNet-TurboCell-TxRate TxRate-383k 383
+VALUE KarlNet-TurboCell-TxRate TxRate-384k 384
+VALUE KarlNet-TurboCell-TxRate TxRate-385k 385
+VALUE KarlNet-TurboCell-TxRate TxRate-386k 386
+VALUE KarlNet-TurboCell-TxRate TxRate-387k 387
+VALUE KarlNet-TurboCell-TxRate TxRate-388k 388
+VALUE KarlNet-TurboCell-TxRate TxRate-389k 389
+VALUE KarlNet-TurboCell-TxRate TxRate-390k 390
+VALUE KarlNet-TurboCell-TxRate TxRate-391k 391
+VALUE KarlNet-TurboCell-TxRate TxRate-392k 392
+VALUE KarlNet-TurboCell-TxRate TxRate-393k 393
+VALUE KarlNet-TurboCell-TxRate TxRate-394k 394
+VALUE KarlNet-TurboCell-TxRate TxRate-395k 395
+VALUE KarlNet-TurboCell-TxRate TxRate-396k 396
+VALUE KarlNet-TurboCell-TxRate TxRate-397k 397
+VALUE KarlNet-TurboCell-TxRate TxRate-398k 398
+VALUE KarlNet-TurboCell-TxRate TxRate-399k 399
+VALUE KarlNet-TurboCell-TxRate TxRate-400k 400
+VALUE KarlNet-TurboCell-TxRate TxRate-401k 401
+VALUE KarlNet-TurboCell-TxRate TxRate-402k 402
+VALUE KarlNet-TurboCell-TxRate TxRate-403k 403
+VALUE KarlNet-TurboCell-TxRate TxRate-404k 404
+VALUE KarlNet-TurboCell-TxRate TxRate-405k 405
+VALUE KarlNet-TurboCell-TxRate TxRate-406k 406
+VALUE KarlNet-TurboCell-TxRate TxRate-407k 407
+VALUE KarlNet-TurboCell-TxRate TxRate-408k 408
+VALUE KarlNet-TurboCell-TxRate TxRate-409k 409
+VALUE KarlNet-TurboCell-TxRate TxRate-410k 410
+VALUE KarlNet-TurboCell-TxRate TxRate-411k 411
+VALUE KarlNet-TurboCell-TxRate TxRate-412k 412
+VALUE KarlNet-TurboCell-TxRate TxRate-413k 413
+VALUE KarlNet-TurboCell-TxRate TxRate-414k 414
+VALUE KarlNet-TurboCell-TxRate TxRate-415k 415
+VALUE KarlNet-TurboCell-TxRate TxRate-416k 416
+VALUE KarlNet-TurboCell-TxRate TxRate-417k 417
+VALUE KarlNet-TurboCell-TxRate TxRate-418k 418
+VALUE KarlNet-TurboCell-TxRate TxRate-419k 419
+VALUE KarlNet-TurboCell-TxRate TxRate-420k 420
+VALUE KarlNet-TurboCell-TxRate TxRate-421k 421
+VALUE KarlNet-TurboCell-TxRate TxRate-422k 422
+VALUE KarlNet-TurboCell-TxRate TxRate-423k 423
+VALUE KarlNet-TurboCell-TxRate TxRate-424k 424
+VALUE KarlNet-TurboCell-TxRate TxRate-425k 425
+VALUE KarlNet-TurboCell-TxRate TxRate-426k 426
+VALUE KarlNet-TurboCell-TxRate TxRate-427k 427
+VALUE KarlNet-TurboCell-TxRate TxRate-428k 428
+VALUE KarlNet-TurboCell-TxRate TxRate-429k 429
+VALUE KarlNet-TurboCell-TxRate TxRate-430k 430
+VALUE KarlNet-TurboCell-TxRate TxRate-431k 431
+VALUE KarlNet-TurboCell-TxRate TxRate-432k 432
+VALUE KarlNet-TurboCell-TxRate TxRate-433k 433
+VALUE KarlNet-TurboCell-TxRate TxRate-434k 434
+VALUE KarlNet-TurboCell-TxRate TxRate-435k 435
+VALUE KarlNet-TurboCell-TxRate TxRate-436k 436
+VALUE KarlNet-TurboCell-TxRate TxRate-437k 437
+VALUE KarlNet-TurboCell-TxRate TxRate-438k 438
+VALUE KarlNet-TurboCell-TxRate TxRate-439k 439
+VALUE KarlNet-TurboCell-TxRate TxRate-440k 440
+VALUE KarlNet-TurboCell-TxRate TxRate-441k 441
+VALUE KarlNet-TurboCell-TxRate TxRate-442k 442
+VALUE KarlNet-TurboCell-TxRate TxRate-443k 443
+VALUE KarlNet-TurboCell-TxRate TxRate-444k 444
+VALUE KarlNet-TurboCell-TxRate TxRate-445k 445
+VALUE KarlNet-TurboCell-TxRate TxRate-446k 446
+VALUE KarlNet-TurboCell-TxRate TxRate-447k 447
+VALUE KarlNet-TurboCell-TxRate TxRate-448k 448
+VALUE KarlNet-TurboCell-TxRate TxRate-449k 449
+VALUE KarlNet-TurboCell-TxRate TxRate-450k 450
+VALUE KarlNet-TurboCell-TxRate TxRate-451k 451
+VALUE KarlNet-TurboCell-TxRate TxRate-452k 452
+VALUE KarlNet-TurboCell-TxRate TxRate-453k 453
+VALUE KarlNet-TurboCell-TxRate TxRate-454k 454
+VALUE KarlNet-TurboCell-TxRate TxRate-455k 455
+VALUE KarlNet-TurboCell-TxRate TxRate-456k 456
+VALUE KarlNet-TurboCell-TxRate TxRate-457k 457
+VALUE KarlNet-TurboCell-TxRate TxRate-458k 458
+VALUE KarlNet-TurboCell-TxRate TxRate-459k 459
+VALUE KarlNet-TurboCell-TxRate TxRate-460k 460
+VALUE KarlNet-TurboCell-TxRate TxRate-461k 461
+VALUE KarlNet-TurboCell-TxRate TxRate-462k 462
+VALUE KarlNet-TurboCell-TxRate TxRate-463k 463
+VALUE KarlNet-TurboCell-TxRate TxRate-464k 464
+VALUE KarlNet-TurboCell-TxRate TxRate-465k 465
+VALUE KarlNet-TurboCell-TxRate TxRate-466k 466
+VALUE KarlNet-TurboCell-TxRate TxRate-467k 467
+VALUE KarlNet-TurboCell-TxRate TxRate-468k 468
+VALUE KarlNet-TurboCell-TxRate TxRate-469k 469
+VALUE KarlNet-TurboCell-TxRate TxRate-470k 470
+VALUE KarlNet-TurboCell-TxRate TxRate-471k 471
+VALUE KarlNet-TurboCell-TxRate TxRate-472k 472
+VALUE KarlNet-TurboCell-TxRate TxRate-473k 473
+VALUE KarlNet-TurboCell-TxRate TxRate-474k 474
+VALUE KarlNet-TurboCell-TxRate TxRate-475k 475
+VALUE KarlNet-TurboCell-TxRate TxRate-476k 476
+VALUE KarlNet-TurboCell-TxRate TxRate-477k 477
+VALUE KarlNet-TurboCell-TxRate TxRate-478k 478
+VALUE KarlNet-TurboCell-TxRate TxRate-479k 479
+VALUE KarlNet-TurboCell-TxRate TxRate-480k 480
+VALUE KarlNet-TurboCell-TxRate TxRate-481k 481
+VALUE KarlNet-TurboCell-TxRate TxRate-482k 482
+VALUE KarlNet-TurboCell-TxRate TxRate-483k 483
+VALUE KarlNet-TurboCell-TxRate TxRate-484k 484
+VALUE KarlNet-TurboCell-TxRate TxRate-485k 485
+VALUE KarlNet-TurboCell-TxRate TxRate-486k 486
+VALUE KarlNet-TurboCell-TxRate TxRate-487k 487
+VALUE KarlNet-TurboCell-TxRate TxRate-488k 488
+VALUE KarlNet-TurboCell-TxRate TxRate-489k 489
+VALUE KarlNet-TurboCell-TxRate TxRate-490k 490
+VALUE KarlNet-TurboCell-TxRate TxRate-491k 491
+VALUE KarlNet-TurboCell-TxRate TxRate-492k 492
+VALUE KarlNet-TurboCell-TxRate TxRate-493k 493
+VALUE KarlNet-TurboCell-TxRate TxRate-494k 494
+VALUE KarlNet-TurboCell-TxRate TxRate-495k 495
+VALUE KarlNet-TurboCell-TxRate TxRate-496k 496
+VALUE KarlNet-TurboCell-TxRate TxRate-497k 497
+VALUE KarlNet-TurboCell-TxRate TxRate-498k 498
+VALUE KarlNet-TurboCell-TxRate TxRate-499k 499
+VALUE KarlNet-TurboCell-TxRate TxRate-500k 500
+VALUE KarlNet-TurboCell-TxRate TxRate-501k 501
+VALUE KarlNet-TurboCell-TxRate TxRate-502k 502
+VALUE KarlNet-TurboCell-TxRate TxRate-503k 503
+VALUE KarlNet-TurboCell-TxRate TxRate-504k 504
+VALUE KarlNet-TurboCell-TxRate TxRate-505k 505
+VALUE KarlNet-TurboCell-TxRate TxRate-506k 506
+VALUE KarlNet-TurboCell-TxRate TxRate-507k 507
+VALUE KarlNet-TurboCell-TxRate TxRate-508k 508
+VALUE KarlNet-TurboCell-TxRate TxRate-509k 509
+VALUE KarlNet-TurboCell-TxRate TxRate-510k 510
+VALUE KarlNet-TurboCell-TxRate TxRate-511k 511
+VALUE KarlNet-TurboCell-TxRate TxRate-512k 512
+VALUE KarlNet-TurboCell-TxRate TxRate-513k 513
+VALUE KarlNet-TurboCell-TxRate TxRate-514k 514
+VALUE KarlNet-TurboCell-TxRate TxRate-515k 515
+VALUE KarlNet-TurboCell-TxRate TxRate-516k 516
+VALUE KarlNet-TurboCell-TxRate TxRate-517k 517
+VALUE KarlNet-TurboCell-TxRate TxRate-518k 518
+VALUE KarlNet-TurboCell-TxRate TxRate-519k 519
+VALUE KarlNet-TurboCell-TxRate TxRate-520k 520
+VALUE KarlNet-TurboCell-TxRate TxRate-521k 521
+VALUE KarlNet-TurboCell-TxRate TxRate-522k 522
+VALUE KarlNet-TurboCell-TxRate TxRate-523k 523
+VALUE KarlNet-TurboCell-TxRate TxRate-524k 524
+VALUE KarlNet-TurboCell-TxRate TxRate-525k 525
+VALUE KarlNet-TurboCell-TxRate TxRate-526k 526
+VALUE KarlNet-TurboCell-TxRate TxRate-527k 527
+VALUE KarlNet-TurboCell-TxRate TxRate-528k 528
+VALUE KarlNet-TurboCell-TxRate TxRate-529k 529
+VALUE KarlNet-TurboCell-TxRate TxRate-530k 530
+VALUE KarlNet-TurboCell-TxRate TxRate-531k 531
+VALUE KarlNet-TurboCell-TxRate TxRate-532k 532
+VALUE KarlNet-TurboCell-TxRate TxRate-533k 533
+VALUE KarlNet-TurboCell-TxRate TxRate-534k 534
+VALUE KarlNet-TurboCell-TxRate TxRate-535k 535
+VALUE KarlNet-TurboCell-TxRate TxRate-536k 536
+VALUE KarlNet-TurboCell-TxRate TxRate-537k 537
+VALUE KarlNet-TurboCell-TxRate TxRate-538k 538
+VALUE KarlNet-TurboCell-TxRate TxRate-539k 539
+VALUE KarlNet-TurboCell-TxRate TxRate-540k 540
+VALUE KarlNet-TurboCell-TxRate TxRate-541k 541
+VALUE KarlNet-TurboCell-TxRate TxRate-542k 542
+VALUE KarlNet-TurboCell-TxRate TxRate-543k 543
+VALUE KarlNet-TurboCell-TxRate TxRate-544k 544
+VALUE KarlNet-TurboCell-TxRate TxRate-545k 545
+VALUE KarlNet-TurboCell-TxRate TxRate-546k 546
+VALUE KarlNet-TurboCell-TxRate TxRate-547k 547
+VALUE KarlNet-TurboCell-TxRate TxRate-548k 548
+VALUE KarlNet-TurboCell-TxRate TxRate-549k 549
+VALUE KarlNet-TurboCell-TxRate TxRate-550k 550
+VALUE KarlNet-TurboCell-TxRate TxRate-551k 551
+VALUE KarlNet-TurboCell-TxRate TxRate-552k 552
+VALUE KarlNet-TurboCell-TxRate TxRate-553k 553
+VALUE KarlNet-TurboCell-TxRate TxRate-554k 554
+VALUE KarlNet-TurboCell-TxRate TxRate-555k 555
+VALUE KarlNet-TurboCell-TxRate TxRate-556k 556
+VALUE KarlNet-TurboCell-TxRate TxRate-557k 557
+VALUE KarlNet-TurboCell-TxRate TxRate-558k 558
+VALUE KarlNet-TurboCell-TxRate TxRate-559k 559
+VALUE KarlNet-TurboCell-TxRate TxRate-560k 560
+VALUE KarlNet-TurboCell-TxRate TxRate-561k 561
+VALUE KarlNet-TurboCell-TxRate TxRate-562k 562
+VALUE KarlNet-TurboCell-TxRate TxRate-563k 563
+VALUE KarlNet-TurboCell-TxRate TxRate-564k 564
+VALUE KarlNet-TurboCell-TxRate TxRate-565k 565
+VALUE KarlNet-TurboCell-TxRate TxRate-566k 566
+VALUE KarlNet-TurboCell-TxRate TxRate-567k 567
+VALUE KarlNet-TurboCell-TxRate TxRate-568k 568
+VALUE KarlNet-TurboCell-TxRate TxRate-569k 569
+VALUE KarlNet-TurboCell-TxRate TxRate-570k 570
+VALUE KarlNet-TurboCell-TxRate TxRate-571k 571
+VALUE KarlNet-TurboCell-TxRate TxRate-572k 572
+VALUE KarlNet-TurboCell-TxRate TxRate-573k 573
+VALUE KarlNet-TurboCell-TxRate TxRate-574k 574
+VALUE KarlNet-TurboCell-TxRate TxRate-575k 575
+VALUE KarlNet-TurboCell-TxRate TxRate-576k 576
+VALUE KarlNet-TurboCell-TxRate TxRate-577k 577
+VALUE KarlNet-TurboCell-TxRate TxRate-578k 578
+VALUE KarlNet-TurboCell-TxRate TxRate-579k 579
+VALUE KarlNet-TurboCell-TxRate TxRate-580k 580
+VALUE KarlNet-TurboCell-TxRate TxRate-581k 581
+VALUE KarlNet-TurboCell-TxRate TxRate-582k 582
+VALUE KarlNet-TurboCell-TxRate TxRate-583k 583
+VALUE KarlNet-TurboCell-TxRate TxRate-584k 584
+VALUE KarlNet-TurboCell-TxRate TxRate-585k 585
+VALUE KarlNet-TurboCell-TxRate TxRate-586k 586
+VALUE KarlNet-TurboCell-TxRate TxRate-587k 587
+VALUE KarlNet-TurboCell-TxRate TxRate-588k 588
+VALUE KarlNet-TurboCell-TxRate TxRate-589k 589
+VALUE KarlNet-TurboCell-TxRate TxRate-590k 590
+VALUE KarlNet-TurboCell-TxRate TxRate-591k 591
+VALUE KarlNet-TurboCell-TxRate TxRate-592k 592
+VALUE KarlNet-TurboCell-TxRate TxRate-593k 593
+VALUE KarlNet-TurboCell-TxRate TxRate-594k 594
+VALUE KarlNet-TurboCell-TxRate TxRate-595k 595
+VALUE KarlNet-TurboCell-TxRate TxRate-596k 596
+VALUE KarlNet-TurboCell-TxRate TxRate-597k 597
+VALUE KarlNet-TurboCell-TxRate TxRate-598k 598
+VALUE KarlNet-TurboCell-TxRate TxRate-599k 599
+VALUE KarlNet-TurboCell-TxRate TxRate-600k 600
+VALUE KarlNet-TurboCell-TxRate TxRate-601k 601
+VALUE KarlNet-TurboCell-TxRate TxRate-602k 602
+VALUE KarlNet-TurboCell-TxRate TxRate-603k 603
+VALUE KarlNet-TurboCell-TxRate TxRate-604k 604
+VALUE KarlNet-TurboCell-TxRate TxRate-605k 605
+VALUE KarlNet-TurboCell-TxRate TxRate-606k 606
+VALUE KarlNet-TurboCell-TxRate TxRate-607k 607
+VALUE KarlNet-TurboCell-TxRate TxRate-608k 608
+VALUE KarlNet-TurboCell-TxRate TxRate-609k 609
+VALUE KarlNet-TurboCell-TxRate TxRate-610k 610
+VALUE KarlNet-TurboCell-TxRate TxRate-611k 611
+VALUE KarlNet-TurboCell-TxRate TxRate-612k 612
+VALUE KarlNet-TurboCell-TxRate TxRate-613k 613
+VALUE KarlNet-TurboCell-TxRate TxRate-614k 614
+VALUE KarlNet-TurboCell-TxRate TxRate-615k 615
+VALUE KarlNet-TurboCell-TxRate TxRate-616k 616
+VALUE KarlNet-TurboCell-TxRate TxRate-617k 617
+VALUE KarlNet-TurboCell-TxRate TxRate-618k 618
+VALUE KarlNet-TurboCell-TxRate TxRate-619k 619
+VALUE KarlNet-TurboCell-TxRate TxRate-620k 620
+VALUE KarlNet-TurboCell-TxRate TxRate-621k 621
+VALUE KarlNet-TurboCell-TxRate TxRate-622k 622
+VALUE KarlNet-TurboCell-TxRate TxRate-623k 623
+VALUE KarlNet-TurboCell-TxRate TxRate-624k 624
+VALUE KarlNet-TurboCell-TxRate TxRate-625k 625
+VALUE KarlNet-TurboCell-TxRate TxRate-626k 626
+VALUE KarlNet-TurboCell-TxRate TxRate-627k 627
+VALUE KarlNet-TurboCell-TxRate TxRate-628k 628
+VALUE KarlNet-TurboCell-TxRate TxRate-629k 629
+VALUE KarlNet-TurboCell-TxRate TxRate-630k 630
+VALUE KarlNet-TurboCell-TxRate TxRate-631k 631
+VALUE KarlNet-TurboCell-TxRate TxRate-632k 632
+VALUE KarlNet-TurboCell-TxRate TxRate-633k 633
+VALUE KarlNet-TurboCell-TxRate TxRate-634k 634
+VALUE KarlNet-TurboCell-TxRate TxRate-635k 635
+VALUE KarlNet-TurboCell-TxRate TxRate-636k 636
+VALUE KarlNet-TurboCell-TxRate TxRate-637k 637
+VALUE KarlNet-TurboCell-TxRate TxRate-638k 638
+VALUE KarlNet-TurboCell-TxRate TxRate-639k 639
+VALUE KarlNet-TurboCell-TxRate TxRate-640k 640
+VALUE KarlNet-TurboCell-TxRate TxRate-641k 641
+VALUE KarlNet-TurboCell-TxRate TxRate-642k 642
+VALUE KarlNet-TurboCell-TxRate TxRate-643k 643
+VALUE KarlNet-TurboCell-TxRate TxRate-644k 644
+VALUE KarlNet-TurboCell-TxRate TxRate-645k 645
+VALUE KarlNet-TurboCell-TxRate TxRate-646k 646
+VALUE KarlNet-TurboCell-TxRate TxRate-647k 647
+VALUE KarlNet-TurboCell-TxRate TxRate-648k 648
+VALUE KarlNet-TurboCell-TxRate TxRate-649k 649
+VALUE KarlNet-TurboCell-TxRate TxRate-650k 650
+VALUE KarlNet-TurboCell-TxRate TxRate-651k 651
+VALUE KarlNet-TurboCell-TxRate TxRate-652k 652
+VALUE KarlNet-TurboCell-TxRate TxRate-653k 653
+VALUE KarlNet-TurboCell-TxRate TxRate-654k 654
+VALUE KarlNet-TurboCell-TxRate TxRate-655k 655
+VALUE KarlNet-TurboCell-TxRate TxRate-656k 656
+VALUE KarlNet-TurboCell-TxRate TxRate-657k 657
+VALUE KarlNet-TurboCell-TxRate TxRate-658k 658
+VALUE KarlNet-TurboCell-TxRate TxRate-659k 659
+VALUE KarlNet-TurboCell-TxRate TxRate-660k 660
+VALUE KarlNet-TurboCell-TxRate TxRate-661k 661
+VALUE KarlNet-TurboCell-TxRate TxRate-662k 662
+VALUE KarlNet-TurboCell-TxRate TxRate-663k 663
+VALUE KarlNet-TurboCell-TxRate TxRate-664k 664
+VALUE KarlNet-TurboCell-TxRate TxRate-665k 665
+VALUE KarlNet-TurboCell-TxRate TxRate-666k 666
+VALUE KarlNet-TurboCell-TxRate TxRate-667k 667
+VALUE KarlNet-TurboCell-TxRate TxRate-668k 668
+VALUE KarlNet-TurboCell-TxRate TxRate-669k 669
+VALUE KarlNet-TurboCell-TxRate TxRate-670k 670
+VALUE KarlNet-TurboCell-TxRate TxRate-671k 671
+VALUE KarlNet-TurboCell-TxRate TxRate-672k 672
+VALUE KarlNet-TurboCell-TxRate TxRate-673k 673
+VALUE KarlNet-TurboCell-TxRate TxRate-674k 674
+VALUE KarlNet-TurboCell-TxRate TxRate-675k 675
+VALUE KarlNet-TurboCell-TxRate TxRate-676k 676
+VALUE KarlNet-TurboCell-TxRate TxRate-677k 677
+VALUE KarlNet-TurboCell-TxRate TxRate-678k 678
+VALUE KarlNet-TurboCell-TxRate TxRate-679k 679
+VALUE KarlNet-TurboCell-TxRate TxRate-680k 680
+VALUE KarlNet-TurboCell-TxRate TxRate-681k 681
+VALUE KarlNet-TurboCell-TxRate TxRate-682k 682
+VALUE KarlNet-TurboCell-TxRate TxRate-683k 683
+VALUE KarlNet-TurboCell-TxRate TxRate-684k 684
+VALUE KarlNet-TurboCell-TxRate TxRate-685k 685
+VALUE KarlNet-TurboCell-TxRate TxRate-686k 686
+VALUE KarlNet-TurboCell-TxRate TxRate-687k 687
+VALUE KarlNet-TurboCell-TxRate TxRate-688k 688
+VALUE KarlNet-TurboCell-TxRate TxRate-689k 689
+VALUE KarlNet-TurboCell-TxRate TxRate-690k 690
+VALUE KarlNet-TurboCell-TxRate TxRate-691k 691
+VALUE KarlNet-TurboCell-TxRate TxRate-692k 692
+VALUE KarlNet-TurboCell-TxRate TxRate-693k 693
+VALUE KarlNet-TurboCell-TxRate TxRate-694k 694
+VALUE KarlNet-TurboCell-TxRate TxRate-695k 695
+VALUE KarlNet-TurboCell-TxRate TxRate-696k 696
+VALUE KarlNet-TurboCell-TxRate TxRate-697k 697
+VALUE KarlNet-TurboCell-TxRate TxRate-698k 698
+VALUE KarlNet-TurboCell-TxRate TxRate-699k 699
+VALUE KarlNet-TurboCell-TxRate TxRate-700k 700
+VALUE KarlNet-TurboCell-TxRate TxRate-701k 701
+VALUE KarlNet-TurboCell-TxRate TxRate-702k 702
+VALUE KarlNet-TurboCell-TxRate TxRate-703k 703
+VALUE KarlNet-TurboCell-TxRate TxRate-704k 704
+VALUE KarlNet-TurboCell-TxRate TxRate-705k 705
+VALUE KarlNet-TurboCell-TxRate TxRate-706k 706
+VALUE KarlNet-TurboCell-TxRate TxRate-707k 707
+VALUE KarlNet-TurboCell-TxRate TxRate-708k 708
+VALUE KarlNet-TurboCell-TxRate TxRate-709k 709
+VALUE KarlNet-TurboCell-TxRate TxRate-710k 710
+VALUE KarlNet-TurboCell-TxRate TxRate-711k 711
+VALUE KarlNet-TurboCell-TxRate TxRate-712k 712
+VALUE KarlNet-TurboCell-TxRate TxRate-713k 713
+VALUE KarlNet-TurboCell-TxRate TxRate-714k 714
+VALUE KarlNet-TurboCell-TxRate TxRate-715k 715
+VALUE KarlNet-TurboCell-TxRate TxRate-716k 716
+VALUE KarlNet-TurboCell-TxRate TxRate-717k 717
+VALUE KarlNet-TurboCell-TxRate TxRate-718k 718
+VALUE KarlNet-TurboCell-TxRate TxRate-719k 719
+VALUE KarlNet-TurboCell-TxRate TxRate-720k 720
+VALUE KarlNet-TurboCell-TxRate TxRate-721k 721
+VALUE KarlNet-TurboCell-TxRate TxRate-722k 722
+VALUE KarlNet-TurboCell-TxRate TxRate-723k 723
+VALUE KarlNet-TurboCell-TxRate TxRate-724k 724
+VALUE KarlNet-TurboCell-TxRate TxRate-725k 725
+VALUE KarlNet-TurboCell-TxRate TxRate-726k 726
+VALUE KarlNet-TurboCell-TxRate TxRate-727k 727
+VALUE KarlNet-TurboCell-TxRate TxRate-728k 728
+VALUE KarlNet-TurboCell-TxRate TxRate-729k 729
+VALUE KarlNet-TurboCell-TxRate TxRate-730k 730
+VALUE KarlNet-TurboCell-TxRate TxRate-731k 731
+VALUE KarlNet-TurboCell-TxRate TxRate-732k 732
+VALUE KarlNet-TurboCell-TxRate TxRate-733k 733
+VALUE KarlNet-TurboCell-TxRate TxRate-734k 734
+VALUE KarlNet-TurboCell-TxRate TxRate-735k 735
+VALUE KarlNet-TurboCell-TxRate TxRate-736k 736
+VALUE KarlNet-TurboCell-TxRate TxRate-737k 737
+VALUE KarlNet-TurboCell-TxRate TxRate-738k 738
+VALUE KarlNet-TurboCell-TxRate TxRate-739k 739
+VALUE KarlNet-TurboCell-TxRate TxRate-740k 740
+VALUE KarlNet-TurboCell-TxRate TxRate-741k 741
+VALUE KarlNet-TurboCell-TxRate TxRate-742k 742
+VALUE KarlNet-TurboCell-TxRate TxRate-743k 743
+VALUE KarlNet-TurboCell-TxRate TxRate-744k 744
+VALUE KarlNet-TurboCell-TxRate TxRate-745k 745
+VALUE KarlNet-TurboCell-TxRate TxRate-746k 746
+VALUE KarlNet-TurboCell-TxRate TxRate-747k 747
+VALUE KarlNet-TurboCell-TxRate TxRate-748k 748
+VALUE KarlNet-TurboCell-TxRate TxRate-749k 749
+VALUE KarlNet-TurboCell-TxRate TxRate-750k 750
+VALUE KarlNet-TurboCell-TxRate TxRate-751k 751
+VALUE KarlNet-TurboCell-TxRate TxRate-752k 752
+VALUE KarlNet-TurboCell-TxRate TxRate-753k 753
+VALUE KarlNet-TurboCell-TxRate TxRate-754k 754
+VALUE KarlNet-TurboCell-TxRate TxRate-755k 755
+VALUE KarlNet-TurboCell-TxRate TxRate-756k 756
+VALUE KarlNet-TurboCell-TxRate TxRate-757k 757
+VALUE KarlNet-TurboCell-TxRate TxRate-758k 758
+VALUE KarlNet-TurboCell-TxRate TxRate-759k 759
+VALUE KarlNet-TurboCell-TxRate TxRate-760k 760
+VALUE KarlNet-TurboCell-TxRate TxRate-761k 761
+VALUE KarlNet-TurboCell-TxRate TxRate-762k 762
+VALUE KarlNet-TurboCell-TxRate TxRate-763k 763
+VALUE KarlNet-TurboCell-TxRate TxRate-764k 764
+VALUE KarlNet-TurboCell-TxRate TxRate-765k 765
+VALUE KarlNet-TurboCell-TxRate TxRate-766k 766
+VALUE KarlNet-TurboCell-TxRate TxRate-767k 767
+VALUE KarlNet-TurboCell-TxRate TxRate-768k 768
+VALUE KarlNet-TurboCell-TxRate TxRate-769k 769
+VALUE KarlNet-TurboCell-TxRate TxRate-770k 770
+VALUE KarlNet-TurboCell-TxRate TxRate-771k 771
+VALUE KarlNet-TurboCell-TxRate TxRate-772k 772
+VALUE KarlNet-TurboCell-TxRate TxRate-773k 773
+VALUE KarlNet-TurboCell-TxRate TxRate-774k 774
+VALUE KarlNet-TurboCell-TxRate TxRate-775k 775
+VALUE KarlNet-TurboCell-TxRate TxRate-776k 776
+VALUE KarlNet-TurboCell-TxRate TxRate-777k 777
+VALUE KarlNet-TurboCell-TxRate TxRate-778k 778
+VALUE KarlNet-TurboCell-TxRate TxRate-779k 779
+VALUE KarlNet-TurboCell-TxRate TxRate-780k 780
+VALUE KarlNet-TurboCell-TxRate TxRate-781k 781
+VALUE KarlNet-TurboCell-TxRate TxRate-782k 782
+VALUE KarlNet-TurboCell-TxRate TxRate-783k 783
+VALUE KarlNet-TurboCell-TxRate TxRate-784k 784
+VALUE KarlNet-TurboCell-TxRate TxRate-785k 785
+VALUE KarlNet-TurboCell-TxRate TxRate-786k 786
+VALUE KarlNet-TurboCell-TxRate TxRate-787k 787
+VALUE KarlNet-TurboCell-TxRate TxRate-788k 788
+VALUE KarlNet-TurboCell-TxRate TxRate-789k 789
+VALUE KarlNet-TurboCell-TxRate TxRate-790k 790
+VALUE KarlNet-TurboCell-TxRate TxRate-791k 791
+VALUE KarlNet-TurboCell-TxRate TxRate-792k 792
+VALUE KarlNet-TurboCell-TxRate TxRate-793k 793
+VALUE KarlNet-TurboCell-TxRate TxRate-794k 794
+VALUE KarlNet-TurboCell-TxRate TxRate-795k 795
+VALUE KarlNet-TurboCell-TxRate TxRate-796k 796
+VALUE KarlNet-TurboCell-TxRate TxRate-797k 797
+VALUE KarlNet-TurboCell-TxRate TxRate-798k 798
+VALUE KarlNet-TurboCell-TxRate TxRate-799k 799
+VALUE KarlNet-TurboCell-TxRate TxRate-800k 800
+VALUE KarlNet-TurboCell-TxRate TxRate-801k 801
+VALUE KarlNet-TurboCell-TxRate TxRate-802k 802
+VALUE KarlNet-TurboCell-TxRate TxRate-803k 803
+VALUE KarlNet-TurboCell-TxRate TxRate-804k 804
+VALUE KarlNet-TurboCell-TxRate TxRate-805k 805
+VALUE KarlNet-TurboCell-TxRate TxRate-806k 806
+VALUE KarlNet-TurboCell-TxRate TxRate-807k 807
+VALUE KarlNet-TurboCell-TxRate TxRate-808k 808
+VALUE KarlNet-TurboCell-TxRate TxRate-809k 809
+VALUE KarlNet-TurboCell-TxRate TxRate-810k 810
+VALUE KarlNet-TurboCell-TxRate TxRate-811k 811
+VALUE KarlNet-TurboCell-TxRate TxRate-812k 812
+VALUE KarlNet-TurboCell-TxRate TxRate-813k 813
+VALUE KarlNet-TurboCell-TxRate TxRate-814k 814
+VALUE KarlNet-TurboCell-TxRate TxRate-815k 815
+VALUE KarlNet-TurboCell-TxRate TxRate-816k 816
+VALUE KarlNet-TurboCell-TxRate TxRate-817k 817
+VALUE KarlNet-TurboCell-TxRate TxRate-818k 818
+VALUE KarlNet-TurboCell-TxRate TxRate-819k 819
+VALUE KarlNet-TurboCell-TxRate TxRate-820k 820
+VALUE KarlNet-TurboCell-TxRate TxRate-821k 821
+VALUE KarlNet-TurboCell-TxRate TxRate-822k 822
+VALUE KarlNet-TurboCell-TxRate TxRate-823k 823
+VALUE KarlNet-TurboCell-TxRate TxRate-824k 824
+VALUE KarlNet-TurboCell-TxRate TxRate-825k 825
+VALUE KarlNet-TurboCell-TxRate TxRate-826k 826
+VALUE KarlNet-TurboCell-TxRate TxRate-827k 827
+VALUE KarlNet-TurboCell-TxRate TxRate-828k 828
+VALUE KarlNet-TurboCell-TxRate TxRate-829k 829
+VALUE KarlNet-TurboCell-TxRate TxRate-830k 830
+VALUE KarlNet-TurboCell-TxRate TxRate-831k 831
+VALUE KarlNet-TurboCell-TxRate TxRate-832k 832
+VALUE KarlNet-TurboCell-TxRate TxRate-833k 833
+VALUE KarlNet-TurboCell-TxRate TxRate-834k 834
+VALUE KarlNet-TurboCell-TxRate TxRate-835k 835
+VALUE KarlNet-TurboCell-TxRate TxRate-836k 836
+VALUE KarlNet-TurboCell-TxRate TxRate-837k 837
+VALUE KarlNet-TurboCell-TxRate TxRate-838k 838
+VALUE KarlNet-TurboCell-TxRate TxRate-839k 839
+VALUE KarlNet-TurboCell-TxRate TxRate-840k 840
+VALUE KarlNet-TurboCell-TxRate TxRate-841k 841
+VALUE KarlNet-TurboCell-TxRate TxRate-842k 842
+VALUE KarlNet-TurboCell-TxRate TxRate-843k 843
+VALUE KarlNet-TurboCell-TxRate TxRate-844k 844
+VALUE KarlNet-TurboCell-TxRate TxRate-845k 845
+VALUE KarlNet-TurboCell-TxRate TxRate-846k 846
+VALUE KarlNet-TurboCell-TxRate TxRate-847k 847
+VALUE KarlNet-TurboCell-TxRate TxRate-848k 848
+VALUE KarlNet-TurboCell-TxRate TxRate-849k 849
+VALUE KarlNet-TurboCell-TxRate TxRate-850k 850
+VALUE KarlNet-TurboCell-TxRate TxRate-851k 851
+VALUE KarlNet-TurboCell-TxRate TxRate-852k 852
+VALUE KarlNet-TurboCell-TxRate TxRate-853k 853
+VALUE KarlNet-TurboCell-TxRate TxRate-854k 854
+VALUE KarlNet-TurboCell-TxRate TxRate-855k 855
+VALUE KarlNet-TurboCell-TxRate TxRate-856k 856
+VALUE KarlNet-TurboCell-TxRate TxRate-857k 857
+VALUE KarlNet-TurboCell-TxRate TxRate-858k 858
+VALUE KarlNet-TurboCell-TxRate TxRate-859k 859
+VALUE KarlNet-TurboCell-TxRate TxRate-860k 860
+VALUE KarlNet-TurboCell-TxRate TxRate-861k 861
+VALUE KarlNet-TurboCell-TxRate TxRate-862k 862
+VALUE KarlNet-TurboCell-TxRate TxRate-863k 863
+VALUE KarlNet-TurboCell-TxRate TxRate-864k 864
+VALUE KarlNet-TurboCell-TxRate TxRate-865k 865
+VALUE KarlNet-TurboCell-TxRate TxRate-866k 866
+VALUE KarlNet-TurboCell-TxRate TxRate-867k 867
+VALUE KarlNet-TurboCell-TxRate TxRate-868k 868
+VALUE KarlNet-TurboCell-TxRate TxRate-869k 869
+VALUE KarlNet-TurboCell-TxRate TxRate-870k 870
+VALUE KarlNet-TurboCell-TxRate TxRate-871k 871
+VALUE KarlNet-TurboCell-TxRate TxRate-872k 872
+VALUE KarlNet-TurboCell-TxRate TxRate-873k 873
+VALUE KarlNet-TurboCell-TxRate TxRate-874k 874
+VALUE KarlNet-TurboCell-TxRate TxRate-875k 875
+VALUE KarlNet-TurboCell-TxRate TxRate-876k 876
+VALUE KarlNet-TurboCell-TxRate TxRate-877k 877
+VALUE KarlNet-TurboCell-TxRate TxRate-878k 878
+VALUE KarlNet-TurboCell-TxRate TxRate-879k 879
+VALUE KarlNet-TurboCell-TxRate TxRate-880k 880
+VALUE KarlNet-TurboCell-TxRate TxRate-881k 881
+VALUE KarlNet-TurboCell-TxRate TxRate-882k 882
+VALUE KarlNet-TurboCell-TxRate TxRate-883k 883
+VALUE KarlNet-TurboCell-TxRate TxRate-884k 884
+VALUE KarlNet-TurboCell-TxRate TxRate-885k 885
+VALUE KarlNet-TurboCell-TxRate TxRate-886k 886
+VALUE KarlNet-TurboCell-TxRate TxRate-887k 887
+VALUE KarlNet-TurboCell-TxRate TxRate-888k 888
+VALUE KarlNet-TurboCell-TxRate TxRate-889k 889
+VALUE KarlNet-TurboCell-TxRate TxRate-890k 890
+VALUE KarlNet-TurboCell-TxRate TxRate-891k 891
+VALUE KarlNet-TurboCell-TxRate TxRate-892k 892
+VALUE KarlNet-TurboCell-TxRate TxRate-893k 893
+VALUE KarlNet-TurboCell-TxRate TxRate-894k 894
+VALUE KarlNet-TurboCell-TxRate TxRate-895k 895
+VALUE KarlNet-TurboCell-TxRate TxRate-896k 896
+VALUE KarlNet-TurboCell-TxRate TxRate-897k 897
+VALUE KarlNet-TurboCell-TxRate TxRate-898k 898
+VALUE KarlNet-TurboCell-TxRate TxRate-899k 899
+VALUE KarlNet-TurboCell-TxRate TxRate-900k 900
+VALUE KarlNet-TurboCell-TxRate TxRate-901k 901
+VALUE KarlNet-TurboCell-TxRate TxRate-902k 902
+VALUE KarlNet-TurboCell-TxRate TxRate-903k 903
+VALUE KarlNet-TurboCell-TxRate TxRate-904k 904
+VALUE KarlNet-TurboCell-TxRate TxRate-905k 905
+VALUE KarlNet-TurboCell-TxRate TxRate-906k 906
+VALUE KarlNet-TurboCell-TxRate TxRate-907k 907
+VALUE KarlNet-TurboCell-TxRate TxRate-908k 908
+VALUE KarlNet-TurboCell-TxRate TxRate-909k 909
+VALUE KarlNet-TurboCell-TxRate TxRate-910k 910
+VALUE KarlNet-TurboCell-TxRate TxRate-911k 911
+VALUE KarlNet-TurboCell-TxRate TxRate-912k 912
+VALUE KarlNet-TurboCell-TxRate TxRate-913k 913
+VALUE KarlNet-TurboCell-TxRate TxRate-914k 914
+VALUE KarlNet-TurboCell-TxRate TxRate-915k 915
+VALUE KarlNet-TurboCell-TxRate TxRate-916k 916
+VALUE KarlNet-TurboCell-TxRate TxRate-917k 917
+VALUE KarlNet-TurboCell-TxRate TxRate-918k 918
+VALUE KarlNet-TurboCell-TxRate TxRate-919k 919
+VALUE KarlNet-TurboCell-TxRate TxRate-920k 920
+VALUE KarlNet-TurboCell-TxRate TxRate-921k 921
+VALUE KarlNet-TurboCell-TxRate TxRate-922k 922
+VALUE KarlNet-TurboCell-TxRate TxRate-923k 923
+VALUE KarlNet-TurboCell-TxRate TxRate-924k 924
+VALUE KarlNet-TurboCell-TxRate TxRate-925k 925
+VALUE KarlNet-TurboCell-TxRate TxRate-926k 926
+VALUE KarlNet-TurboCell-TxRate TxRate-927k 927
+VALUE KarlNet-TurboCell-TxRate TxRate-928k 928
+VALUE KarlNet-TurboCell-TxRate TxRate-929k 929
+VALUE KarlNet-TurboCell-TxRate TxRate-930k 930
+VALUE KarlNet-TurboCell-TxRate TxRate-931k 931
+VALUE KarlNet-TurboCell-TxRate TxRate-932k 932
+VALUE KarlNet-TurboCell-TxRate TxRate-933k 933
+VALUE KarlNet-TurboCell-TxRate TxRate-934k 934
+VALUE KarlNet-TurboCell-TxRate TxRate-935k 935
+VALUE KarlNet-TurboCell-TxRate TxRate-936k 936
+VALUE KarlNet-TurboCell-TxRate TxRate-937k 937
+VALUE KarlNet-TurboCell-TxRate TxRate-938k 938
+VALUE KarlNet-TurboCell-TxRate TxRate-939k 939
+VALUE KarlNet-TurboCell-TxRate TxRate-940k 940
+VALUE KarlNet-TurboCell-TxRate TxRate-941k 941
+VALUE KarlNet-TurboCell-TxRate TxRate-942k 942
+VALUE KarlNet-TurboCell-TxRate TxRate-943k 943
+VALUE KarlNet-TurboCell-TxRate TxRate-944k 944
+VALUE KarlNet-TurboCell-TxRate TxRate-945k 945
+VALUE KarlNet-TurboCell-TxRate TxRate-946k 946
+VALUE KarlNet-TurboCell-TxRate TxRate-947k 947
+VALUE KarlNet-TurboCell-TxRate TxRate-948k 948
+VALUE KarlNet-TurboCell-TxRate TxRate-949k 949
+VALUE KarlNet-TurboCell-TxRate TxRate-950k 950
+VALUE KarlNet-TurboCell-TxRate TxRate-951k 951
+VALUE KarlNet-TurboCell-TxRate TxRate-952k 952
+VALUE KarlNet-TurboCell-TxRate TxRate-953k 953
+VALUE KarlNet-TurboCell-TxRate TxRate-954k 954
+VALUE KarlNet-TurboCell-TxRate TxRate-955k 955
+VALUE KarlNet-TurboCell-TxRate TxRate-956k 956
+VALUE KarlNet-TurboCell-TxRate TxRate-957k 957
+VALUE KarlNet-TurboCell-TxRate TxRate-958k 958
+VALUE KarlNet-TurboCell-TxRate TxRate-959k 959
+VALUE KarlNet-TurboCell-TxRate TxRate-960k 960
+VALUE KarlNet-TurboCell-TxRate TxRate-961k 961
+VALUE KarlNet-TurboCell-TxRate TxRate-962k 962
+VALUE KarlNet-TurboCell-TxRate TxRate-963k 963
+VALUE KarlNet-TurboCell-TxRate TxRate-964k 964
+VALUE KarlNet-TurboCell-TxRate TxRate-965k 965
+VALUE KarlNet-TurboCell-TxRate TxRate-966k 966
+VALUE KarlNet-TurboCell-TxRate TxRate-967k 967
+VALUE KarlNet-TurboCell-TxRate TxRate-968k 968
+VALUE KarlNet-TurboCell-TxRate TxRate-969k 969
+VALUE KarlNet-TurboCell-TxRate TxRate-970k 970
+VALUE KarlNet-TurboCell-TxRate TxRate-971k 971
+VALUE KarlNet-TurboCell-TxRate TxRate-972k 972
+VALUE KarlNet-TurboCell-TxRate TxRate-973k 973
+VALUE KarlNet-TurboCell-TxRate TxRate-974k 974
+VALUE KarlNet-TurboCell-TxRate TxRate-975k 975
+VALUE KarlNet-TurboCell-TxRate TxRate-976k 976
+VALUE KarlNet-TurboCell-TxRate TxRate-977k 977
+VALUE KarlNet-TurboCell-TxRate TxRate-978k 978
+VALUE KarlNet-TurboCell-TxRate TxRate-979k 979
+VALUE KarlNet-TurboCell-TxRate TxRate-980k 980
+VALUE KarlNet-TurboCell-TxRate TxRate-981k 981
+VALUE KarlNet-TurboCell-TxRate TxRate-982k 982
+VALUE KarlNet-TurboCell-TxRate TxRate-983k 983
+VALUE KarlNet-TurboCell-TxRate TxRate-984k 984
+VALUE KarlNet-TurboCell-TxRate TxRate-985k 985
+VALUE KarlNet-TurboCell-TxRate TxRate-986k 986
+VALUE KarlNet-TurboCell-TxRate TxRate-987k 987
+VALUE KarlNet-TurboCell-TxRate TxRate-988k 988
+VALUE KarlNet-TurboCell-TxRate TxRate-989k 989
+VALUE KarlNet-TurboCell-TxRate TxRate-990k 990
+VALUE KarlNet-TurboCell-TxRate TxRate-991k 991
+VALUE KarlNet-TurboCell-TxRate TxRate-992k 992
+VALUE KarlNet-TurboCell-TxRate TxRate-993k 993
+VALUE KarlNet-TurboCell-TxRate TxRate-994k 994
+VALUE KarlNet-TurboCell-TxRate TxRate-995k 995
+VALUE KarlNet-TurboCell-TxRate TxRate-996k 996
+VALUE KarlNet-TurboCell-TxRate TxRate-997k 997
+VALUE KarlNet-TurboCell-TxRate TxRate-998k 998
+VALUE KarlNet-TurboCell-TxRate TxRate-999k 999
+VALUE KarlNet-TurboCell-TxRate TxRate-1000k 1000
+VALUE KarlNet-TurboCell-TxRate TxRate-1001k 1001
+VALUE KarlNet-TurboCell-TxRate TxRate-1002k 1002
+VALUE KarlNet-TurboCell-TxRate TxRate-1003k 1003
+VALUE KarlNet-TurboCell-TxRate TxRate-1004k 1004
+VALUE KarlNet-TurboCell-TxRate TxRate-1005k 1005
+VALUE KarlNet-TurboCell-TxRate TxRate-1006k 1006
+VALUE KarlNet-TurboCell-TxRate TxRate-1007k 1007
+VALUE KarlNet-TurboCell-TxRate TxRate-1008k 1008
+VALUE KarlNet-TurboCell-TxRate TxRate-1009k 1009
+VALUE KarlNet-TurboCell-TxRate TxRate-1010k 1010
+VALUE KarlNet-TurboCell-TxRate TxRate-1011k 1011
+VALUE KarlNet-TurboCell-TxRate TxRate-1012k 1012
+VALUE KarlNet-TurboCell-TxRate TxRate-1013k 1013
+VALUE KarlNet-TurboCell-TxRate TxRate-1014k 1014
+VALUE KarlNet-TurboCell-TxRate TxRate-1015k 1015
+VALUE KarlNet-TurboCell-TxRate TxRate-1016k 1016
+VALUE KarlNet-TurboCell-TxRate TxRate-1017k 1017
+VALUE KarlNet-TurboCell-TxRate TxRate-1018k 1018
+VALUE KarlNet-TurboCell-TxRate TxRate-1019k 1019
+VALUE KarlNet-TurboCell-TxRate TxRate-1020k 1020
+VALUE KarlNet-TurboCell-TxRate TxRate-1021k 1021
+VALUE KarlNet-TurboCell-TxRate TxRate-1022k 1022
+VALUE KarlNet-TurboCell-TxRate TxRate-1023k 1023
+VALUE KarlNet-TurboCell-TxRate TxRate-1024k 1024
+VALUE KarlNet-TurboCell-TxRate TxRate-1152k 1025
+VALUE KarlNet-TurboCell-TxRate TxRate-1280k 1026
+VALUE KarlNet-TurboCell-TxRate TxRate-1408k 1027
+VALUE KarlNet-TurboCell-TxRate TxRate-1536k 1028
+VALUE KarlNet-TurboCell-TxRate TxRate-1664k 1029
+VALUE KarlNet-TurboCell-TxRate TxRate-1792k 1030
+VALUE KarlNet-TurboCell-TxRate TxRate-1920k 1031
+VALUE KarlNet-TurboCell-TxRate TxRate-2048k 1032
+VALUE KarlNet-TurboCell-TxRate TxRate-2176k 1033
+VALUE KarlNet-TurboCell-TxRate TxRate-2304k 1034
+VALUE KarlNet-TurboCell-TxRate TxRate-2432k 1035
+VALUE KarlNet-TurboCell-TxRate TxRate-2560k 1036
+VALUE KarlNet-TurboCell-TxRate TxRate-2688k 1037
+VALUE KarlNet-TurboCell-TxRate TxRate-2816k 1038
+VALUE KarlNet-TurboCell-TxRate TxRate-2944k 1039
+VALUE KarlNet-TurboCell-TxRate TxRate-3072k 1040
+VALUE KarlNet-TurboCell-TxRate TxRate-3200k 1041
+VALUE KarlNet-TurboCell-TxRate TxRate-3328k 1042
+VALUE KarlNet-TurboCell-TxRate TxRate-3456k 1043
+VALUE KarlNet-TurboCell-TxRate TxRate-3584k 1044
+VALUE KarlNet-TurboCell-TxRate TxRate-3712k 1045
+VALUE KarlNet-TurboCell-TxRate TxRate-3840k 1046
+VALUE KarlNet-TurboCell-TxRate TxRate-3968k 1047
+VALUE KarlNet-TurboCell-TxRate TxRate-4096k 1048
+VALUE KarlNet-TurboCell-TxRate TxRate-4224k 1049
+VALUE KarlNet-TurboCell-TxRate TxRate-4352k 1050
+VALUE KarlNet-TurboCell-TxRate TxRate-4480k 1051
+VALUE KarlNet-TurboCell-TxRate TxRate-4608k 1052
+VALUE KarlNet-TurboCell-TxRate TxRate-4736k 1053
+VALUE KarlNet-TurboCell-TxRate TxRate-4864k 1054
+VALUE KarlNet-TurboCell-TxRate TxRate-4992k 1055
+VALUE KarlNet-TurboCell-TxRate TxRate-5120k 1056
+VALUE KarlNet-TurboCell-TxRate TxRate-5248k 1057
+VALUE KarlNet-TurboCell-TxRate TxRate-5376k 1058
+VALUE KarlNet-TurboCell-TxRate TxRate-5504k 1059
+VALUE KarlNet-TurboCell-TxRate TxRate-5632k 1060
+VALUE KarlNet-TurboCell-TxRate TxRate-5760k 1061
+VALUE KarlNet-TurboCell-TxRate TxRate-5888k 1062
+VALUE KarlNet-TurboCell-TxRate TxRate-6016k 1063
+VALUE KarlNet-TurboCell-TxRate TxRate-6144k 1064
+VALUE KarlNet-TurboCell-TxRate TxRate-6272k 1065
+VALUE KarlNet-TurboCell-TxRate TxRate-6400k 1066
+VALUE KarlNet-TurboCell-TxRate TxRate-6528k 1067
+VALUE KarlNet-TurboCell-TxRate TxRate-6656k 1068
+VALUE KarlNet-TurboCell-TxRate TxRate-6784k 1069
+VALUE KarlNet-TurboCell-TxRate TxRate-6912k 1070
+VALUE KarlNet-TurboCell-TxRate TxRate-7040k 1071
+VALUE KarlNet-TurboCell-TxRate TxRate-7168k 1072
+VALUE KarlNet-TurboCell-TxRate TxRate-7296k 1073
+VALUE KarlNet-TurboCell-TxRate TxRate-7424k 1074
+VALUE KarlNet-TurboCell-TxRate TxRate-7552k 1075
+VALUE KarlNet-TurboCell-TxRate TxRate-7680k 1076
+VALUE KarlNet-TurboCell-TxRate TxRate-7808k 1077
+VALUE KarlNet-TurboCell-TxRate TxRate-7936k 1078
+VALUE KarlNet-TurboCell-TxRate TxRate-8064k 1079
+VALUE KarlNet-TurboCell-TxRate TxRate-8192k 1080
+VALUE KarlNet-TurboCell-TxRate TxRate-8320k 1081
+VALUE KarlNet-TurboCell-TxRate TxRate-8448k 1082
+VALUE KarlNet-TurboCell-TxRate TxRate-8576k 1083
+VALUE KarlNet-TurboCell-TxRate TxRate-8704k 1084
+VALUE KarlNet-TurboCell-TxRate TxRate-8832k 1085
+VALUE KarlNet-TurboCell-TxRate TxRate-8960k 1086
+VALUE KarlNet-TurboCell-TxRate TxRate-9088k 1087
+VALUE KarlNet-TurboCell-TxRate TxRate-9216k 1088
+VALUE KarlNet-TurboCell-TxRate TxRate-9344k 1089
+VALUE KarlNet-TurboCell-TxRate TxRate-9472k 1090
+VALUE KarlNet-TurboCell-TxRate TxRate-9600k 1091
+VALUE KarlNet-TurboCell-TxRate TxRate-9728k 1092
+VALUE KarlNet-TurboCell-TxRate TxRate-9856k 1093
+VALUE KarlNet-TurboCell-TxRate TxRate-9984k 1094
+VALUE KarlNet-TurboCell-TxRate TxRate-10112k 1095
+VALUE KarlNet-TurboCell-TxRate TxRate-10240k 1096
+VALUE KarlNet-TurboCell-TxRate TxRate-10368k 1097
+VALUE KarlNet-TurboCell-TxRate TxRate-10496k 1098
+VALUE KarlNet-TurboCell-TxRate TxRate-10624k 1099
+VALUE KarlNet-TurboCell-TxRate TxRate-10752k 1100
+VALUE KarlNet-TurboCell-TxRate TxRate-10880k 1101
+VALUE KarlNet-TurboCell-TxRate TxRate-11008k 1102
+VALUE KarlNet-TurboCell-TxRate TxRate-11136k 1103
+VALUE KarlNet-TurboCell-TxRate TxRate-11264k 1104
+VALUE KarlNet-TurboCell-TxRate TxRate-11392k 1105
+VALUE KarlNet-TurboCell-TxRate TxRate-11520k 1106
+VALUE KarlNet-TurboCell-TxRate TxRate-11648k 1107
+VALUE KarlNet-TurboCell-TxRate TxRate-11776k 1108
+VALUE KarlNet-TurboCell-TxRate TxRate-11904k 1109
+VALUE KarlNet-TurboCell-TxRate TxRate-12032k 1110
+VALUE KarlNet-TurboCell-TxRate TxRate-12160k 1111
+VALUE KarlNet-TurboCell-TxRate TxRate-12288k 1112
+VALUE KarlNet-TurboCell-TxRate TxRate-12416k 1113
+VALUE KarlNet-TurboCell-TxRate TxRate-12544k 1114
+VALUE KarlNet-TurboCell-TxRate TxRate-12672k 1115
+VALUE KarlNet-TurboCell-TxRate TxRate-12800k 1116
+VALUE KarlNet-TurboCell-TxRate TxRate-12928k 1117
+VALUE KarlNet-TurboCell-TxRate TxRate-13056k 1118
+VALUE KarlNet-TurboCell-TxRate TxRate-13184k 1119
+VALUE KarlNet-TurboCell-TxRate TxRate-13312k 1120
+VALUE KarlNet-TurboCell-TxRate TxRate-13440k 1121
+VALUE KarlNet-TurboCell-TxRate TxRate-13568k 1122
+VALUE KarlNet-TurboCell-TxRate TxRate-13696k 1123
+VALUE KarlNet-TurboCell-TxRate TxRate-13824k 1124
+VALUE KarlNet-TurboCell-TxRate TxRate-13952k 1125
+VALUE KarlNet-TurboCell-TxRate TxRate-14080k 1126
+VALUE KarlNet-TurboCell-TxRate TxRate-14208k 1127
+VALUE KarlNet-TurboCell-TxRate TxRate-14336k 1128
+VALUE KarlNet-TurboCell-TxRate TxRate-14464k 1129
+VALUE KarlNet-TurboCell-TxRate TxRate-14592k 1130
+VALUE KarlNet-TurboCell-TxRate TxRate-14720k 1131
+VALUE KarlNet-TurboCell-TxRate TxRate-14848k 1132
+VALUE KarlNet-TurboCell-TxRate TxRate-14976k 1133
+VALUE KarlNet-TurboCell-TxRate TxRate-15104k 1134
+VALUE KarlNet-TurboCell-TxRate TxRate-15232k 1135
+VALUE KarlNet-TurboCell-TxRate TxRate-15360k 1136
+VALUE KarlNet-TurboCell-TxRate TxRate-15488k 1137
+VALUE KarlNet-TurboCell-TxRate TxRate-15616k 1138
+VALUE KarlNet-TurboCell-TxRate TxRate-15744k 1139
+VALUE KarlNet-TurboCell-TxRate TxRate-15872k 1140
+VALUE KarlNet-TurboCell-TxRate TxRate-16000k 1141
+VALUE KarlNet-TurboCell-TxRate TxRate-16128k 1142
+VALUE KarlNet-TurboCell-TxRate TxRate-16256k 1143
+VALUE KarlNet-TurboCell-TxRate TxRate-16384k 1144
+VALUE KarlNet-TurboCell-TxRate TxRate-16512k 1145
+VALUE KarlNet-TurboCell-TxRate TxRate-16640k 1146
+VALUE KarlNet-TurboCell-TxRate TxRate-16768k 1147
+VALUE KarlNet-TurboCell-TxRate TxRate-16896k 1148
+VALUE KarlNet-TurboCell-TxRate TxRate-17024k 1149
+VALUE KarlNet-TurboCell-TxRate TxRate-17152k 1150
+VALUE KarlNet-TurboCell-TxRate TxRate-17280k 1151
+VALUE KarlNet-TurboCell-TxRate TxRate-17408k 1152
+VALUE KarlNet-TurboCell-TxRate TxRate-17536k 1153
+VALUE KarlNet-TurboCell-TxRate TxRate-17664k 1154
+VALUE KarlNet-TurboCell-TxRate TxRate-17792k 1155
+VALUE KarlNet-TurboCell-TxRate TxRate-17920k 1156
+VALUE KarlNet-TurboCell-TxRate TxRate-18048k 1157
+VALUE KarlNet-TurboCell-TxRate TxRate-18176k 1158
+VALUE KarlNet-TurboCell-TxRate TxRate-18304k 1159
+VALUE KarlNet-TurboCell-TxRate TxRate-18432k 1160
+VALUE KarlNet-TurboCell-TxRate TxRate-18560k 1161
+VALUE KarlNet-TurboCell-TxRate TxRate-18688k 1162
+VALUE KarlNet-TurboCell-TxRate TxRate-18816k 1163
+VALUE KarlNet-TurboCell-TxRate TxRate-18944k 1164
+VALUE KarlNet-TurboCell-TxRate TxRate-19072k 1165
+VALUE KarlNet-TurboCell-TxRate TxRate-19200k 1166
+VALUE KarlNet-TurboCell-TxRate TxRate-19328k 1167
+VALUE KarlNet-TurboCell-TxRate TxRate-19456k 1168
+VALUE KarlNet-TurboCell-TxRate TxRate-19584k 1169
+VALUE KarlNet-TurboCell-TxRate TxRate-19712k 1170
+VALUE KarlNet-TurboCell-TxRate TxRate-19840k 1171
+VALUE KarlNet-TurboCell-TxRate TxRate-19968k 1172
+VALUE KarlNet-TurboCell-TxRate TxRate-20096k 1173
+VALUE KarlNet-TurboCell-TxRate TxRate-20224k 1174
+VALUE KarlNet-TurboCell-TxRate TxRate-20352k 1175
+VALUE KarlNet-TurboCell-TxRate TxRate-20480k 1176
+VALUE KarlNet-TurboCell-TxRate TxRate-20608k 1177
+VALUE KarlNet-TurboCell-TxRate TxRate-20736k 1178
+VALUE KarlNet-TurboCell-TxRate TxRate-20864k 1179
+VALUE KarlNet-TurboCell-TxRate TxRate-20992k 1180
+VALUE KarlNet-TurboCell-TxRate TxRate-21120k 1181
+VALUE KarlNet-TurboCell-TxRate TxRate-21248k 1182
+VALUE KarlNet-TurboCell-TxRate TxRate-21376k 1183
+VALUE KarlNet-TurboCell-TxRate TxRate-21504k 1184
+VALUE KarlNet-TurboCell-TxRate TxRate-21632k 1185
+VALUE KarlNet-TurboCell-TxRate TxRate-21760k 1186
+VALUE KarlNet-TurboCell-TxRate TxRate-21888k 1187
+VALUE KarlNet-TurboCell-TxRate TxRate-22016k 1188
+VALUE KarlNet-TurboCell-TxRate TxRate-22144k 1189
+VALUE KarlNet-TurboCell-TxRate TxRate-22272k 1190
+VALUE KarlNet-TurboCell-TxRate TxRate-22400k 1191
+VALUE KarlNet-TurboCell-TxRate TxRate-22528k 1192
+VALUE KarlNet-TurboCell-TxRate TxRate-22656k 1193
+VALUE KarlNet-TurboCell-TxRate TxRate-22784k 1194
+VALUE KarlNet-TurboCell-TxRate TxRate-22912k 1195
+VALUE KarlNet-TurboCell-TxRate TxRate-23040k 1196
+VALUE KarlNet-TurboCell-TxRate TxRate-23168k 1197
+VALUE KarlNet-TurboCell-TxRate TxRate-23296k 1198
+VALUE KarlNet-TurboCell-TxRate TxRate-23424k 1199
+VALUE KarlNet-TurboCell-TxRate TxRate-23552k 1200
+VALUE KarlNet-TurboCell-TxRate TxRate-23680k 1201
+VALUE KarlNet-TurboCell-TxRate TxRate-23808k 1202
+VALUE KarlNet-TurboCell-TxRate TxRate-23936k 1203
+VALUE KarlNet-TurboCell-TxRate TxRate-24064k 1204
+VALUE KarlNet-TurboCell-TxRate TxRate-24192k 1205
+VALUE KarlNet-TurboCell-TxRate TxRate-24320k 1206
+VALUE KarlNet-TurboCell-TxRate TxRate-24448k 1207
+VALUE KarlNet-TurboCell-TxRate TxRate-24576k 1208
+VALUE KarlNet-TurboCell-TxRate TxRate-24704k 1209
+VALUE KarlNet-TurboCell-TxRate TxRate-24832k 1210
+VALUE KarlNet-TurboCell-TxRate TxRate-24960k 1211
+VALUE KarlNet-TurboCell-TxRate TxRate-25088k 1212
+VALUE KarlNet-TurboCell-TxRate TxRate-25216k 1213
+VALUE KarlNet-TurboCell-TxRate TxRate-25344k 1214
+VALUE KarlNet-TurboCell-TxRate TxRate-25472k 1215
+VALUE KarlNet-TurboCell-TxRate TxRate-25600k 1216
+VALUE KarlNet-TurboCell-TxRate TxRate-25728k 1217
+VALUE KarlNet-TurboCell-TxRate TxRate-25856k 1218
+VALUE KarlNet-TurboCell-TxRate TxRate-25984k 1219
+VALUE KarlNet-TurboCell-TxRate TxRate-26112k 1220
+VALUE KarlNet-TurboCell-TxRate TxRate-26240k 1221
+VALUE KarlNet-TurboCell-TxRate TxRate-26368k 1222
+VALUE KarlNet-TurboCell-TxRate TxRate-26496k 1223
+VALUE KarlNet-TurboCell-TxRate TxRate-26624k 1224
+VALUE KarlNet-TurboCell-TxRate TxRate-26752k 1225
+VALUE KarlNet-TurboCell-TxRate TxRate-26880k 1226
+VALUE KarlNet-TurboCell-TxRate TxRate-27008k 1227
+VALUE KarlNet-TurboCell-TxRate TxRate-27136k 1228
+VALUE KarlNet-TurboCell-TxRate TxRate-27264k 1229
+VALUE KarlNet-TurboCell-TxRate TxRate-27392k 1230
+VALUE KarlNet-TurboCell-TxRate TxRate-27520k 1231
+VALUE KarlNet-TurboCell-TxRate TxRate-27648k 1232
+VALUE KarlNet-TurboCell-TxRate TxRate-27776k 1233
+VALUE KarlNet-TurboCell-TxRate TxRate-27904k 1234
+VALUE KarlNet-TurboCell-TxRate TxRate-28032k 1235
+VALUE KarlNet-TurboCell-TxRate TxRate-28160k 1236
+VALUE KarlNet-TurboCell-TxRate TxRate-28288k 1237
+VALUE KarlNet-TurboCell-TxRate TxRate-28416k 1238
+VALUE KarlNet-TurboCell-TxRate TxRate-28544k 1239
+VALUE KarlNet-TurboCell-TxRate TxRate-28672k 1240
+VALUE KarlNet-TurboCell-TxRate TxRate-28800k 1241
+VALUE KarlNet-TurboCell-TxRate TxRate-28928k 1242
+VALUE KarlNet-TurboCell-TxRate TxRate-29056k 1243
+VALUE KarlNet-TurboCell-TxRate TxRate-29184k 1244
+VALUE KarlNet-TurboCell-TxRate TxRate-29312k 1245
+VALUE KarlNet-TurboCell-TxRate TxRate-29440k 1246
+VALUE KarlNet-TurboCell-TxRate TxRate-29568k 1247
+VALUE KarlNet-TurboCell-TxRate TxRate-29696k 1248
+VALUE KarlNet-TurboCell-TxRate TxRate-29824k 1249
+VALUE KarlNet-TurboCell-TxRate TxRate-29952k 1250
+VALUE KarlNet-TurboCell-TxRate TxRate-30080k 1251
+VALUE KarlNet-TurboCell-TxRate TxRate-30208k 1252
+VALUE KarlNet-TurboCell-TxRate TxRate-30336k 1253
+VALUE KarlNet-TurboCell-TxRate TxRate-30464k 1254
+VALUE KarlNet-TurboCell-TxRate TxRate-30592k 1255
+VALUE KarlNet-TurboCell-TxRate TxRate-30720k 1256
+VALUE KarlNet-TurboCell-TxRate TxRate-30848k 1257
+VALUE KarlNet-TurboCell-TxRate TxRate-30976k 1258
+VALUE KarlNet-TurboCell-TxRate TxRate-31104k 1259
+VALUE KarlNet-TurboCell-TxRate TxRate-31232k 1260
+VALUE KarlNet-TurboCell-TxRate TxRate-31360k 1261
+VALUE KarlNet-TurboCell-TxRate TxRate-31488k 1262
+VALUE KarlNet-TurboCell-TxRate TxRate-31616k 1263
+VALUE KarlNet-TurboCell-TxRate TxRate-31744k 1264
+VALUE KarlNet-TurboCell-TxRate TxRate-31872k 1265
+VALUE KarlNet-TurboCell-TxRate TxRate-32000k 1266
+VALUE KarlNet-TurboCell-TxRate TxRate-32128k 1267
+VALUE KarlNet-TurboCell-TxRate TxRate-32256k 1268
+VALUE KarlNet-TurboCell-TxRate TxRate-32384k 1269
+VALUE KarlNet-TurboCell-TxRate TxRate-32512k 1270
+VALUE KarlNet-TurboCell-TxRate TxRate-32640k 1271
+VALUE KarlNet-TurboCell-TxRate TxRate-32768k 1272
+VALUE KarlNet-TurboCell-TxRate TxRate-32896k 1273
+VALUE KarlNet-TurboCell-TxRate TxRate-33024k 1274
+VALUE KarlNet-TurboCell-TxRate TxRate-33152k 1275
+VALUE KarlNet-TurboCell-TxRate TxRate-33280k 1276
+VALUE KarlNet-TurboCell-TxRate TxRate-33408k 1277
+VALUE KarlNet-TurboCell-TxRate TxRate-33536k 1278
+VALUE KarlNet-TurboCell-TxRate TxRate-33664k 1279
+VALUE KarlNet-TurboCell-TxRate TxRate-33792k 1280
+VALUE KarlNet-TurboCell-TxRate TxRate-33920k 1281
+VALUE KarlNet-TurboCell-TxRate TxRate-34048k 1282
+VALUE KarlNet-TurboCell-TxRate TxRate-34176k 1283
+VALUE KarlNet-TurboCell-TxRate TxRate-34304k 1284
+VALUE KarlNet-TurboCell-TxRate TxRate-34432k 1285
+VALUE KarlNet-TurboCell-TxRate TxRate-34560k 1286
+VALUE KarlNet-TurboCell-TxRate TxRate-34688k 1287
+VALUE KarlNet-TurboCell-TxRate TxRate-34816k 1288
+VALUE KarlNet-TurboCell-TxRate TxRate-34944k 1289
+VALUE KarlNet-TurboCell-TxRate TxRate-35072k 1290
+VALUE KarlNet-TurboCell-TxRate TxRate-35200k 1291
+VALUE KarlNet-TurboCell-TxRate TxRate-35328k 1292
+VALUE KarlNet-TurboCell-TxRate TxRate-35456k 1293
+VALUE KarlNet-TurboCell-TxRate TxRate-35584k 1294
+VALUE KarlNet-TurboCell-TxRate TxRate-35712k 1295
+VALUE KarlNet-TurboCell-TxRate TxRate-35840k 1296
+VALUE KarlNet-TurboCell-TxRate TxRate-35968k 1297
+VALUE KarlNet-TurboCell-TxRate TxRate-36096k 1298
+VALUE KarlNet-TurboCell-TxRate TxRate-36224k 1299
+VALUE KarlNet-TurboCell-TxRate TxRate-36352k 1300
+VALUE KarlNet-TurboCell-TxRate TxRate-36480k 1301
+VALUE KarlNet-TurboCell-TxRate TxRate-36608k 1302
+VALUE KarlNet-TurboCell-TxRate TxRate-36736k 1303
+VALUE KarlNet-TurboCell-TxRate TxRate-36864k 1304
+VALUE KarlNet-TurboCell-TxRate TxRate-36992k 1305
+VALUE KarlNet-TurboCell-TxRate TxRate-37120k 1306
+VALUE KarlNet-TurboCell-TxRate TxRate-37248k 1307
+VALUE KarlNet-TurboCell-TxRate TxRate-37376k 1308
+VALUE KarlNet-TurboCell-TxRate TxRate-37504k 1309
+VALUE KarlNet-TurboCell-TxRate TxRate-37632k 1310
+VALUE KarlNet-TurboCell-TxRate TxRate-37760k 1311
+VALUE KarlNet-TurboCell-TxRate TxRate-37888k 1312
+VALUE KarlNet-TurboCell-TxRate TxRate-38016k 1313
+VALUE KarlNet-TurboCell-TxRate TxRate-38144k 1314
+VALUE KarlNet-TurboCell-TxRate TxRate-38272k 1315
+VALUE KarlNet-TurboCell-TxRate TxRate-38400k 1316
+VALUE KarlNet-TurboCell-TxRate TxRate-38528k 1317
+VALUE KarlNet-TurboCell-TxRate TxRate-38656k 1318
+VALUE KarlNet-TurboCell-TxRate TxRate-38784k 1319
+VALUE KarlNet-TurboCell-TxRate TxRate-38912k 1320
+VALUE KarlNet-TurboCell-TxRate TxRate-39040k 1321
+VALUE KarlNet-TurboCell-TxRate TxRate-39168k 1322
+VALUE KarlNet-TurboCell-TxRate TxRate-39296k 1323
+VALUE KarlNet-TurboCell-TxRate TxRate-39424k 1324
+VALUE KarlNet-TurboCell-TxRate TxRate-39552k 1325
+VALUE KarlNet-TurboCell-TxRate TxRate-39680k 1326
+VALUE KarlNet-TurboCell-TxRate TxRate-39808k 1327
+VALUE KarlNet-TurboCell-TxRate TxRate-39936k 1328
+VALUE KarlNet-TurboCell-TxRate TxRate-40064k 1329
+VALUE KarlNet-TurboCell-TxRate TxRate-40192k 1330
+VALUE KarlNet-TurboCell-TxRate TxRate-40320k 1331
+VALUE KarlNet-TurboCell-TxRate TxRate-40448k 1332
+VALUE KarlNet-TurboCell-TxRate TxRate-40576k 1333
+VALUE KarlNet-TurboCell-TxRate TxRate-40704k 1334
+VALUE KarlNet-TurboCell-TxRate TxRate-40832k 1335
+VALUE KarlNet-TurboCell-TxRate TxRate-40960k 1336
+VALUE KarlNet-TurboCell-TxRate TxRate-41088k 1337
+VALUE KarlNet-TurboCell-TxRate TxRate-41216k 1338
+VALUE KarlNet-TurboCell-TxRate TxRate-41344k 1339
+VALUE KarlNet-TurboCell-TxRate TxRate-41472k 1340
+VALUE KarlNet-TurboCell-TxRate TxRate-41600k 1341
+VALUE KarlNet-TurboCell-TxRate TxRate-41728k 1342
+VALUE KarlNet-TurboCell-TxRate TxRate-41856k 1343
+VALUE KarlNet-TurboCell-TxRate TxRate-41984k 1344
+VALUE KarlNet-TurboCell-TxRate TxRate-42112k 1345
+VALUE KarlNet-TurboCell-TxRate TxRate-42240k 1346
+VALUE KarlNet-TurboCell-TxRate TxRate-42368k 1347
+VALUE KarlNet-TurboCell-TxRate TxRate-42496k 1348
+VALUE KarlNet-TurboCell-TxRate TxRate-42624k 1349
+VALUE KarlNet-TurboCell-TxRate TxRate-42752k 1350
+VALUE KarlNet-TurboCell-TxRate TxRate-42880k 1351
+VALUE KarlNet-TurboCell-TxRate TxRate-43008k 1352
+VALUE KarlNet-TurboCell-TxRate TxRate-43136k 1353
+VALUE KarlNet-TurboCell-TxRate TxRate-43264k 1354
+VALUE KarlNet-TurboCell-TxRate TxRate-43392k 1355
+VALUE KarlNet-TurboCell-TxRate TxRate-43520k 1356
+VALUE KarlNet-TurboCell-TxRate TxRate-43648k 1357
+VALUE KarlNet-TurboCell-TxRate TxRate-43776k 1358
+VALUE KarlNet-TurboCell-TxRate TxRate-43904k 1359
+VALUE KarlNet-TurboCell-TxRate TxRate-44032k 1360
+VALUE KarlNet-TurboCell-TxRate TxRate-44160k 1361
+VALUE KarlNet-TurboCell-TxRate TxRate-44288k 1362
+VALUE KarlNet-TurboCell-TxRate TxRate-44416k 1363
+VALUE KarlNet-TurboCell-TxRate TxRate-44544k 1364
+VALUE KarlNet-TurboCell-TxRate TxRate-44672k 1365
+VALUE KarlNet-TurboCell-TxRate TxRate-44800k 1366
+VALUE KarlNet-TurboCell-TxRate TxRate-44928k 1367
+VALUE KarlNet-TurboCell-TxRate TxRate-45056k 1368
+VALUE KarlNet-TurboCell-TxRate TxRate-45184k 1369
+VALUE KarlNet-TurboCell-TxRate TxRate-45312k 1370
+VALUE KarlNet-TurboCell-TxRate TxRate-45440k 1371
+VALUE KarlNet-TurboCell-TxRate TxRate-45568k 1372
+VALUE KarlNet-TurboCell-TxRate TxRate-45696k 1373
+VALUE KarlNet-TurboCell-TxRate TxRate-45824k 1374
+VALUE KarlNet-TurboCell-TxRate TxRate-45952k 1375
+VALUE KarlNet-TurboCell-TxRate TxRate-46080k 1376
+VALUE KarlNet-TurboCell-TxRate TxRate-46208k 1377
+VALUE KarlNet-TurboCell-TxRate TxRate-46336k 1378
+VALUE KarlNet-TurboCell-TxRate TxRate-46464k 1379
+VALUE KarlNet-TurboCell-TxRate TxRate-46592k 1380
+VALUE KarlNet-TurboCell-TxRate TxRate-46720k 1381
+VALUE KarlNet-TurboCell-TxRate TxRate-46848k 1382
+VALUE KarlNet-TurboCell-TxRate TxRate-46976k 1383
+VALUE KarlNet-TurboCell-TxRate TxRate-47104k 1384
+VALUE KarlNet-TurboCell-TxRate TxRate-47232k 1385
+VALUE KarlNet-TurboCell-TxRate TxRate-47360k 1386
+VALUE KarlNet-TurboCell-TxRate TxRate-47488k 1387
+VALUE KarlNet-TurboCell-TxRate TxRate-47616k 1388
+VALUE KarlNet-TurboCell-TxRate TxRate-47744k 1389
+VALUE KarlNet-TurboCell-TxRate TxRate-47872k 1390
+VALUE KarlNet-TurboCell-TxRate TxRate-48000k 1391
+VALUE KarlNet-TurboCell-TxRate TxRate-48128k 1392
+VALUE KarlNet-TurboCell-TxRate TxRate-48256k 1393
+VALUE KarlNet-TurboCell-TxRate TxRate-48384k 1394
+VALUE KarlNet-TurboCell-TxRate TxRate-48512k 1395
+VALUE KarlNet-TurboCell-TxRate TxRate-48640k 1396
+VALUE KarlNet-TurboCell-TxRate TxRate-48768k 1397
+VALUE KarlNet-TurboCell-TxRate TxRate-48896k 1398
+VALUE KarlNet-TurboCell-TxRate TxRate-49024k 1399
+VALUE KarlNet-TurboCell-TxRate TxRate-49152k 1400
+VALUE KarlNet-TurboCell-TxRate TxRate-49280k 1401
+VALUE KarlNet-TurboCell-TxRate TxRate-49408k 1402
+VALUE KarlNet-TurboCell-TxRate TxRate-49536k 1403
+VALUE KarlNet-TurboCell-TxRate TxRate-49664k 1404
+VALUE KarlNet-TurboCell-TxRate TxRate-49792k 1405
+VALUE KarlNet-TurboCell-TxRate TxRate-49920k 1406
+VALUE KarlNet-TurboCell-TxRate TxRate-50048k 1407
+VALUE KarlNet-TurboCell-TxRate TxRate-50176k 1408
+VALUE KarlNet-TurboCell-TxRate TxRate-50304k 1409
+VALUE KarlNet-TurboCell-TxRate TxRate-50432k 1410
+VALUE KarlNet-TurboCell-TxRate TxRate-50560k 1411
+VALUE KarlNet-TurboCell-TxRate TxRate-50688k 1412
+VALUE KarlNet-TurboCell-TxRate TxRate-50816k 1413
+VALUE KarlNet-TurboCell-TxRate TxRate-50944k 1414
+VALUE KarlNet-TurboCell-TxRate TxRate-51072k 1415
+VALUE KarlNet-TurboCell-TxRate TxRate-51200k 1416
+VALUE KarlNet-TurboCell-TxRate TxRate-51328k 1417
+VALUE KarlNet-TurboCell-TxRate TxRate-51456k 1418
+VALUE KarlNet-TurboCell-TxRate TxRate-51584k 1419
+VALUE KarlNet-TurboCell-TxRate TxRate-51712k 1420
+VALUE KarlNet-TurboCell-TxRate TxRate-51840k 1421
+VALUE KarlNet-TurboCell-TxRate TxRate-51968k 1422
+VALUE KarlNet-TurboCell-TxRate TxRate-52096k 1423
+VALUE KarlNet-TurboCell-TxRate TxRate-52224k 1424
+VALUE KarlNet-TurboCell-TxRate TxRate-52352k 1425
+VALUE KarlNet-TurboCell-TxRate TxRate-52480k 1426
+VALUE KarlNet-TurboCell-TxRate TxRate-52608k 1427
+VALUE KarlNet-TurboCell-TxRate TxRate-52736k 1428
+VALUE KarlNet-TurboCell-TxRate TxRate-52864k 1429
+VALUE KarlNet-TurboCell-TxRate TxRate-52992k 1430
+VALUE KarlNet-TurboCell-TxRate TxRate-53120k 1431
+VALUE KarlNet-TurboCell-TxRate TxRate-53248k 1432
+VALUE KarlNet-TurboCell-TxRate TxRate-53376k 1433
+VALUE KarlNet-TurboCell-TxRate TxRate-53504k 1434
+VALUE KarlNet-TurboCell-TxRate TxRate-53632k 1435
+VALUE KarlNet-TurboCell-TxRate TxRate-53760k 1436
+VALUE KarlNet-TurboCell-TxRate TxRate-53888k 1437
+VALUE KarlNet-TurboCell-TxRate TxRate-54016k 1438
+VALUE KarlNet-TurboCell-TxRate TxRate-54144k 1439
+VALUE KarlNet-TurboCell-TxRate TxRate-54272k 1440
+VALUE KarlNet-TurboCell-TxRate TxRate-54400k 1441
+VALUE KarlNet-TurboCell-TxRate TxRate-54528k 1442
+VALUE KarlNet-TurboCell-TxRate TxRate-54656k 1443
+VALUE KarlNet-TurboCell-TxRate TxRate-54784k 1444
+VALUE KarlNet-TurboCell-TxRate TxRate-54912k 1445
+VALUE KarlNet-TurboCell-TxRate TxRate-55040k 1446
+VALUE KarlNet-TurboCell-TxRate TxRate-55168k 1447
+VALUE KarlNet-TurboCell-TxRate TxRate-55296k 1448
+VALUE KarlNet-TurboCell-TxRate TxRate-55424k 1449
+VALUE KarlNet-TurboCell-TxRate TxRate-55552k 1450
+VALUE KarlNet-TurboCell-TxRate TxRate-55680k 1451
+VALUE KarlNet-TurboCell-TxRate TxRate-55808k 1452
+VALUE KarlNet-TurboCell-TxRate TxRate-55936k 1453
+VALUE KarlNet-TurboCell-TxRate TxRate-56064k 1454
+VALUE KarlNet-TurboCell-TxRate TxRate-56192k 1455
+VALUE KarlNet-TurboCell-TxRate TxRate-56320k 1456
+VALUE KarlNet-TurboCell-TxRate TxRate-56448k 1457
+VALUE KarlNet-TurboCell-TxRate TxRate-56576k 1458
+VALUE KarlNet-TurboCell-TxRate TxRate-56704k 1459
+VALUE KarlNet-TurboCell-TxRate TxRate-56832k 1460
+VALUE KarlNet-TurboCell-TxRate TxRate-56960k 1461
+VALUE KarlNet-TurboCell-TxRate TxRate-57088k 1462
+VALUE KarlNet-TurboCell-TxRate TxRate-57216k 1463
+VALUE KarlNet-TurboCell-TxRate TxRate-57344k 1464
+VALUE KarlNet-TurboCell-TxRate TxRate-57472k 1465
+VALUE KarlNet-TurboCell-TxRate TxRate-57600k 1466
+VALUE KarlNet-TurboCell-TxRate TxRate-57728k 1467
+VALUE KarlNet-TurboCell-TxRate TxRate-57856k 1468
+VALUE KarlNet-TurboCell-TxRate TxRate-57984k 1469
+VALUE KarlNet-TurboCell-TxRate TxRate-58112k 1470
+VALUE KarlNet-TurboCell-TxRate TxRate-58240k 1471
+VALUE KarlNet-TurboCell-TxRate TxRate-58368k 1472
+VALUE KarlNet-TurboCell-TxRate TxRate-58496k 1473
+VALUE KarlNet-TurboCell-TxRate TxRate-58624k 1474
+VALUE KarlNet-TurboCell-TxRate TxRate-58752k 1475
+VALUE KarlNet-TurboCell-TxRate TxRate-58880k 1476
+VALUE KarlNet-TurboCell-TxRate TxRate-59008k 1477
+VALUE KarlNet-TurboCell-TxRate TxRate-59136k 1478
+VALUE KarlNet-TurboCell-TxRate TxRate-59264k 1479
+VALUE KarlNet-TurboCell-TxRate TxRate-59392k 1480
+VALUE KarlNet-TurboCell-TxRate TxRate-59520k 1481
+VALUE KarlNet-TurboCell-TxRate TxRate-59648k 1482
+VALUE KarlNet-TurboCell-TxRate TxRate-59776k 1483
+VALUE KarlNet-TurboCell-TxRate TxRate-59904k 1484
+VALUE KarlNet-TurboCell-TxRate TxRate-60032k 1485
+VALUE KarlNet-TurboCell-TxRate TxRate-60160k 1486
+VALUE KarlNet-TurboCell-TxRate TxRate-60288k 1487
+VALUE KarlNet-TurboCell-TxRate TxRate-60416k 1488
+VALUE KarlNet-TurboCell-TxRate TxRate-60544k 1489
+VALUE KarlNet-TurboCell-TxRate TxRate-60672k 1490
+VALUE KarlNet-TurboCell-TxRate TxRate-60800k 1491
+VALUE KarlNet-TurboCell-TxRate TxRate-60928k 1492
+VALUE KarlNet-TurboCell-TxRate TxRate-61056k 1493
+VALUE KarlNet-TurboCell-TxRate TxRate-61184k 1494
+VALUE KarlNet-TurboCell-TxRate TxRate-61312k 1495
+VALUE KarlNet-TurboCell-TxRate TxRate-61440k 1496
+VALUE KarlNet-TurboCell-TxRate TxRate-61568k 1497
+VALUE KarlNet-TurboCell-TxRate TxRate-61696k 1498
+VALUE KarlNet-TurboCell-TxRate TxRate-61824k 1499
+VALUE KarlNet-TurboCell-TxRate TxRate-61952k 1500
+VALUE KarlNet-TurboCell-TxRate TxRate-62080k 1501
+VALUE KarlNet-TurboCell-TxRate TxRate-62208k 1502
+VALUE KarlNet-TurboCell-TxRate TxRate-62336k 1503
+VALUE KarlNet-TurboCell-TxRate TxRate-62464k 1504
+VALUE KarlNet-TurboCell-TxRate TxRate-62592k 1505
+VALUE KarlNet-TurboCell-TxRate TxRate-62720k 1506
+VALUE KarlNet-TurboCell-TxRate TxRate-62848k 1507
+VALUE KarlNet-TurboCell-TxRate TxRate-62976k 1508
+VALUE KarlNet-TurboCell-TxRate TxRate-63104k 1509
+VALUE KarlNet-TurboCell-TxRate TxRate-63232k 1510
+VALUE KarlNet-TurboCell-TxRate TxRate-63360k 1511
+VALUE KarlNet-TurboCell-TxRate TxRate-63488k 1512
+VALUE KarlNet-TurboCell-TxRate TxRate-63616k 1513
+VALUE KarlNet-TurboCell-TxRate TxRate-63744k 1514
+VALUE KarlNet-TurboCell-TxRate TxRate-63872k 1515
+VALUE KarlNet-TurboCell-TxRate TxRate-64000k 1516
+VALUE KarlNet-TurboCell-TxRate TxRate-64128k 1517
+VALUE KarlNet-TurboCell-TxRate TxRate-64256k 1518
+VALUE KarlNet-TurboCell-TxRate TxRate-64384k 1519
+VALUE KarlNet-TurboCell-TxRate TxRate-64512k 1520
+VALUE KarlNet-TurboCell-TxRate TxRate-64640k 1521
+VALUE KarlNet-TurboCell-TxRate TxRate-64768k 1522
+VALUE KarlNet-TurboCell-TxRate TxRate-64896k 1523
+VALUE KarlNet-TurboCell-TxRate TxRate-65024k 1524
+VALUE KarlNet-TurboCell-TxRate TxRate-65152k 1525
+VALUE KarlNet-TurboCell-TxRate TxRate-65280k 1526
+VALUE KarlNet-TurboCell-TxRate TxRate-65408k 1527
+VALUE KarlNet-TurboCell-TxRate TxRate-65536k 1528
+VALUE KarlNet-TurboCell-TxRate TxRate-65664k 1529
+VALUE KarlNet-TurboCell-TxRate TxRate-65792k 1530
+VALUE KarlNet-TurboCell-TxRate TxRate-65920k 1531
+VALUE KarlNet-TurboCell-TxRate TxRate-66048k 1532
+VALUE KarlNet-TurboCell-TxRate TxRate-66176k 1533
+VALUE KarlNet-TurboCell-TxRate TxRate-66304k 1534
+VALUE KarlNet-TurboCell-TxRate TxRate-66432k 1535
+VALUE KarlNet-TurboCell-TxRate TxRate-66560k 1536
+VALUE KarlNet-TurboCell-TxRate TxRate-66688k 1537
+VALUE KarlNet-TurboCell-TxRate TxRate-66816k 1538
+VALUE KarlNet-TurboCell-TxRate TxRate-66944k 1539
+VALUE KarlNet-TurboCell-TxRate TxRate-67072k 1540
+VALUE KarlNet-TurboCell-TxRate TxRate-67200k 1541
+VALUE KarlNet-TurboCell-TxRate TxRate-67328k 1542
+VALUE KarlNet-TurboCell-TxRate TxRate-67456k 1543
+VALUE KarlNet-TurboCell-TxRate TxRate-67584k 1544
+VALUE KarlNet-TurboCell-TxRate TxRate-67712k 1545
+VALUE KarlNet-TurboCell-TxRate TxRate-67840k 1546
+VALUE KarlNet-TurboCell-TxRate TxRate-67968k 1547
+VALUE KarlNet-TurboCell-TxRate TxRate-68096k 1548
+VALUE KarlNet-TurboCell-TxRate TxRate-68224k 1549
+VALUE KarlNet-TurboCell-TxRate TxRate-68352k 1550
+VALUE KarlNet-TurboCell-TxRate TxRate-68480k 1551
+VALUE KarlNet-TurboCell-TxRate TxRate-68608k 1552
+VALUE KarlNet-TurboCell-TxRate TxRate-68736k 1553
+VALUE KarlNet-TurboCell-TxRate TxRate-68864k 1554
+VALUE KarlNet-TurboCell-TxRate TxRate-68992k 1555
+VALUE KarlNet-TurboCell-TxRate TxRate-69120k 1556
+VALUE KarlNet-TurboCell-TxRate TxRate-69248k 1557
+VALUE KarlNet-TurboCell-TxRate TxRate-69376k 1558
+VALUE KarlNet-TurboCell-TxRate TxRate-69504k 1559
+VALUE KarlNet-TurboCell-TxRate TxRate-69632k 1560
+VALUE KarlNet-TurboCell-TxRate TxRate-69760k 1561
+VALUE KarlNet-TurboCell-TxRate TxRate-69888k 1562
+VALUE KarlNet-TurboCell-TxRate TxRate-70016k 1563
+VALUE KarlNet-TurboCell-TxRate TxRate-70144k 1564
+VALUE KarlNet-TurboCell-TxRate TxRate-70272k 1565
+VALUE KarlNet-TurboCell-TxRate TxRate-70400k 1566
+VALUE KarlNet-TurboCell-TxRate TxRate-70528k 1567
+VALUE KarlNet-TurboCell-TxRate TxRate-70656k 1568
+VALUE KarlNet-TurboCell-TxRate TxRate-70784k 1569
+VALUE KarlNet-TurboCell-TxRate TxRate-70912k 1570
+VALUE KarlNet-TurboCell-TxRate TxRate-71040k 1571
+VALUE KarlNet-TurboCell-TxRate TxRate-71168k 1572
+VALUE KarlNet-TurboCell-TxRate TxRate-71296k 1573
+VALUE KarlNet-TurboCell-TxRate TxRate-71424k 1574
+VALUE KarlNet-TurboCell-TxRate TxRate-71552k 1575
+VALUE KarlNet-TurboCell-TxRate TxRate-71680k 1576
+VALUE KarlNet-TurboCell-TxRate TxRate-71808k 1577
+VALUE KarlNet-TurboCell-TxRate TxRate-71936k 1578
+VALUE KarlNet-TurboCell-TxRate TxRate-72064k 1579
+VALUE KarlNet-TurboCell-TxRate TxRate-72192k 1580
+VALUE KarlNet-TurboCell-TxRate TxRate-72320k 1581
+VALUE KarlNet-TurboCell-TxRate TxRate-72448k 1582
+VALUE KarlNet-TurboCell-TxRate TxRate-72576k 1583
+VALUE KarlNet-TurboCell-TxRate TxRate-72704k 1584
+VALUE KarlNet-TurboCell-TxRate TxRate-72832k 1585
+VALUE KarlNet-TurboCell-TxRate TxRate-72960k 1586
+VALUE KarlNet-TurboCell-TxRate TxRate-73088k 1587
+VALUE KarlNet-TurboCell-TxRate TxRate-73216k 1588
+VALUE KarlNet-TurboCell-TxRate TxRate-73344k 1589
+VALUE KarlNet-TurboCell-TxRate TxRate-73472k 1590
+VALUE KarlNet-TurboCell-TxRate TxRate-73600k 1591
+VALUE KarlNet-TurboCell-TxRate TxRate-73728k 1592
+VALUE KarlNet-TurboCell-TxRate TxRate-73856k 1593
+VALUE KarlNet-TurboCell-TxRate TxRate-73984k 1594
+VALUE KarlNet-TurboCell-TxRate TxRate-74112k 1595
+VALUE KarlNet-TurboCell-TxRate TxRate-74240k 1596
+VALUE KarlNet-TurboCell-TxRate TxRate-74368k 1597
+VALUE KarlNet-TurboCell-TxRate TxRate-74496k 1598
+VALUE KarlNet-TurboCell-TxRate TxRate-74624k 1599
+VALUE KarlNet-TurboCell-TxRate TxRate-74752k 1600
+VALUE KarlNet-TurboCell-TxRate TxRate-74880k 1601
+VALUE KarlNet-TurboCell-TxRate TxRate-75008k 1602
+VALUE KarlNet-TurboCell-TxRate TxRate-75136k 1603
+VALUE KarlNet-TurboCell-TxRate TxRate-75264k 1604
+VALUE KarlNet-TurboCell-TxRate TxRate-75392k 1605
+VALUE KarlNet-TurboCell-TxRate TxRate-75520k 1606
+VALUE KarlNet-TurboCell-TxRate TxRate-75648k 1607
+VALUE KarlNet-TurboCell-TxRate TxRate-75776k 1608
+VALUE KarlNet-TurboCell-TxRate TxRate-75904k 1609
+VALUE KarlNet-TurboCell-TxRate TxRate-76032k 1610
+VALUE KarlNet-TurboCell-TxRate TxRate-76160k 1611
+VALUE KarlNet-TurboCell-TxRate TxRate-76288k 1612
+VALUE KarlNet-TurboCell-TxRate TxRate-76416k 1613
+VALUE KarlNet-TurboCell-TxRate TxRate-76544k 1614
+VALUE KarlNet-TurboCell-TxRate TxRate-76672k 1615
+VALUE KarlNet-TurboCell-TxRate TxRate-76800k 1616
+VALUE KarlNet-TurboCell-TxRate TxRate-76928k 1617
+VALUE KarlNet-TurboCell-TxRate TxRate-77056k 1618
+VALUE KarlNet-TurboCell-TxRate TxRate-77184k 1619
+VALUE KarlNet-TurboCell-TxRate TxRate-77312k 1620
+VALUE KarlNet-TurboCell-TxRate TxRate-77440k 1621
+VALUE KarlNet-TurboCell-TxRate TxRate-77568k 1622
+VALUE KarlNet-TurboCell-TxRate TxRate-77696k 1623
+VALUE KarlNet-TurboCell-TxRate TxRate-77824k 1624
+VALUE KarlNet-TurboCell-TxRate TxRate-77952k 1625
+VALUE KarlNet-TurboCell-TxRate TxRate-78080k 1626
+VALUE KarlNet-TurboCell-TxRate TxRate-78208k 1627
+VALUE KarlNet-TurboCell-TxRate TxRate-78336k 1628
+VALUE KarlNet-TurboCell-TxRate TxRate-78464k 1629
+VALUE KarlNet-TurboCell-TxRate TxRate-78592k 1630
+VALUE KarlNet-TurboCell-TxRate TxRate-78720k 1631
+VALUE KarlNet-TurboCell-TxRate TxRate-78848k 1632
+VALUE KarlNet-TurboCell-TxRate TxRate-78976k 1633
+VALUE KarlNet-TurboCell-TxRate TxRate-79104k 1634
+VALUE KarlNet-TurboCell-TxRate TxRate-79232k 1635
+VALUE KarlNet-TurboCell-TxRate TxRate-79360k 1636
+VALUE KarlNet-TurboCell-TxRate TxRate-79488k 1637
+VALUE KarlNet-TurboCell-TxRate TxRate-79616k 1638
+VALUE KarlNet-TurboCell-TxRate TxRate-79744k 1639
+VALUE KarlNet-TurboCell-TxRate TxRate-79872k 1640
+VALUE KarlNet-TurboCell-TxRate TxRate-80000k 1641
+VALUE KarlNet-TurboCell-TxRate TxRate-80128k 1642
+VALUE KarlNet-TurboCell-TxRate TxRate-80256k 1643
+VALUE KarlNet-TurboCell-TxRate TxRate-80384k 1644
+VALUE KarlNet-TurboCell-TxRate TxRate-80512k 1645
+VALUE KarlNet-TurboCell-TxRate TxRate-80640k 1646
+VALUE KarlNet-TurboCell-TxRate TxRate-80768k 1647
+VALUE KarlNet-TurboCell-TxRate TxRate-80896k 1648
+VALUE KarlNet-TurboCell-TxRate TxRate-81024k 1649
+VALUE KarlNet-TurboCell-TxRate TxRate-81152k 1650
+VALUE KarlNet-TurboCell-TxRate TxRate-81280k 1651
+VALUE KarlNet-TurboCell-TxRate TxRate-81408k 1652
+VALUE KarlNet-TurboCell-TxRate TxRate-81536k 1653
+VALUE KarlNet-TurboCell-TxRate TxRate-81664k 1654
+VALUE KarlNet-TurboCell-TxRate TxRate-81792k 1655
+VALUE KarlNet-TurboCell-TxRate TxRate-81920k 1656
+VALUE KarlNet-TurboCell-TxRate TxRate-82048k 1657
+VALUE KarlNet-TurboCell-TxRate TxRate-82176k 1658
+VALUE KarlNet-TurboCell-TxRate TxRate-82304k 1659
+VALUE KarlNet-TurboCell-TxRate TxRate-82432k 1660
+VALUE KarlNet-TurboCell-TxRate TxRate-82560k 1661
+VALUE KarlNet-TurboCell-TxRate TxRate-82688k 1662
+VALUE KarlNet-TurboCell-TxRate TxRate-82816k 1663
+VALUE KarlNet-TurboCell-TxRate TxRate-82944k 1664
+VALUE KarlNet-TurboCell-TxRate TxRate-83072k 1665
+VALUE KarlNet-TurboCell-TxRate TxRate-83200k 1666
+VALUE KarlNet-TurboCell-TxRate TxRate-83328k 1667
+VALUE KarlNet-TurboCell-TxRate TxRate-83456k 1668
+VALUE KarlNet-TurboCell-TxRate TxRate-83584k 1669
+VALUE KarlNet-TurboCell-TxRate TxRate-83712k 1670
+VALUE KarlNet-TurboCell-TxRate TxRate-83840k 1671
+VALUE KarlNet-TurboCell-TxRate TxRate-83968k 1672
+VALUE KarlNet-TurboCell-TxRate TxRate-84096k 1673
+VALUE KarlNet-TurboCell-TxRate TxRate-84224k 1674
+VALUE KarlNet-TurboCell-TxRate TxRate-84352k 1675
+VALUE KarlNet-TurboCell-TxRate TxRate-84480k 1676
+VALUE KarlNet-TurboCell-TxRate TxRate-84608k 1677
+VALUE KarlNet-TurboCell-TxRate TxRate-84736k 1678
+VALUE KarlNet-TurboCell-TxRate TxRate-84864k 1679
+VALUE KarlNet-TurboCell-TxRate TxRate-84992k 1680
+VALUE KarlNet-TurboCell-TxRate TxRate-85120k 1681
+VALUE KarlNet-TurboCell-TxRate TxRate-85248k 1682
+VALUE KarlNet-TurboCell-TxRate TxRate-85376k 1683
+VALUE KarlNet-TurboCell-TxRate TxRate-85504k 1684
+VALUE KarlNet-TurboCell-TxRate TxRate-85632k 1685
+VALUE KarlNet-TurboCell-TxRate TxRate-85760k 1686
+VALUE KarlNet-TurboCell-TxRate TxRate-85888k 1687
+VALUE KarlNet-TurboCell-TxRate TxRate-86016k 1688
+VALUE KarlNet-TurboCell-TxRate TxRate-86144k 1689
+VALUE KarlNet-TurboCell-TxRate TxRate-86272k 1690
+VALUE KarlNet-TurboCell-TxRate TxRate-86400k 1691
+VALUE KarlNet-TurboCell-TxRate TxRate-86528k 1692
+VALUE KarlNet-TurboCell-TxRate TxRate-86656k 1693
+VALUE KarlNet-TurboCell-TxRate TxRate-86784k 1694
+VALUE KarlNet-TurboCell-TxRate TxRate-86912k 1695
+VALUE KarlNet-TurboCell-TxRate TxRate-87040k 1696
+VALUE KarlNet-TurboCell-TxRate TxRate-87168k 1697
+VALUE KarlNet-TurboCell-TxRate TxRate-87296k 1698
+VALUE KarlNet-TurboCell-TxRate TxRate-87424k 1699
+VALUE KarlNet-TurboCell-TxRate TxRate-87552k 1700
+VALUE KarlNet-TurboCell-TxRate TxRate-87680k 1701
+VALUE KarlNet-TurboCell-TxRate TxRate-87808k 1702
+VALUE KarlNet-TurboCell-TxRate TxRate-87936k 1703
+VALUE KarlNet-TurboCell-TxRate TxRate-88064k 1704
+VALUE KarlNet-TurboCell-TxRate TxRate-88192k 1705
+VALUE KarlNet-TurboCell-TxRate TxRate-88320k 1706
+VALUE KarlNet-TurboCell-TxRate TxRate-88448k 1707
+VALUE KarlNet-TurboCell-TxRate TxRate-88576k 1708
+VALUE KarlNet-TurboCell-TxRate TxRate-88704k 1709
+VALUE KarlNet-TurboCell-TxRate TxRate-88832k 1710
+VALUE KarlNet-TurboCell-TxRate TxRate-88960k 1711
+VALUE KarlNet-TurboCell-TxRate TxRate-89088k 1712
+VALUE KarlNet-TurboCell-TxRate TxRate-89216k 1713
+VALUE KarlNet-TurboCell-TxRate TxRate-89344k 1714
+VALUE KarlNet-TurboCell-TxRate TxRate-89472k 1715
+VALUE KarlNet-TurboCell-TxRate TxRate-89600k 1716
+VALUE KarlNet-TurboCell-TxRate TxRate-89728k 1717
+VALUE KarlNet-TurboCell-TxRate TxRate-89856k 1718
+VALUE KarlNet-TurboCell-TxRate TxRate-89984k 1719
+VALUE KarlNet-TurboCell-TxRate TxRate-90112k 1720
+VALUE KarlNet-TurboCell-TxRate TxRate-90240k 1721
+VALUE KarlNet-TurboCell-TxRate TxRate-90368k 1722
+VALUE KarlNet-TurboCell-TxRate TxRate-90496k 1723
+VALUE KarlNet-TurboCell-TxRate TxRate-90624k 1724
+VALUE KarlNet-TurboCell-TxRate TxRate-90752k 1725
+VALUE KarlNet-TurboCell-TxRate TxRate-90880k 1726
+VALUE KarlNet-TurboCell-TxRate TxRate-91008k 1727
+VALUE KarlNet-TurboCell-TxRate TxRate-91136k 1728
+VALUE KarlNet-TurboCell-TxRate TxRate-91264k 1729
+VALUE KarlNet-TurboCell-TxRate TxRate-91392k 1730
+VALUE KarlNet-TurboCell-TxRate TxRate-91520k 1731
+VALUE KarlNet-TurboCell-TxRate TxRate-91648k 1732
+VALUE KarlNet-TurboCell-TxRate TxRate-91776k 1733
+VALUE KarlNet-TurboCell-TxRate TxRate-91904k 1734
+VALUE KarlNet-TurboCell-TxRate TxRate-92032k 1735
+VALUE KarlNet-TurboCell-TxRate TxRate-92160k 1736
+VALUE KarlNet-TurboCell-TxRate TxRate-92288k 1737
+VALUE KarlNet-TurboCell-TxRate TxRate-92416k 1738
+VALUE KarlNet-TurboCell-TxRate TxRate-92544k 1739
+VALUE KarlNet-TurboCell-TxRate TxRate-92672k 1740
+VALUE KarlNet-TurboCell-TxRate TxRate-92800k 1741
+VALUE KarlNet-TurboCell-TxRate TxRate-92928k 1742
+VALUE KarlNet-TurboCell-TxRate TxRate-93056k 1743
+VALUE KarlNet-TurboCell-TxRate TxRate-93184k 1744
+VALUE KarlNet-TurboCell-TxRate TxRate-93312k 1745
+VALUE KarlNet-TurboCell-TxRate TxRate-93440k 1746
+VALUE KarlNet-TurboCell-TxRate TxRate-93568k 1747
+VALUE KarlNet-TurboCell-TxRate TxRate-93696k 1748
+VALUE KarlNet-TurboCell-TxRate TxRate-93824k 1749
+VALUE KarlNet-TurboCell-TxRate TxRate-93952k 1750
+VALUE KarlNet-TurboCell-TxRate TxRate-94080k 1751
+VALUE KarlNet-TurboCell-TxRate TxRate-94208k 1752
+VALUE KarlNet-TurboCell-TxRate TxRate-94336k 1753
+VALUE KarlNet-TurboCell-TxRate TxRate-94464k 1754
+VALUE KarlNet-TurboCell-TxRate TxRate-94592k 1755
+VALUE KarlNet-TurboCell-TxRate TxRate-94720k 1756
+VALUE KarlNet-TurboCell-TxRate TxRate-94848k 1757
+VALUE KarlNet-TurboCell-TxRate TxRate-94976k 1758
+VALUE KarlNet-TurboCell-TxRate TxRate-95104k 1759
+VALUE KarlNet-TurboCell-TxRate TxRate-95232k 1760
+VALUE KarlNet-TurboCell-TxRate TxRate-95360k 1761
+VALUE KarlNet-TurboCell-TxRate TxRate-95488k 1762
+VALUE KarlNet-TurboCell-TxRate TxRate-95616k 1763
+VALUE KarlNet-TurboCell-TxRate TxRate-95744k 1764
+VALUE KarlNet-TurboCell-TxRate TxRate-95872k 1765
+VALUE KarlNet-TurboCell-TxRate TxRate-96000k 1766
+VALUE KarlNet-TurboCell-TxRate TxRate-96128k 1767
+VALUE KarlNet-TurboCell-TxRate TxRate-96256k 1768
+VALUE KarlNet-TurboCell-TxRate TxRate-96384k 1769
+VALUE KarlNet-TurboCell-TxRate TxRate-96512k 1770
+VALUE KarlNet-TurboCell-TxRate TxRate-96640k 1771
+VALUE KarlNet-TurboCell-TxRate TxRate-96768k 1772
+VALUE KarlNet-TurboCell-TxRate TxRate-96896k 1773
+VALUE KarlNet-TurboCell-TxRate TxRate-97024k 1774
+VALUE KarlNet-TurboCell-TxRate TxRate-97152k 1775
+VALUE KarlNet-TurboCell-TxRate TxRate-97280k 1776
+VALUE KarlNet-TurboCell-TxRate TxRate-97408k 1777
+VALUE KarlNet-TurboCell-TxRate TxRate-97536k 1778
+VALUE KarlNet-TurboCell-TxRate TxRate-97664k 1779
+VALUE KarlNet-TurboCell-TxRate TxRate-97792k 1780
+VALUE KarlNet-TurboCell-TxRate TxRate-97920k 1781
+VALUE KarlNet-TurboCell-TxRate TxRate-98048k 1782
+VALUE KarlNet-TurboCell-TxRate TxRate-98176k 1783
+VALUE KarlNet-TurboCell-TxRate TxRate-98304k 1784
+VALUE KarlNet-TurboCell-TxRate TxRate-98432k 1785
+VALUE KarlNet-TurboCell-TxRate TxRate-98560k 1786
+VALUE KarlNet-TurboCell-TxRate TxRate-98688k 1787
+VALUE KarlNet-TurboCell-TxRate TxRate-98816k 1788
+VALUE KarlNet-TurboCell-TxRate TxRate-98944k 1789
+VALUE KarlNet-TurboCell-TxRate TxRate-99072k 1790
+VALUE KarlNet-TurboCell-TxRate TxRate-99200k 1791
+VALUE KarlNet-TurboCell-TxRate TxRate-99328k 1792
+VALUE KarlNet-TurboCell-TxRate TxRate-99456k 1793
+VALUE KarlNet-TurboCell-TxRate TxRate-99584k 1794
+VALUE KarlNet-TurboCell-TxRate TxRate-99712k 1795
+VALUE KarlNet-TurboCell-TxRate TxRate-99840k 1796
+VALUE KarlNet-TurboCell-TxRate TxRate-99968k 1797
+VALUE KarlNet-TurboCell-TxRate TxRate-100096k 1798
+VALUE KarlNet-TurboCell-TxRate TxRate-100224k 1799
+VALUE KarlNet-TurboCell-TxRate TxRate-100352k 1800
+VALUE KarlNet-TurboCell-TxRate TxRate-100480k 1801
+VALUE KarlNet-TurboCell-TxRate TxRate-100608k 1802
+VALUE KarlNet-TurboCell-TxRate TxRate-100736k 1803
+VALUE KarlNet-TurboCell-TxRate TxRate-100864k 1804
+VALUE KarlNet-TurboCell-TxRate TxRate-100992k 1805
+VALUE KarlNet-TurboCell-TxRate TxRate-101120k 1806
+VALUE KarlNet-TurboCell-TxRate TxRate-101248k 1807
+VALUE KarlNet-TurboCell-TxRate TxRate-101376k 1808
+VALUE KarlNet-TurboCell-TxRate TxRate-101504k 1809
+VALUE KarlNet-TurboCell-TxRate TxRate-101632k 1810
+VALUE KarlNet-TurboCell-TxRate TxRate-101760k 1811
+VALUE KarlNet-TurboCell-TxRate TxRate-101888k 1812
+VALUE KarlNet-TurboCell-TxRate TxRate-102016k 1813
+VALUE KarlNet-TurboCell-TxRate TxRate-102144k 1814
+VALUE KarlNet-TurboCell-TxRate TxRate-102272k 1815
+VALUE KarlNet-TurboCell-TxRate TxRate-102400k 1816
+VALUE KarlNet-TurboCell-TxRate TxRate-102528k 1817
+VALUE KarlNet-TurboCell-TxRate TxRate-102656k 1818
+VALUE KarlNet-TurboCell-TxRate TxRate-102784k 1819
+VALUE KarlNet-TurboCell-TxRate TxRate-102912k 1820
+VALUE KarlNet-TurboCell-TxRate TxRate-103040k 1821
+VALUE KarlNet-TurboCell-TxRate TxRate-103168k 1822
+VALUE KarlNet-TurboCell-TxRate TxRate-103296k 1823
+VALUE KarlNet-TurboCell-TxRate TxRate-103424k 1824
+VALUE KarlNet-TurboCell-TxRate TxRate-103552k 1825
+VALUE KarlNet-TurboCell-TxRate TxRate-103680k 1826
+VALUE KarlNet-TurboCell-TxRate TxRate-103808k 1827
+VALUE KarlNet-TurboCell-TxRate TxRate-103936k 1828
+VALUE KarlNet-TurboCell-TxRate TxRate-104064k 1829
+VALUE KarlNet-TurboCell-TxRate TxRate-104192k 1830
+VALUE KarlNet-TurboCell-TxRate TxRate-104320k 1831
+VALUE KarlNet-TurboCell-TxRate TxRate-104448k 1832
+VALUE KarlNet-TurboCell-TxRate TxRate-104576k 1833
+VALUE KarlNet-TurboCell-TxRate TxRate-104704k 1834
+VALUE KarlNet-TurboCell-TxRate TxRate-104832k 1835
+VALUE KarlNet-TurboCell-TxRate TxRate-104960k 1836
+VALUE KarlNet-TurboCell-TxRate TxRate-105088k 1837
+VALUE KarlNet-TurboCell-TxRate TxRate-105216k 1838
+VALUE KarlNet-TurboCell-TxRate TxRate-105344k 1839
+VALUE KarlNet-TurboCell-TxRate TxRate-105472k 1840
+VALUE KarlNet-TurboCell-TxRate TxRate-105600k 1841
+VALUE KarlNet-TurboCell-TxRate TxRate-105728k 1842
+VALUE KarlNet-TurboCell-TxRate TxRate-105856k 1843
+VALUE KarlNet-TurboCell-TxRate TxRate-105984k 1844
+VALUE KarlNet-TurboCell-TxRate TxRate-106112k 1845
+VALUE KarlNet-TurboCell-TxRate TxRate-106240k 1846
+VALUE KarlNet-TurboCell-TxRate TxRate-106368k 1847
+VALUE KarlNet-TurboCell-TxRate TxRate-106496k 1848
+VALUE KarlNet-TurboCell-TxRate TxRate-106624k 1849
+VALUE KarlNet-TurboCell-TxRate TxRate-106752k 1850
+VALUE KarlNet-TurboCell-TxRate TxRate-106880k 1851
+VALUE KarlNet-TurboCell-TxRate TxRate-107008k 1852
+VALUE KarlNet-TurboCell-TxRate TxRate-107136k 1853
+VALUE KarlNet-TurboCell-TxRate TxRate-107264k 1854
+VALUE KarlNet-TurboCell-TxRate TxRate-107392k 1855
+VALUE KarlNet-TurboCell-TxRate TxRate-107520k 1856
+VALUE KarlNet-TurboCell-TxRate TxRate-107648k 1857
+VALUE KarlNet-TurboCell-TxRate TxRate-107776k 1858
+VALUE KarlNet-TurboCell-TxRate TxRate-107904k 1859
+VALUE KarlNet-TurboCell-TxRate TxRate-108032k 1860
+VALUE KarlNet-TurboCell-TxRate TxRate-108160k 1861
+VALUE KarlNet-TurboCell-TxRate TxRate-108288k 1862
+VALUE KarlNet-TurboCell-TxRate TxRate-108416k 1863
+VALUE KarlNet-TurboCell-TxRate TxRate-108544k 1864
+VALUE KarlNet-TurboCell-TxRate TxRate-108672k 1865
+VALUE KarlNet-TurboCell-TxRate TxRate-108800k 1866
+VALUE KarlNet-TurboCell-TxRate TxRate-108928k 1867
+VALUE KarlNet-TurboCell-TxRate TxRate-109056k 1868
+VALUE KarlNet-TurboCell-TxRate TxRate-109184k 1869
+VALUE KarlNet-TurboCell-TxRate TxRate-109312k 1870
+VALUE KarlNet-TurboCell-TxRate TxRate-109440k 1871
+VALUE KarlNet-TurboCell-TxRate TxRate-109568k 1872
+VALUE KarlNet-TurboCell-TxRate TxRate-109696k 1873
+VALUE KarlNet-TurboCell-TxRate TxRate-109824k 1874
+VALUE KarlNet-TurboCell-TxRate TxRate-109952k 1875
+VALUE KarlNet-TurboCell-TxRate TxRate-110080k 1876
+VALUE KarlNet-TurboCell-TxRate TxRate-110208k 1877
+VALUE KarlNet-TurboCell-TxRate TxRate-110336k 1878
+VALUE KarlNet-TurboCell-TxRate TxRate-110464k 1879
+VALUE KarlNet-TurboCell-TxRate TxRate-110592k 1880
+VALUE KarlNet-TurboCell-TxRate TxRate-110720k 1881
+VALUE KarlNet-TurboCell-TxRate TxRate-110848k 1882
+VALUE KarlNet-TurboCell-TxRate TxRate-110976k 1883
+VALUE KarlNet-TurboCell-TxRate TxRate-111104k 1884
+VALUE KarlNet-TurboCell-TxRate TxRate-111232k 1885
+VALUE KarlNet-TurboCell-TxRate TxRate-111360k 1886
+VALUE KarlNet-TurboCell-TxRate TxRate-111488k 1887
+VALUE KarlNet-TurboCell-TxRate TxRate-111616k 1888
+VALUE KarlNet-TurboCell-TxRate TxRate-111744k 1889
+VALUE KarlNet-TurboCell-TxRate TxRate-111872k 1890
+VALUE KarlNet-TurboCell-TxRate TxRate-112000k 1891
+VALUE KarlNet-TurboCell-TxRate TxRate-112128k 1892
+VALUE KarlNet-TurboCell-TxRate TxRate-112256k 1893
+VALUE KarlNet-TurboCell-TxRate TxRate-112384k 1894
+VALUE KarlNet-TurboCell-TxRate TxRate-112512k 1895
+VALUE KarlNet-TurboCell-TxRate TxRate-112640k 1896
+VALUE KarlNet-TurboCell-TxRate TxRate-112768k 1897
+VALUE KarlNet-TurboCell-TxRate TxRate-112896k 1898
+VALUE KarlNet-TurboCell-TxRate TxRate-113024k 1899
+VALUE KarlNet-TurboCell-TxRate TxRate-113152k 1900
+VALUE KarlNet-TurboCell-TxRate TxRate-113280k 1901
+VALUE KarlNet-TurboCell-TxRate TxRate-113408k 1902
+VALUE KarlNet-TurboCell-TxRate TxRate-113536k 1903
+VALUE KarlNet-TurboCell-TxRate TxRate-113664k 1904
+VALUE KarlNet-TurboCell-TxRate TxRate-113792k 1905
+VALUE KarlNet-TurboCell-TxRate TxRate-113920k 1906
+VALUE KarlNet-TurboCell-TxRate TxRate-114048k 1907
+VALUE KarlNet-TurboCell-TxRate TxRate-114176k 1908
+VALUE KarlNet-TurboCell-TxRate TxRate-114304k 1909
+VALUE KarlNet-TurboCell-TxRate TxRate-114432k 1910
+VALUE KarlNet-TurboCell-TxRate TxRate-114560k 1911
+VALUE KarlNet-TurboCell-TxRate TxRate-114688k 1912
+VALUE KarlNet-TurboCell-TxRate TxRate-114816k 1913
+VALUE KarlNet-TurboCell-TxRate TxRate-114944k 1914
+VALUE KarlNet-TurboCell-TxRate TxRate-115072k 1915
+VALUE KarlNet-TurboCell-TxRate TxRate-115200k 1916
+VALUE KarlNet-TurboCell-TxRate TxRate-115328k 1917
+VALUE KarlNet-TurboCell-TxRate TxRate-115456k 1918
+VALUE KarlNet-TurboCell-TxRate TxRate-115584k 1919
+VALUE KarlNet-TurboCell-TxRate TxRate-115712k 1920
+VALUE KarlNet-TurboCell-TxRate TxRate-115840k 1921
+VALUE KarlNet-TurboCell-TxRate TxRate-115968k 1922
+VALUE KarlNet-TurboCell-TxRate TxRate-116096k 1923
+VALUE KarlNet-TurboCell-TxRate TxRate-116224k 1924
+VALUE KarlNet-TurboCell-TxRate TxRate-116352k 1925
+VALUE KarlNet-TurboCell-TxRate TxRate-116480k 1926
+VALUE KarlNet-TurboCell-TxRate TxRate-116608k 1927
+VALUE KarlNet-TurboCell-TxRate TxRate-116736k 1928
+VALUE KarlNet-TurboCell-TxRate TxRate-116864k 1929
+VALUE KarlNet-TurboCell-TxRate TxRate-116992k 1930
+VALUE KarlNet-TurboCell-TxRate TxRate-117120k 1931
+VALUE KarlNet-TurboCell-TxRate TxRate-117248k 1932
+VALUE KarlNet-TurboCell-TxRate TxRate-117376k 1933
+VALUE KarlNet-TurboCell-TxRate TxRate-117504k 1934
+VALUE KarlNet-TurboCell-TxRate TxRate-117632k 1935
+VALUE KarlNet-TurboCell-TxRate TxRate-117760k 1936
+VALUE KarlNet-TurboCell-TxRate TxRate-117888k 1937
+VALUE KarlNet-TurboCell-TxRate TxRate-118016k 1938
+VALUE KarlNet-TurboCell-TxRate TxRate-118144k 1939
+VALUE KarlNet-TurboCell-TxRate TxRate-118272k 1940
+VALUE KarlNet-TurboCell-TxRate TxRate-118400k 1941
+VALUE KarlNet-TurboCell-TxRate TxRate-118528k 1942
+VALUE KarlNet-TurboCell-TxRate TxRate-118656k 1943
+VALUE KarlNet-TurboCell-TxRate TxRate-118784k 1944
+VALUE KarlNet-TurboCell-TxRate TxRate-118912k 1945
+VALUE KarlNet-TurboCell-TxRate TxRate-119040k 1946
+VALUE KarlNet-TurboCell-TxRate TxRate-119168k 1947
+VALUE KarlNet-TurboCell-TxRate TxRate-119296k 1948
+VALUE KarlNet-TurboCell-TxRate TxRate-119424k 1949
+VALUE KarlNet-TurboCell-TxRate TxRate-119552k 1950
+VALUE KarlNet-TurboCell-TxRate TxRate-119680k 1951
+VALUE KarlNet-TurboCell-TxRate TxRate-119808k 1952
+VALUE KarlNet-TurboCell-TxRate TxRate-119936k 1953
+VALUE KarlNet-TurboCell-TxRate TxRate-120064k 1954
+VALUE KarlNet-TurboCell-TxRate TxRate-120192k 1955
+VALUE KarlNet-TurboCell-TxRate TxRate-120320k 1956
+VALUE KarlNet-TurboCell-TxRate TxRate-120448k 1957
+VALUE KarlNet-TurboCell-TxRate TxRate-120576k 1958
+VALUE KarlNet-TurboCell-TxRate TxRate-120704k 1959
+VALUE KarlNet-TurboCell-TxRate TxRate-120832k 1960
+VALUE KarlNet-TurboCell-TxRate TxRate-120960k 1961
+VALUE KarlNet-TurboCell-TxRate TxRate-121088k 1962
+VALUE KarlNet-TurboCell-TxRate TxRate-121216k 1963
+VALUE KarlNet-TurboCell-TxRate TxRate-121344k 1964
+VALUE KarlNet-TurboCell-TxRate TxRate-121472k 1965
+VALUE KarlNet-TurboCell-TxRate TxRate-121600k 1966
+VALUE KarlNet-TurboCell-TxRate TxRate-121728k 1967
+VALUE KarlNet-TurboCell-TxRate TxRate-121856k 1968
+VALUE KarlNet-TurboCell-TxRate TxRate-121984k 1969
+VALUE KarlNet-TurboCell-TxRate TxRate-122112k 1970
+VALUE KarlNet-TurboCell-TxRate TxRate-122240k 1971
+VALUE KarlNet-TurboCell-TxRate TxRate-122368k 1972
+VALUE KarlNet-TurboCell-TxRate TxRate-122496k 1973
+VALUE KarlNet-TurboCell-TxRate TxRate-122624k 1974
+VALUE KarlNet-TurboCell-TxRate TxRate-122752k 1975
+VALUE KarlNet-TurboCell-TxRate TxRate-122880k 1976
+VALUE KarlNet-TurboCell-TxRate TxRate-123008k 1977
+VALUE KarlNet-TurboCell-TxRate TxRate-123136k 1978
+VALUE KarlNet-TurboCell-TxRate TxRate-123264k 1979
+VALUE KarlNet-TurboCell-TxRate TxRate-123392k 1980
+VALUE KarlNet-TurboCell-TxRate TxRate-123520k 1981
+VALUE KarlNet-TurboCell-TxRate TxRate-123648k 1982
+VALUE KarlNet-TurboCell-TxRate TxRate-123776k 1983
+VALUE KarlNet-TurboCell-TxRate TxRate-123904k 1984
+VALUE KarlNet-TurboCell-TxRate TxRate-124032k 1985
+VALUE KarlNet-TurboCell-TxRate TxRate-124160k 1986
+VALUE KarlNet-TurboCell-TxRate TxRate-124288k 1987
+VALUE KarlNet-TurboCell-TxRate TxRate-124416k 1988
+VALUE KarlNet-TurboCell-TxRate TxRate-124544k 1989
+VALUE KarlNet-TurboCell-TxRate TxRate-124672k 1990
+VALUE KarlNet-TurboCell-TxRate TxRate-124800k 1991
+VALUE KarlNet-TurboCell-TxRate TxRate-124928k 1992
+VALUE KarlNet-TurboCell-TxRate TxRate-125056k 1993
+VALUE KarlNet-TurboCell-TxRate TxRate-125184k 1994
+VALUE KarlNet-TurboCell-TxRate TxRate-125312k 1995
+VALUE KarlNet-TurboCell-TxRate TxRate-125440k 1996
+VALUE KarlNet-TurboCell-TxRate TxRate-125568k 1997
+VALUE KarlNet-TurboCell-TxRate TxRate-125696k 1998
+VALUE KarlNet-TurboCell-TxRate TxRate-125824k 1999
+VALUE KarlNet-TurboCell-TxRate TxRate-125952k 2000
+VALUE KarlNet-TurboCell-TxRate TxRate-126080k 2001
+VALUE KarlNet-TurboCell-TxRate TxRate-126208k 2002
+VALUE KarlNet-TurboCell-TxRate TxRate-126336k 2003
+VALUE KarlNet-TurboCell-TxRate TxRate-126464k 2004
+VALUE KarlNet-TurboCell-TxRate TxRate-126592k 2005
+VALUE KarlNet-TurboCell-TxRate TxRate-126720k 2006
+VALUE KarlNet-TurboCell-TxRate TxRate-126848k 2007
+VALUE KarlNet-TurboCell-TxRate TxRate-126976k 2008
+VALUE KarlNet-TurboCell-TxRate TxRate-127104k 2009
+VALUE KarlNet-TurboCell-TxRate TxRate-127232k 2010
+VALUE KarlNet-TurboCell-TxRate TxRate-127360k 2011
+VALUE KarlNet-TurboCell-TxRate TxRate-127488k 2012
+VALUE KarlNet-TurboCell-TxRate TxRate-127616k 2013
+VALUE KarlNet-TurboCell-TxRate TxRate-127744k 2014
+VALUE KarlNet-TurboCell-TxRate TxRate-127872k 2015
+VALUE KarlNet-TurboCell-TxRate TxRate-128000k 2016
+VALUE KarlNet-TurboCell-TxRate TxRate-128128k 2017
+VALUE KarlNet-TurboCell-TxRate TxRate-128256k 2018
+VALUE KarlNet-TurboCell-TxRate TxRate-128384k 2019
+VALUE KarlNet-TurboCell-TxRate TxRate-128512k 2020
+VALUE KarlNet-TurboCell-TxRate TxRate-128640k 2021
+VALUE KarlNet-TurboCell-TxRate TxRate-128768k 2022
+VALUE KarlNet-TurboCell-TxRate TxRate-128896k 2023
+VALUE KarlNet-TurboCell-TxRate TxRate-129024k 2024
+VALUE KarlNet-TurboCell-TxRate TxRate-129152k 2025
+VALUE KarlNet-TurboCell-TxRate TxRate-129280k 2026
+VALUE KarlNet-TurboCell-TxRate TxRate-129408k 2027
+VALUE KarlNet-TurboCell-TxRate TxRate-129536k 2028
+VALUE KarlNet-TurboCell-TxRate TxRate-129664k 2029
+VALUE KarlNet-TurboCell-TxRate TxRate-129792k 2030
+VALUE KarlNet-TurboCell-TxRate TxRate-129920k 2031
+VALUE KarlNet-TurboCell-TxRate TxRate-130048k 2032
+VALUE KarlNet-TurboCell-TxRate TxRate-130176k 2033
+VALUE KarlNet-TurboCell-TxRate TxRate-130304k 2034
+VALUE KarlNet-TurboCell-TxRate TxRate-130432k 2035
+VALUE KarlNet-TurboCell-TxRate TxRate-130560k 2036
+VALUE KarlNet-TurboCell-TxRate TxRate-130688k 2037
+VALUE KarlNet-TurboCell-TxRate TxRate-130816k 2038
+VALUE KarlNet-TurboCell-TxRate TxRate-130944k 2039
+VALUE KarlNet-TurboCell-TxRate TxRate-131072k 2040
+VALUE KarlNet-TurboCell-TxRate TxRate-131200k 2041
+VALUE KarlNet-TurboCell-TxRate TxRate-131328k 2042
+VALUE KarlNet-TurboCell-TxRate TxRate-131456k 2043
+VALUE KarlNet-TurboCell-TxRate TxRate-131584k 2044
+VALUE KarlNet-TurboCell-TxRate TxRate-131712k 2045
+VALUE KarlNet-TurboCell-TxRate TxRate-131840k 2046
+VALUE KarlNet-TurboCell-TxRate TxRate-131968k 2047
+
+# Sets the remote client's Operating State
+ATTRIBUTE KarlNet-TurboCell-OpState 153 integer
+VALUE KarlNet-TurboCell-OpState Up 0
+VALUE KarlNet-TurboCell-OpState Down 1
+
+# Sets the remote client's Operating Mode
+ATTRIBUTE KarlNet-TurboCell-OpMode 154 integer
+VALUE KarlNet-TurboCell-OpMode Peer-to-Peer 0
+VALUE KarlNet-TurboCell-OpMode Base 1
+VALUE KarlNet-TurboCell-OpMode Base-Polling 2
+VALUE KarlNet-TurboCell-OpMode Satellite-NT 3
+
+# ----------------------------------------------
+# END OF KarlNet Vendor-specific information
+# ----------------------------------------------
+
+END-VENDOR KarlNet
diff --git a/share/dictionary.kineto b/share/dictionary.kineto
new file mode 100644
index 0000000..8cc8584
--- /dev/null
+++ b/share/dictionary.kineto
@@ -0,0 +1,119 @@
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Version $Id$
+#
+# Kineto Wireless Dictionary
+#
+# As posted to the list by Swaran Sethi <ssethi@kinetowireless.com>
+#
+# For documentation on Kineto Wireless RADIUS attributes, see:
+# http://www.kinetowireless.com/
+#
+
+VENDOR Kineto 16445 format=2,1
+
+BEGIN-VENDOR Kineto
+
+# Kineto Vendor Specific Attributes Based on UMA Information Elements
+#
+# For documentation on UMA Information Elements, see:
+# http://www.umatechnology.org/specifications/index.htm
+# Unlicensed Mobile Access (UMA) Protocols (Stage 3), Release 1.0.4,
+# May 2005
+#
+ATTRIBUTE Kineto-UMA-Release-Indicator 2 octets
+ATTRIBUTE Kineto-UMA-AP-Radio-Identity 3 octets
+ATTRIBUTE Kineto-UMA-Cell-Identity 4 octets
+ATTRIBUTE Kineto-UMA-Location-Area-Identification 5 octets
+ATTRIBUTE Kineto-UMA-Coverage-Indicator 6 octets
+ATTRIBUTE Kineto-UMA-Classmark 7 octets
+ATTRIBUTE Kineto-UMA-Geographical-Location 8 octets
+ATTRIBUTE Kineto-UMA-SGW-IP-Address 9 octets
+ATTRIBUTE Kineto-UMA-SGW-FQDN 10 octets
+ATTRIBUTE Kineto-UMA-Redirection-Counter 11 octets
+ATTRIBUTE Kineto-UMA-Discovery-Reject-Cause 12 octets
+ATTRIBUTE Kineto-UMA-RRC-State 17 octets
+ATTRIBUTE Kineto-UMA-Register-Reject-Cause 21 octets
+ATTRIBUTE Kineto-UMA-Routing-Area-Code 41 octets
+ATTRIBUTE Kineto-UMA-AP-Location 42 octets
+ATTRIBUTE Kineto-UMA-Location-Status 44 octets
+ATTRIBUTE Kineto-UMA-Utran-Cell-Identity 49 octets
+ATTRIBUTE Kineto-UMA-Location-Blacklist-Indicator 58 octets
+ATTRIBUTE Kineto-UMA-AP-Service-Name 61 octets
+ATTRIBUTE Kineto-UMA-Service-Zone-Information 62 octets
+ATTRIBUTE Kineto-UMA-Serving-UNC-Table-Indicator 67 octets
+ATTRIBUTE Kineto-UMA-Registration-Indicators 68 octets
+ATTRIBUTE Kineto-UMA-UMA-PLMN-List 69 octets
+ATTRIBUTE Kineto-UMA-Required-UMA-Services 71 octets
+ATTRIBUTE Kineto-UMA-3G-Cell-Identity 73 octets
+ATTRIBUTE Kineto-UMA-MS-Radio-Identity 96 octets
+ATTRIBUTE Kineto-UMA-UNC-IP-Address 97 octets
+ATTRIBUTE Kineto-UMA-UNC-FQDN 98 octets
+
+# Kineto Vendor Specific Attributes
+#
+
+ATTRIBUTE Kineto-URR-Transaction-Type 0xff01 octets
+ATTRIBUTE Kineto-Location-Key 0xff02 octets
+ATTRIBUTE Kineto-UP-Client-Remote-Address 0xff03 octets
+ATTRIBUTE Kineto-Hand-In-Control-Flag 0xff04 octets
+ATTRIBUTE Kineto-Hand-Out-Control-Flag 0xff05 octets
+ATTRIBUTE Kineto-Billing-Rate-Indicator 0xff06 octets
+ATTRIBUTE Kineto-Service-Area-Code 0xff09 octets
+ATTRIBUTE KW-IUH-MESSAGE-TYPE 65408 string
+ATTRIBUTE KW-HNB-REMOTE-ADDRESS 65409 ipaddr
+ATTRIBUTE KW-HNB-IDENTITY 65410 string
+ATTRIBUTE KW-HNB-LOC-INFO-MACRO-COVERAGE-IND 65411 integer
+ATTRIBUTE KW-HNB-LOC-INFO-GERAN-CELL-ID 65412 string
+ATTRIBUTE KW-HNB-LOC-INFO-UTRAN-CELL-ID 65413 string
+ATTRIBUTE KW-HNB-LOC-INFO-GEO-COORDINATES 65414 integer
+ATTRIBUTE KW-HNB-LOC-INFO-ALTITUDE-Direction 65415 integer
+ATTRIBUTE KW-HNB-LOC-INFO-IP-ADDRESS 65416 string
+ATTRIBUTE KW-HNB-PLMN-ID 65417 string
+ATTRIBUTE KW-HNB-CELL-ID 65418 string
+ATTRIBUTE KW-HNB-LAC 65419 string
+ATTRIBUTE KW-HNB-RAC 65420 string
+ATTRIBUTE KW-HNB-SAC 65421 string
+ATTRIBUTE KW-HNB-CSG-ID 65422 string
+ATTRIBUTE KW-UE-Capabilities 65423 integer
+ATTRIBUTE KW-HNB-LOCATION-AREA-IND 0xff90 octets
+ATTRIBUTE KW-IUH-BILLING-RATE-INDICATOR 0xff91 octets
+ATTRIBUTE KW-REGISTRATION-REJECT-CAUSE 0xff92 octets
+ATTRIBUTE KW-HNB-LOCATION-BLACKLIST-IND 0xff93 octets
+
+# (please refer Iuh-AAA-KS1 Rel 2.0.doc )
+ATTRIBUTE KW-HNB-CELL-ACCESS-MODE 0xff94 octets
+ATTRIBUTE KW-UE-MEMBERSHIP-STATUS 0xff95 octets
+
+# (please refer Iuh-AAA-S1.doc, 0xff93 are defined Blacklist & Reg-reject
+# in Iuh. by kbnao
+#ATTRIBUTE KW-HNB-REGISTER-REJECT-CAUSE 0xff94 octets
+
+#ATTRIBUTE KW-HNB-LOC-INFO-MACRO-COVERAGE-IND
+
+VALUE KW-HNB-LOC-INFO-MACRO-COVERAGE-IND GERAN 0
+VALUE KW-HNB-LOC-INFO-MACRO-COVERAGE-IND UTRAN 1
+VALUE KW-HNB-LOC-INFO-MACRO-COVERAGE-IND NONE 2
+
+#ATTRIBUTE KW-HNB-LOC-INFO-GEO-COORDINATES
+
+VALUE KW-HNB-LOC-INFO-GEO-COORDINATES North 0
+VALUE KW-HNB-LOC-INFO-GEO-COORDINATES South 1
+
+#ATTRIBUTE KW-HNB-LOC-INFO-ALTITUDE-Direction
+
+VALUE KW-HNB-LOC-INFO-ALTITUDE-Direction Height 0
+VALUE KW-HNB-LOC-INFO-ALTITUDE-Direction Depth 1
+
+#ATTRIBUTE KW-UE-Capabilities
+VALUE KW-UE-Capabilities R99 0
+VALUE KW-UE-Capabilities Rel-4 1
+VALUE KW-UE-Capabilities Rel-5 2
+VALUE KW-UE-Capabilities Rel-6 3
+VALUE KW-UE-Capabilities Rel-7 4
+VALUE KW-UE-Capabilities Rel-8 5
+VALUE KW-UE-Capabilities CSG-Capable 0
+VALUE KW-UE-Capabilities Not-CSG-Capable 1
+
+END-VENDOR Kineto
diff --git a/share/dictionary.lancom b/share/dictionary.lancom
new file mode 100644
index 0000000..7462430
--- /dev/null
+++ b/share/dictionary.lancom
@@ -0,0 +1,42 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# originally by
+# "Eugen K. " <>
+#
+
+VENDOR Lancom 2356
+
+BEGIN-VENDOR Lancom
+
+# Attributes
+ATTRIBUTE LCS-Traffic-Limit 1 integer
+ATTRIBUTE LCS-Mac-Address 2 string
+ATTRIBUTE LCS-Redirection-URL 3 string
+ATTRIBUTE LCS-Comment 4 string
+ATTRIBUTE LCS-Account-End 5 integer
+ATTRIBUTE LCS-WPA-Passphrase 6 string
+ATTRIBUTE LCS-PbSpotUserName 7 string
+ATTRIBUTE LCS-TxRateLimit 8 integer
+ATTRIBUTE LCS-RxRateLimit 9 integer
+ATTRIBUTE LCS-Access-Rights 11 integer
+ATTRIBUTE LCS-Function-Rights 12 integer
+ATTRIBUTE LCS-Advertisement-URL 13 string
+ATTRIBUTE LCS-Advertisement-Interval 14 integer
+ATTRIBUTE LCS-Traffic-Limit-Gigawords 15 integer
+ATTRIBUTE LCS-Orig-NAS-Identifier 16 string
+ATTRIBUTE LCS-Orig-NAS-IP-Address 17 ipaddr
+ATTRIBUTE LCS-Orig-NAS-IPv6-Address 18 ipv6addr
+ATTRIBUTE LCS-IKEv2-Local-Password 19 string has_tag,encrypt=2
+ATTRIBUTE LCS-IKEv2-Remote-Password 20 string has_tag,encrypt=2
+ATTRIBUTE LCS-DNS-Server-IPv4-Address 21 ipaddr
+ATTRIBUTE LCS-VPN-IPv4-Rule 22 string
+ATTRIBUTE LCS-VPN-IPv6-Rule 23 string
+ATTRIBUTE LCS-Routing-Tag 24 integer
+ATTRIBUTE LCS-IKEv2-IPv4-Route 25 string
+ATTRIBUTE LCS-IKEv2-IPv6-Route 26 string
+ATTRIBUTE LCS-IKEv2-DNS-Domain 27 string
+ATTRIBUTE LCS-Load-Balancer 28 string
+
+END-VENDOR Lancom
diff --git a/share/dictionary.lantronix b/share/dictionary.lantronix
new file mode 100644
index 0000000..75f931b
--- /dev/null
+++ b/share/dictionary.lantronix
@@ -0,0 +1,13 @@
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Lantronix SLC Secure Lantronix Console Manager
+# Provides SLC-specific user attributes
+#
+VENDOR Lantronix 244
+
+BEGIN-VENDOR Lantronix
+
+ATTRIBUTE Lantronix-User-Attributes 1 string
+
+END-VENDOR Lantronix
diff --git a/share/dictionary.livingston b/share/dictionary.livingston
new file mode 100644
index 0000000..f9e0da7
--- /dev/null
+++ b/share/dictionary.livingston
@@ -0,0 +1,63 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+VENDOR Livingston 307
+
+#
+# Livingston Vendor-Specific Attributes (requires ComOS 3.8)
+#
+BEGIN-VENDOR Livingston
+
+ATTRIBUTE LE-Terminate-Detail 2 string
+ATTRIBUTE LE-Advice-of-Charge 3 string
+ATTRIBUTE LE-Connect-Detail 4 string
+
+ATTRIBUTE LE-IP-Pool 6 string
+ATTRIBUTE LE-IP-Gateway 7 ipaddr
+ATTRIBUTE LE-Modem-Info 8 string
+ATTRIBUTE LE-IPSec-Log-Options 9 integer
+ATTRIBUTE LE-IPSec-Deny-Action 10 integer
+ATTRIBUTE LE-IPSec-Active-Profile 11 string
+ATTRIBUTE LE-IPSec-Outsource-Profile 12 string
+ATTRIBUTE LE-IPSec-Passive-Profile 13 string
+ATTRIBUTE LE-NAT-TCP-Session-Timeout 14 integer
+ATTRIBUTE LE-NAT-Other-Session-Timeout 15 integer
+ATTRIBUTE LE-NAT-Log-Options 16 integer
+ATTRIBUTE LE-NAT-Sess-Dir-Fail-Action 17 integer
+ATTRIBUTE LE-NAT-Inmap 18 string
+ATTRIBUTE LE-NAT-Outmap 19 string
+ATTRIBUTE LE-NAT-Outsource-Inmap 20 string
+ATTRIBUTE LE-NAT-Outsource-Outmap 21 string
+ATTRIBUTE LE-Admin-Group 22 string
+ATTRIBUTE LE-Multicast-Client 23 integer
+
+VALUE LE-IPSec-Deny-Action Drop 1
+VALUE LE-IPSec-Deny-Action ICMP-Reject 2
+VALUE LE-IPSec-Deny-Action Pass-Through 3
+
+VALUE LE-IPSec-Log-Options SA-Success-On 1
+VALUE LE-IPSec-Log-Options SA-Failure-On 2
+VALUE LE-IPSec-Log-Options Console-On 3
+VALUE LE-IPSec-Log-Options Syslog-On 4
+VALUE LE-IPSec-Log-Options SA-Success-Off 5
+VALUE LE-IPSec-Log-Options SA-Failure-Off 6
+VALUE LE-IPSec-Log-Options Console-Off 7
+VALUE LE-IPSec-Log-Options Syslog-Off 8
+
+VALUE LE-NAT-Sess-Dir-Fail-Action Drop 1
+VALUE LE-NAT-Sess-Dir-Fail-Action ICMP-Reject 2
+VALUE LE-NAT-Sess-Dir-Fail-Action Pass-Through 3
+
+VALUE LE-NAT-Log-Options Session-Success-On 1
+VALUE LE-NAT-Log-Options Session-Failure-On 2
+VALUE LE-NAT-Log-Options Console-On 3
+VALUE LE-NAT-Log-Options Syslog-On 4
+VALUE LE-NAT-Log-Options Success-Off 5
+VALUE LE-NAT-Log-Options Failure-Off 6
+VALUE LE-NAT-Log-Options Console-Off 7
+VALUE LE-NAT-Log-Options Syslog-Off 8
+
+VALUE LE-Multicast-Client On 1
+
+END-VENDOR Livingston
diff --git a/share/dictionary.localweb b/share/dictionary.localweb
new file mode 100644
index 0000000..8b11a6d
--- /dev/null
+++ b/share/dictionary.localweb
@@ -0,0 +1,35 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Local-Web Accesspoints
+#
+##############################################################################
+
+VENDOR Local-Web 19220
+
+BEGIN-VENDOR Local-Web
+
+ATTRIBUTE Local-Web-Client-Ip 192 string
+ATTRIBUTE Local-Web-Border-Router 193 string
+
+ATTRIBUTE Local-Web-Tx-Limit 200 integer
+ATTRIBUTE Local-Web-Rx-Limit 201 integer
+
+ATTRIBUTE Local-Web-Acct-Time 210 integer
+ATTRIBUTE Local-Web-Acct-Duration 211 integer
+ATTRIBUTE Local-Web-Acct-Interim-Tx-Bytes 212 integer
+ATTRIBUTE Local-Web-Acct-Interim-Rx-Bytes 213 integer
+ATTRIBUTE Local-Web-Acct-Interim-Tx-Gigawords 214 integer
+ATTRIBUTE Local-Web-Acct-Interim-Rx-Gigawords 215 integer
+ATTRIBUTE Local-Web-Acct-Interim-Tx-Mgmt 216 integer
+ATTRIBUTE Local-Web-Acct-Interim-Rx-Mgmt 217 integer
+
+ATTRIBUTE Local-Web-Acct-Tx-Mgmt 230 integer
+ATTRIBUTE Local-Web-Acct-Rx-Mgmt 231 integer
+
+ATTRIBUTE Local-Web-Reauth-Counter 240 integer
+
+END-VENDOR Local-Web
diff --git a/share/dictionary.lucent b/share/dictionary.lucent
new file mode 100644
index 0000000..bf4bf88
--- /dev/null
+++ b/share/dictionary.lucent
@@ -0,0 +1,454 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Lucent VSAs, in their own "magic" 16-bit format.
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR Lucent 4846 format=2,1
+
+BEGIN-VENDOR Lucent
+
+ATTRIBUTE Lucent-Max-Shared-Users 2 integer
+ATTRIBUTE Lucent-IP-DSCP 3 integer
+ATTRIBUTE Lucent-X25-X121-Source-Address 4 string
+ATTRIBUTE Lucent-PPP-Circuit 5 integer
+ATTRIBUTE Lucent-PPP-Circuit-Name 6 string
+ATTRIBUTE Lucent-UU-Info 7 string
+ATTRIBUTE Lucent-User-Priority 8 integer
+ATTRIBUTE Lucent-CIR-Timer 9 integer
+ATTRIBUTE Lucent-FR-08-Mode 10 integer
+ATTRIBUTE Lucent-Destination-NAS-Port 11 integer
+ATTRIBUTE Lucent-FR-SVC-Addr 12 string
+ATTRIBUTE Lucent-NAS-Port-Format 13 integer
+ATTRIBUTE Lucent-ATM-Fault-Management 14 integer
+ATTRIBUTE Lucent-ATM-Loopback-Cell-Loss 15 integer
+ATTRIBUTE Lucent-Ckt-Type 16 integer
+ATTRIBUTE Lucent-SVC-Enabled 17 integer
+ATTRIBUTE Lucent-Session-Type 18 integer
+ATTRIBUTE Lucent-H323-Gatekeeper 19 ipaddr
+ATTRIBUTE Lucent-Global-Call-Id 20 string
+ATTRIBUTE Lucent-H323-Conference-Id 21 integer
+ATTRIBUTE Lucent-H323-Destination-NAS-ID 22 ipaddr
+ATTRIBUTE Lucent-H323-Dialed-Time 23 integer
+ATTRIBUTE Lucent-Dialed-Number 24 string
+ATTRIBUTE Lucent-Inter-Arrival-Jitter 25 integer
+ATTRIBUTE Lucent-Dropped-Octets 26 integer
+ATTRIBUTE Lucent-Dropped-Packets 27 integer
+ATTRIBUTE Lucent-Auth-Delay 28 integer
+ATTRIBUTE Lucent-X25-Pad-X3-Profile 29 integer
+ATTRIBUTE Lucent-X25-Pad-X3-Parameters 30 string
+ATTRIBUTE Lucent-Tunnel-VRouter-Name 31 string
+ATTRIBUTE Lucent-X25-Reverse-Charging 32 integer
+ATTRIBUTE Lucent-X25-Nui-Prompt 33 string
+ATTRIBUTE Lucent-X25-Nui-Password-Prompt 34 string
+ATTRIBUTE Lucent-X25-Cug 35 string
+ATTRIBUTE Lucent-X25-Pad-Alias-1 36 string
+ATTRIBUTE Lucent-X25-Pad-Alias-2 37 string
+ATTRIBUTE Lucent-X25-Pad-Alias-3 38 string
+ATTRIBUTE Lucent-X25-X121-Address 39 string
+ATTRIBUTE Lucent-X25-Nui 40 string
+ATTRIBUTE Lucent-X25-Rpoa 41 string
+ATTRIBUTE Lucent-X25-Pad-Prompt 42 string
+ATTRIBUTE Lucent-X25-Pad-Banner 43 string
+ATTRIBUTE Lucent-X25-Profile-Name 44 string
+ATTRIBUTE Lucent-Recv-Name 45 string
+ATTRIBUTE Lucent-Bi-Directional-Auth 46 integer
+ATTRIBUTE Lucent-MTU 47 integer
+ATTRIBUTE Lucent-Call-Direction 48 integer
+ATTRIBUTE Lucent-Service-Type 49 integer
+ATTRIBUTE Lucent-Filter-Required 50 integer
+ATTRIBUTE Lucent-Traffic-Shaper 51 integer
+ATTRIBUTE Lucent-Access-Intercept-LEA 52 string
+ATTRIBUTE Lucent-Access-Intercept-Log 53 string
+ATTRIBUTE Lucent-Private-Route-Table-ID 54 string
+ATTRIBUTE Lucent-Private-Route-Required 55 integer
+ATTRIBUTE Lucent-Cache-Refresh 56 integer
+ATTRIBUTE Lucent-Cache-Time 57 integer
+ATTRIBUTE Lucent-Egress-Enabled 58 integer
+ATTRIBUTE Lucent-QOS-Upstream 59 string
+ATTRIBUTE Lucent-QOS-Downstream 60 string
+ATTRIBUTE Lucent-ATM-Connect-Vpi 61 integer
+ATTRIBUTE Lucent-ATM-Connect-Vci 62 integer
+ATTRIBUTE Lucent-ATM-Connect-Group 63 integer
+ATTRIBUTE Lucent-ATM-Group 64 integer
+ATTRIBUTE Lucent-IPX-Header-Compression 65 integer
+ATTRIBUTE Lucent-Calling-Id-Type-Of-Number 66 integer
+ATTRIBUTE Lucent-Calling-Id-Numbering-Plan 67 integer
+ATTRIBUTE Lucent-Calling-Id-Presentation 68 integer
+ATTRIBUTE Lucent-Calling-Id-Screening 69 integer
+ATTRIBUTE Lucent-BIR-Enable 70 integer
+ATTRIBUTE Lucent-BIR-Proxy 71 integer
+ATTRIBUTE Lucent-BIR-Bridge-Group 72 integer
+ATTRIBUTE Lucent-IPSEC-Profile 73 string
+ATTRIBUTE Lucent-PPPoE-Enable 74 integer
+ATTRIBUTE Lucent-Bridge-Non-PPPoE 75 integer
+ATTRIBUTE Lucent-ATM-Direct 76 integer
+ATTRIBUTE Lucent-ATM-Direct-Profile 77 string
+ATTRIBUTE Lucent-Client-Primary-WINS 78 ipaddr
+ATTRIBUTE Lucent-Client-Secondary-WINS 79 ipaddr
+ATTRIBUTE Lucent-Client-Assign-WINS 80 integer
+ATTRIBUTE Lucent-Auth-Type 81 integer
+ATTRIBUTE Lucent-Port-Redir-Protocol 82 integer
+ATTRIBUTE Lucent-Port-Redir-Portnum 83 integer
+ATTRIBUTE Lucent-Port-Redir-Server 84 ipaddr
+ATTRIBUTE Lucent-IP-Pool-Chaining 85 integer
+ATTRIBUTE Lucent-Owner-IP-Addr 86 ipaddr
+ATTRIBUTE Lucent-IP-TOS 87 integer
+ATTRIBUTE Lucent-IP-TOS-Precedence 88 integer
+ATTRIBUTE Lucent-IP-TOS-Apply-To 89 integer
+ATTRIBUTE Lucent-Filter 90 string
+ATTRIBUTE Lucent-Telnet-Profile 91 string
+ATTRIBUTE Lucent-Dsl-Rate-Type 92 integer
+ATTRIBUTE Lucent-Redirect-Number 93 string
+ATTRIBUTE Lucent-ATM-Vpi 94 integer
+ATTRIBUTE Lucent-ATM-Vci 95 integer
+ATTRIBUTE Lucent-Source-IP-Check 96 integer
+ATTRIBUTE Lucent-Dsl-Rate-Mode 97 integer
+ATTRIBUTE Lucent-Dsl-Upstream-Limit 98 integer
+ATTRIBUTE Lucent-Dsl-Downstream-Limit 99 integer
+ATTRIBUTE Lucent-Dsl-CIR-Recv-Limit 100 integer
+ATTRIBUTE Lucent-Dsl-CIR-Xmit-Limit 101 integer
+ATTRIBUTE Lucent-VRouter-Name 102 string
+ATTRIBUTE Lucent-Source-Auth 103 string
+ATTRIBUTE Lucent-Private-Route 104 string
+ATTRIBUTE Lucent-Numbering-Plan-ID 105 integer
+ATTRIBUTE Lucent-FR-Link-Status-DLCI 106 integer
+ATTRIBUTE Lucent-Calling-Subaddress 107 string
+ATTRIBUTE Lucent-Callback-Delay 108 integer
+ATTRIBUTE Lucent-Endpoint-Disc 109 octets
+ATTRIBUTE Lucent-Remote-FW 110 string
+ATTRIBUTE Lucent-Multicast-GLeave-Delay 111 integer
+ATTRIBUTE Lucent-CBCP-Enable 112 integer
+ATTRIBUTE Lucent-CBCP-Mode 113 integer
+ATTRIBUTE Lucent-CBCP-Delay 114 integer
+ATTRIBUTE Lucent-CBCP-Trunk-Group 115 integer
+ATTRIBUTE Lucent-Appletalk-Route 116 string
+ATTRIBUTE Lucent-Appletalk-Peer-Mode 117 integer
+ATTRIBUTE Lucent-Route-Appletalk 118 integer
+ATTRIBUTE Lucent-FCP-Parameter 119 string
+ATTRIBUTE Lucent-Modem-PortNo 120 integer
+ATTRIBUTE Lucent-Modem-SlotNo 121 integer
+ATTRIBUTE Lucent-Modem-ShelfNo 122 integer
+ATTRIBUTE Lucent-Call-Attempt-Limit 123 integer
+ATTRIBUTE Lucent-Call-Block-Duration 124 integer
+ATTRIBUTE Lucent-Maximum-Call-Duration 125 integer
+ATTRIBUTE Lucent-Route-Preference 126 integer
+ATTRIBUTE Lucent-Tunneling-Protocol 127 integer
+ATTRIBUTE Lucent-Shared-Profile-Enable 128 integer
+ATTRIBUTE Lucent-Primary-Home-Agent 129 string
+ATTRIBUTE Lucent-Secondary-Home-Agent 130 string
+ATTRIBUTE Lucent-Dialout-Allowed 131 integer
+ATTRIBUTE Lucent-Client-Gateway 132 ipaddr
+ATTRIBUTE Lucent-BACP-Enable 133 integer
+ATTRIBUTE Lucent-DHCP-Maximum-Leases 134 integer
+ATTRIBUTE Lucent-Client-Primary-DNS 135 ipaddr
+ATTRIBUTE Lucent-Client-Secondary-DNS 136 ipaddr
+ATTRIBUTE Lucent-Client-Assign-DNS 137 integer
+ATTRIBUTE Lucent-User-Acct-Type 138 integer
+ATTRIBUTE Lucent-User-Acct-Host 139 ipaddr
+ATTRIBUTE Lucent-User-Acct-Port 140 integer
+ATTRIBUTE Lucent-User-Acct-Key 141 string
+ATTRIBUTE Lucent-User-Acct-Base 142 integer
+ATTRIBUTE Lucent-User-Acct-Time 143 integer
+ATTRIBUTE Lucent-Assign-IP-Client 144 ipaddr
+ATTRIBUTE Lucent-Assign-IP-Server 145 ipaddr
+ATTRIBUTE Lucent-Assign-IP-Global-Pool 146 string
+ATTRIBUTE Lucent-DHCP-Reply 147 integer
+ATTRIBUTE Lucent-DHCP-Pool-Number 148 integer
+ATTRIBUTE Lucent-Expect-Callback 149 integer
+ATTRIBUTE Lucent-Event-Type 150 integer
+ATTRIBUTE Lucent-Session-Svr-Key 151 string
+ATTRIBUTE Lucent-Multicast-Rate-Limit 152 integer
+ATTRIBUTE Lucent-IF-Netmask 153 ipaddr
+ATTRIBUTE Lucent-Remote-Addr 154 ipaddr
+ATTRIBUTE Lucent-Multicast-Client 155 integer
+ATTRIBUTE Lucent-FR-Circuit-Name 156 string
+ATTRIBUTE Lucent-FR-LinkUp 157 integer
+ATTRIBUTE Lucent-FR-Nailed-Grp 158 integer
+ATTRIBUTE Lucent-FR-Type 159 integer
+ATTRIBUTE Lucent-FR-Link-Mgt 160 integer
+ATTRIBUTE Lucent-FR-N391 161 integer
+ATTRIBUTE Lucent-FR-DCE-N392 162 integer
+ATTRIBUTE Lucent-FR-DTE-N392 163 integer
+ATTRIBUTE Lucent-FR-DCE-N393 164 integer
+ATTRIBUTE Lucent-FR-DTE-N393 165 integer
+ATTRIBUTE Lucent-FR-T391 166 integer
+ATTRIBUTE Lucent-FR-T392 167 integer
+ATTRIBUTE Lucent-Bridge-Address 168 string
+ATTRIBUTE Lucent-TS-Idle-Limit 169 integer
+ATTRIBUTE Lucent-TS-Idle-Mode 170 integer
+ATTRIBUTE Lucent-DBA-Monitor 171 integer
+ATTRIBUTE Lucent-Base-Channel-Count 172 integer
+ATTRIBUTE Lucent-Minimum-Channels 173 integer
+ATTRIBUTE Lucent-IPX-Route 174 string
+ATTRIBUTE Lucent-FT1-Caller 175 integer
+ATTRIBUTE Lucent-Backup 176 string
+ATTRIBUTE Lucent-Call-Type 177 integer
+ATTRIBUTE Lucent-Group 178 string
+ATTRIBUTE Lucent-FR-DLCI 179 integer
+ATTRIBUTE Lucent-FR-Profile-Name 180 string
+ATTRIBUTE Lucent-Ara-PW 181 string
+ATTRIBUTE Lucent-IPX-Node-Addr 182 string
+ATTRIBUTE Lucent-Home-Agent-IP-Addr 183 ipaddr
+ATTRIBUTE Lucent-Home-Agent-Password 184 string
+ATTRIBUTE Lucent-Home-Network-Name 185 string
+ATTRIBUTE Lucent-Home-Agent-UDP-Port 186 integer
+ATTRIBUTE Lucent-Multilink-ID 187 integer
+ATTRIBUTE Lucent-Num-In-Multilink 188 integer
+ATTRIBUTE Lucent-First-Dest 189 ipaddr
+ATTRIBUTE Lucent-Pre-Input-Octets 190 integer
+ATTRIBUTE Lucent-Pre-Output-Octets 191 integer
+ATTRIBUTE Lucent-Pre-Input-Packets 192 integer
+ATTRIBUTE Lucent-Pre-Output-Packets 193 integer
+ATTRIBUTE Lucent-Maximum-Time 194 integer
+ATTRIBUTE Lucent-Disconnect-Cause 195 integer
+ATTRIBUTE Lucent-Connect-Progress 196 integer
+ATTRIBUTE Lucent-Data-Rate 197 integer
+ATTRIBUTE Lucent-PreSession-Time 198 integer
+ATTRIBUTE Lucent-Token-Idle 199 integer
+ATTRIBUTE Lucent-Token-Immediate 200 integer
+ATTRIBUTE Lucent-Require-Auth 201 integer
+ATTRIBUTE Lucent-Number-Sessions 202 string
+ATTRIBUTE Lucent-Authen-Alias 203 string
+ATTRIBUTE Lucent-Token-Expiry 204 integer
+ATTRIBUTE Lucent-Menu-Selector 205 string
+ATTRIBUTE Lucent-Menu-Item 206 string
+ATTRIBUTE Lucent-PW-Warntime 207 integer
+ATTRIBUTE Lucent-PW-Lifetime 208 integer
+ATTRIBUTE Lucent-IP-Direct 209 ipaddr
+ATTRIBUTE Lucent-PPP-VJ-Slot-Comp 210 integer
+ATTRIBUTE Lucent-PPP-VJ-1172 211 integer
+ATTRIBUTE Lucent-PPP-Async-Map 212 integer
+ATTRIBUTE Lucent-Third-Prompt 213 string
+ATTRIBUTE Lucent-Send-Secret 214 string encrypt=3
+ATTRIBUTE Lucent-Receive-Secret 215 string encrypt=3
+ATTRIBUTE Lucent-IPX-Peer-Mode 216 integer
+ATTRIBUTE Lucent-IP-Pool-Definition 217 string
+ATTRIBUTE Lucent-Assign-IP-Pool 218 integer
+ATTRIBUTE Lucent-FR-Direct 219 integer
+ATTRIBUTE Lucent-FR-Direct-Profile 220 string
+ATTRIBUTE Lucent-FR-Direct-DLCI 221 integer
+ATTRIBUTE Lucent-Handle-IPX 222 integer
+ATTRIBUTE Lucent-Netware-timeout 223 integer
+ATTRIBUTE Lucent-IPX-Alias 224 integer
+ATTRIBUTE Lucent-Metric 225 integer
+ATTRIBUTE Lucent-PRI-Number-Type 226 integer
+ATTRIBUTE Lucent-Dial-Number 227 string
+ATTRIBUTE Lucent-Route-IP 228 integer
+ATTRIBUTE Lucent-Route-IPX 229 integer
+ATTRIBUTE Lucent-Bridge 230 integer
+ATTRIBUTE Lucent-Send-Auth 231 integer
+ATTRIBUTE Lucent-Send-Passwd 232 string
+ATTRIBUTE Lucent-Link-Compression 233 integer
+ATTRIBUTE Lucent-Target-Util 234 integer
+ATTRIBUTE Lucent-Maximum-Channels 235 integer
+ATTRIBUTE Lucent-Inc-Channel-Count 236 integer
+ATTRIBUTE Lucent-Dec-Channel-Count 237 integer
+ATTRIBUTE Lucent-Seconds-Of-History 238 integer
+ATTRIBUTE Lucent-History-Weigh-Type 239 integer
+ATTRIBUTE Lucent-Add-Seconds 240 integer
+ATTRIBUTE Lucent-Remove-Seconds 241 integer
+ATTRIBUTE Lucent-Data-Filter 242 abinary
+ATTRIBUTE Lucent-Call-Filter 243 abinary
+ATTRIBUTE Lucent-Idle-Limit 244 integer
+ATTRIBUTE Lucent-Preempt-Limit 245 integer
+ATTRIBUTE Lucent-Callback 246 integer
+ATTRIBUTE Lucent-Data-Svc 247 integer
+ATTRIBUTE Lucent-Force-56 248 integer
+ATTRIBUTE Lucent-Billing-Number 249 string
+ATTRIBUTE Lucent-Call-By-Call 250 integer
+ATTRIBUTE Lucent-Transit-Number 251 string
+ATTRIBUTE Lucent-Host-Info 252 string
+ATTRIBUTE Lucent-PPP-Address 253 ipaddr
+ATTRIBUTE Lucent-MPP-Idle-Percent 254 integer
+ATTRIBUTE Lucent-Xmit-Rate 255 integer
+ATTRIBUTE Lucent-Fr05-Traffic-Shaper 256 integer
+ATTRIBUTE Lucent-Fr05-Vpi 257 integer
+ATTRIBUTE Lucent-Fr05-Vci 258 integer
+ATTRIBUTE Lucent-Fr05-Enabled 259 integer
+ATTRIBUTE Lucent-Tunnel-Auth-Type 260 octets # tag?
+ATTRIBUTE Lucent-MOH-Timeout 261 integer
+ATTRIBUTE Lucent-ATM-Circuit-Name 262 string
+ATTRIBUTE Lucent-Priority-For-PPP 263 integer
+ATTRIBUTE Lucent-Max-RTP-Delay 264 integer
+ATTRIBUTE Lucent-RTP-Port-Range 265 string
+ATTRIBUTE Lucent-TOS-Copying 266 integer
+ATTRIBUTE Lucent-Packet-Classification 267 integer
+ATTRIBUTE Lucent-No-High-Prio-Pkt-Duratio 268 integer
+ATTRIBUTE Lucent-AT-Answer-String 269 string
+ATTRIBUTE Lucent-IP-OUTGOING-TOS 270 integer
+ATTRIBUTE Lucent-IP-OUTGOING-TOS-Precedence 271 integer
+ATTRIBUTE Lucent-IP-OUTGOING-DSCP 272 integer
+ATTRIBUTE Lucent-TermSrv-Login-Prompt 273 string
+ATTRIBUTE Lucent-Multicast-Service-Profile-Name 274 string
+ATTRIBUTE Lucent-Multicast-Max-Groups 275 integer
+ATTRIBUTE Lucent-Multicast-Service-Name 276 string
+ATTRIBUTE Lucent-Multicast-Service-Active 277 integer
+ATTRIBUTE Lucent-Multicast-Service-Snmp-Trap 278 integer
+ATTRIBUTE Lucent-Multicast-Service-Filter-Type 279 integer
+ATTRIBUTE Lucent-Multicast-Filter-Active 280 integer
+ATTRIBUTE Lucent-Multicast-Filter-Address 281 ipaddr
+ATTRIBUTE Lucent-Tunnel-TOS 282 integer
+ATTRIBUTE Lucent-Tunnel-TOS-Precedence 283 integer
+ATTRIBUTE Lucent-Tunnel-DSCP 284 integer
+ATTRIBUTE Lucent-Tunnel-TOS-Filter 285 string
+ATTRIBUTE Lucent-Tunnel-TOS-Copy 286 integer
+ATTRIBUTE Lucent-Http-Redirect-URL 287 string
+ATTRIBUTE Lucent-Http-Redirect-Port 288 integer
+ATTRIBUTE Lucent-L2TP-DCI-Disconnect-Code 289 integer
+ATTRIBUTE Lucent-L2TP-DCI-Protocol-Number 290 integer
+ATTRIBUTE Lucent-L2TP-DCI-Direction 291 integer
+ATTRIBUTE Lucent-L2TP-DCI-Message 292 string
+ATTRIBUTE Lucent-L2TP-Q931-Cause-Code 293 integer
+ATTRIBUTE Lucent-L2TP-Q931-Cause-Message 294 integer
+ATTRIBUTE Lucent-L2TP-Q931-Advisory-Message 295 string
+ATTRIBUTE Lucent-L2TP-RC-Result-Code 296 integer
+ATTRIBUTE Lucent-L2TP-RC-Error-Code 297 integer
+ATTRIBUTE Lucent-L2TP-RC-Error-Message 298 string
+ATTRIBUTE Lucent-L2TP-Disconnect-Scenario 299 integer
+ATTRIBUTE Lucent-L2TP-Peer-Disconnect-Cause 300 integer
+ATTRIBUTE Lucent-L2TP-Peer-Connect-Progress 301 integer
+ATTRIBUTE Lucent-QuickConnect-Attempted 302 integer
+ATTRIBUTE Lucent-Num-Moh-Sessions 303 integer
+ATTRIBUTE Lucent-Cumulative-Hold-Time 304 integer
+ATTRIBUTE Lucent-Modem-Modulation 305 integer
+ATTRIBUTE Lucent-User-Acct-Expiration 306 date
+ATTRIBUTE Lucent-User-Login-Level 307 integer
+ATTRIBUTE Lucent-First-Level-User 308 string
+ATTRIBUTE Lucent-IP-Source-If 309 string
+ATTRIBUTE Lucent-Reverse-Path-Check 310 integer
+ATTRIBUTE Lucent-LCP-Keepalive-Period 321 integer
+ATTRIBUTE Lucent-LCP-Keepalive-Missed-Limit 322 integer
+ATTRIBUTE Lucent-Dsl-Atuc-Chan-Uncorrect-Blks 10000 integer
+ATTRIBUTE Lucent-Dsl-Atuc-Chan-Corrected-Blks 10001 integer
+ATTRIBUTE Lucent-Dsl-Atuc-Chan-Xmit-Blks 10002 integer
+ATTRIBUTE Lucent-Dsl-Atuc-Chan-Recd-Blks 10003 integer
+ATTRIBUTE Lucent-Dsl-Atuc-Perf-Inits 10004 integer
+ATTRIBUTE Lucent-Dsl-Atuc-Perf-ESs 10005 integer
+ATTRIBUTE Lucent-Dsl-Atuc-Perf-Lprs 10006 integer
+ATTRIBUTE Lucent-Dsl-Atuc-Perf-Lols 10007 integer
+ATTRIBUTE Lucent-Dsl-Atuc-Perf-Loss 10008 integer
+ATTRIBUTE Lucent-Dsl-Atuc-Perf-Lofs 10009 integer
+ATTRIBUTE Lucent-Dsl-Atuc-Curr-Attainable-Rate-Dn 10010 integer
+ATTRIBUTE Lucent-Dsl-Atuc-Curr-Output-Pwr-Dn 10011 integer
+ATTRIBUTE Lucent-Dsl-Atuc-Curr-Atn-Up 10012 integer
+ATTRIBUTE Lucent-Dsl-Atuc-Curr-Snr-Mgn-Up 10013 integer
+#ATTRIBUTE Lucent-Dsl-Atuc-Perf-Stat-Fast-Retrains 10014 integer
+#ATTRIBUTE Lucent-Dsl-Atuc-Perf-Stat-Failed-Fast-Retrains 10015 integer
+
+# FIXME when we can deal with long attribute names.
+ATTRIBUTE Lucent-Dsl-Atuc-PS-Fast-Retrains 10014 integer
+ATTRIBUTE Lucent-Dsl-Atuc-PS-Failed-Fast-Retrains 10015 integer
+
+ATTRIBUTE Lucent-Dsl-Code-Violations 10016 integer
+ATTRIBUTE Lucent-Line-Type 10017 integer
+ATTRIBUTE Lucent-Dsl-Curr-Up-Rate 10018 integer
+ATTRIBUTE Lucent-Dsl-Curr-Dn-Rate 10019 integer
+ATTRIBUTE Lucent-Dsl-Physical-Slot 10020 integer
+ATTRIBUTE Lucent-Dsl-Physical-Line 10021 integer
+ATTRIBUTE Lucent-Dsl-If-Index 10022 integer
+ATTRIBUTE Lucent-Dsl-Oper-Status 10023 integer
+ATTRIBUTE Lucent-Dsl-Related-If-Index 10024 integer
+ATTRIBUTE Lucent-Dsl-Atuc-Curr-Attainable-Rate-Up 10025 integer
+ATTRIBUTE Lucent-Dsl-Atuc-Curr-Output-Pwr-Up 10026 integer
+ATTRIBUTE Lucent-Dsl-Atuc-Curr-Atn-Dn 10027 integer
+ATTRIBUTE Lucent-Dsl-Atuc-Curr-Snr-Mgn-D 10028 integer
+ATTRIBUTE Lucent-Dsl-Related-Slot 10029 integer
+ATTRIBUTE Lucent-Dsl-Related-Port 10030 integer
+ATTRIBUTE Lucent-Dsl-Sparing-Role 10031 integer
+ATTRIBUTE Lucent-Absolute-Time 10032 integer
+ATTRIBUTE Lucent-Configured-Rate-Up-Min 10033 integer
+ATTRIBUTE Lucent-Configured-Rate-Up-Max 10034 integer
+ATTRIBUTE Lucent-Configured-Rate-Dn-Min 10035 integer
+ATTRIBUTE Lucent-Configured-Rate-Dn-Max 10036 integer
+ATTRIBUTE Lucent-Dsl-Physical-Channel 10037 integer
+ATTRIBUTE Lucent-Sonet-Section-ESs 10100 integer
+ATTRIBUTE Lucent-Sonet-Section-SESs 10101 integer
+ATTRIBUTE Lucent-Sonet-Section-SEFSs 10102 integer
+ATTRIBUTE Lucent-Sonet-Section-CVs 10103 integer
+ATTRIBUTE Lucent-Sonet-Line-ESs-Near 10104 integer
+ATTRIBUTE Lucent-Sonet-Line-SESs-Near 10105 integer
+ATTRIBUTE Lucent-Sonet-Line-CVs-Near 10106 integer
+ATTRIBUTE Lucent-Sonet-Line-USs-Near 10107 integer
+ATTRIBUTE Lucent-Sonet-Line-ESs-Far 10108 integer
+ATTRIBUTE Lucent-Sonet-Line-SESs-Far 10109 integer
+ATTRIBUTE Lucent-Sonet-Line-CVs-Far 10110 integer
+ATTRIBUTE Lucent-Sonet-Line-USs-Far 10111 integer
+ATTRIBUTE Lucent-Sonet-Path-ESs-Near 10112 integer
+ATTRIBUTE Lucent-Sonet-Path-SESs-Near 10113 integer
+ATTRIBUTE Lucent-Sonet-Path-CVs-Near 10114 integer
+ATTRIBUTE Lucent-Sonet-Path-USs-Near 10115 integer
+ATTRIBUTE Lucent-Sonet-Path-ESs-Far 10116 integer
+ATTRIBUTE Lucent-Sonet-Path-SESs-Far 10117 integer
+ATTRIBUTE Lucent-Sonet-Path-CVs-Far 10118 integer
+ATTRIBUTE Lucent-Sonet-Path-USs-Far 10119 integer
+ATTRIBUTE Lucent-Ds3-F-Bit-Err 10200 integer
+ATTRIBUTE Lucent-Ds3-P-Bit-Err 10201 integer
+ATTRIBUTE Lucent-Ds3-CCVs 10202 integer
+ATTRIBUTE Lucent-Ds3-PESs 10203 integer
+ATTRIBUTE Lucent-Ds3-PSESs 10204 integer
+ATTRIBUTE Lucent-Ds3-SEFs 10205 integer
+ATTRIBUTE Lucent-Ds3-UASs 10206 integer
+ATTRIBUTE Lucent-Ds3-LCVs 10207 integer
+ATTRIBUTE Lucent-Ds3-PCVs 10208 integer
+ATTRIBUTE Lucent-Ds3-LESs 10209 integer
+ATTRIBUTE Lucent-Ds3-CESs 10210 integer
+ATTRIBUTE Lucent-Ds3-CSESs 10211 integer
+ATTRIBUTE Lucent-Rtp-Local-Number-Of-Samples 10300 integer
+ATTRIBUTE Lucent-Rtp-Remote-Number-Of-Samples 10301 integer
+ATTRIBUTE Lucent-Rtp-Local-Jitter-Minimum 10302 integer
+ATTRIBUTE Lucent-Rtp-Local-Jitter-Maximum 10303 integer
+ATTRIBUTE Lucent-Rtp-Local-Jitter-Mean 10304 integer
+ATTRIBUTE Lucent-Rtp-Local-Jitter-Variance 10305 integer
+ATTRIBUTE Lucent-Rtp-Local-Delay-Minimum 10306 integer
+ATTRIBUTE Lucent-Rtp-Local-Delay-Maximum 10307 integer
+ATTRIBUTE Lucent-Rtp-Local-Delay-Mean 10308 integer
+ATTRIBUTE Lucent-Rtp-Local-Delay-Variance 10309 integer
+ATTRIBUTE Lucent-Rtp-Local-Packets-Sent 10310 integer
+ATTRIBUTE Lucent-Rtp-Local-Packets-Lost 10311 integer
+ATTRIBUTE Lucent-Rtp-Local-Packets-Late 10312 integer
+ATTRIBUTE Lucent-Rtp-Local-Bytes-Sent 10313 integer
+ATTRIBUTE Lucent-Rtp-Local-Silence-Percent 10314 integer
+ATTRIBUTE Lucent-Rtp-Remote-Jitter-Minimum 10315 integer
+ATTRIBUTE Lucent-Rtp-Remote-Jitter-Maximum 10316 integer
+ATTRIBUTE Lucent-Rtp-Remote-Jitter-Mean 10317 integer
+ATTRIBUTE Lucent-Rtp-Remote-Jitter-Variance 10318 integer
+ATTRIBUTE Lucent-Rtp-Remote-Delay-Minimum 10319 integer
+ATTRIBUTE Lucent-Rtp-Remote-Delay-Maximum 10320 integer
+ATTRIBUTE Lucent-Rtp-Remote-Delay-Mean 10321 integer
+ATTRIBUTE Lucent-Rtp-Remote-Delay-Variance 10322 integer
+ATTRIBUTE Lucent-Rtp-Remote-Packets-Sent 10323 integer
+ATTRIBUTE Lucent-Rtp-Remote-Packets-Lost 10324 integer
+ATTRIBUTE Lucent-Rtp-Remote-Packets-Late 10325 integer
+ATTRIBUTE Lucent-Rtp-Remote-Bytes-Sent 10326 integer
+ATTRIBUTE Lucent-Rtp-Remote-Silence-Percent 10327 integer
+ATTRIBUTE Lucent-Tunnel-Auth-Type2 19999 integer
+ATTRIBUTE Lucent-Multi-Packet-Separator 20000 integer
+ATTRIBUTE Lucent-Min-Xmit-Rate 20100 integer
+ATTRIBUTE Lucent-Max-Xmit-Rate 20101 integer
+ATTRIBUTE Lucent-Min-Recv-Rate 20102 integer
+ATTRIBUTE Lucent-Max-Recv-Rate 20103 integer
+ATTRIBUTE Lucent-Error-Correction-Protocol 20104 integer
+ATTRIBUTE Lucent-Compression-Protocol 20105 integer
+ATTRIBUTE Lucent-Modulation 20106 integer
+ATTRIBUTE Lucent-Xmit-Symbol-Rate 20107 integer
+ATTRIBUTE Lucent-Recv-Symbol-Rate 20108 integer
+ATTRIBUTE Lucent-Current-Xmit-Level 20109 integer
+ATTRIBUTE Lucent-Current-Recv-Level 20110 integer
+ATTRIBUTE Lucent-Current-Line-Quality 20111 integer
+ATTRIBUTE Lucent-Current-SNR 20112 integer
+ATTRIBUTE Lucent-Min-SNR 20113 integer
+ATTRIBUTE Lucent-Max-SNR 20114 integer
+ATTRIBUTE Lucent-Local-Retrain-Requested 20115 integer
+ATTRIBUTE Lucent-Remote-Retrain-Requested 20116 integer
+ATTRIBUTE Lucent-Connection-Time 20117 integer
+ATTRIBUTE Lucent-Modem-Disconnect-Reason 20118 integer
+ATTRIBUTE Lucent-Retrain-Reason 20119 integer
+
+END-VENDOR Lucent
diff --git a/share/dictionary.manzara b/share/dictionary.manzara
new file mode 100644
index 0000000..5fce3d4
--- /dev/null
+++ b/share/dictionary.manzara
@@ -0,0 +1,33 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+VENDOR Manzara 19382
+
+BEGIN-VENDOR Manzara
+
+ATTRIBUTE Manzara-User-UID 1 integer
+ATTRIBUTE Manzara-User-GID 2 integer
+ATTRIBUTE Manzara-User-Home 3 string
+ATTRIBUTE Manzara-User-Shell 4 string
+ATTRIBUTE Manzara-PPP-Addr-String 5 string
+ATTRIBUTE Manzara-Full-Login-String 6 string
+ATTRIBUTE Manzara-Tariff-Units 7 integer
+ATTRIBUTE Manzara-Tariff-Type 8 integer
+ATTRIBUTE Manzara-ECP-Session-Key 9 octets
+ATTRIBUTE Manzara-Map-Name 10 string
+ATTRIBUTE Manzara-Map-Key 11 string
+ATTRIBUTE Manzara-Map-Value 12 string
+ATTRIBUTE Manzara-Map-Error 13 string
+ATTRIBUTE Manzara-Service-Type 14 string
+
+VALUE Manzara-Tariff-Type MMS-Picture 1
+VALUE Manzara-Tariff-Type Unused 2
+VALUE Manzara-Tariff-Type Internet 3
+
+#
+# Poaching on the standard space is wrong.
+#
+VALUE Acct-Status-Type One-Time 17
+
+END-VENDOR Manzara
diff --git a/share/dictionary.meinberg b/share/dictionary.meinberg
new file mode 100644
index 0000000..b57ea84
--- /dev/null
+++ b/share/dictionary.meinberg
@@ -0,0 +1,19 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Meinberg
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR Meinberg 5597
+
+BEGIN-VENDOR Meinberg
+
+ATTRIBUTE MBG-Management-Privilege-Level 1 integer
+
+END-VENDOR Meinberg
diff --git a/share/dictionary.mellanox b/share/dictionary.mellanox
new file mode 100644
index 0000000..4da5c34
--- /dev/null
+++ b/share/dictionary.mellanox
@@ -0,0 +1,18 @@
+# -*- text -*-
+# Copyright (C) 2021 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# dictionary.mellanox
+#
+# Discovered by Aaron Knister <aaron.knister@gmail.com>
+#
+#
+# Version $Id$
+
+VENDOR Mellanox 33049
+
+BEGIN-VENDOR Mellanox
+
+ATTRIBUTE Mellanox-Local-User-Name 1 string
+
+END-VENDOR Mellanox
diff --git a/share/dictionary.meraki b/share/dictionary.meraki
new file mode 100644
index 0000000..eb69f5e
--- /dev/null
+++ b/share/dictionary.meraki
@@ -0,0 +1,15 @@
+# -*- text -*-
+# Copyright (C) 2015 The FreeRADIUS Server project and contributors
+#
+# For Meraki.
+#
+
+VENDOR Meraki 29671
+BEGIN-VENDOR Meraki
+
+ATTRIBUTE Meraki-Device-Name 1 string
+ATTRIBUTE Meraki-Network-Name 2 string
+ATTRIBUTE Meraki-Ap-Name 3 string
+ATTRIBUTE Meraki-Ap-Tags 4 string
+
+END-VENDOR Meraki
diff --git a/share/dictionary.merit b/share/dictionary.merit
new file mode 100644
index 0000000..cc95c8a
--- /dev/null
+++ b/share/dictionary.merit
@@ -0,0 +1,17 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# For Merit.
+#
+# $Id$
+#
+VENDOR Merit 61
+
+BEGIN-VENDOR Merit
+
+ATTRIBUTE Merit-Proxy-Action 211 string
+ATTRIBUTE Merit-User-Id 222 string
+ATTRIBUTE Merit-User-Realm 223 string
+
+END-VENDOR Merit
diff --git a/share/dictionary.meru b/share/dictionary.meru
new file mode 100644
index 0000000..b5cee24
--- /dev/null
+++ b/share/dictionary.meru
@@ -0,0 +1,18 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# dictionary.meru
+#
+# $Id$
+#
+#
+VENDOR Meru 15983
+
+BEGIN-VENDOR Meru
+
+ATTRIBUTE Meru-Access-Point-Id 1 integer
+ATTRIBUTE Meru-Access-Point-Name 2 string
+
+END-VENDOR Meru
+
diff --git a/share/dictionary.microsemi b/share/dictionary.microsemi
new file mode 100644
index 0000000..68967fa
--- /dev/null
+++ b/share/dictionary.microsemi
@@ -0,0 +1,22 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# As posted to the list by Simon Butcher <simon.butcher@microsemi.com>
+#
+# Version: $Id$
+#
+
+VENDOR Microsemi 40676
+
+BEGIN-VENDOR Microsemi
+
+ATTRIBUTE Microsemi-User-Full-Name 1 string
+ATTRIBUTE Microsemi-User-Name 2 string
+ATTRIBUTE Microsemi-User-Initials 3 string
+ATTRIBUTE Microsemi-User-Email 4 string
+ATTRIBUTE Microsemi-User-Group 5 string
+ATTRIBUTE Microsemi-Fallback-User-Group 6 string
+ATTRIBUTE Microsemi-Network-Element-Group 7 string
+
+END-VENDOR Microsemi
diff --git a/share/dictionary.microsoft b/share/dictionary.microsoft
new file mode 100644
index 0000000..6ba9dd5
--- /dev/null
+++ b/share/dictionary.microsoft
@@ -0,0 +1,170 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Microsoft's VSA's, from RFC 2548
+#
+# $Id$
+#
+
+VENDOR Microsoft 311
+
+BEGIN-VENDOR Microsoft
+ATTRIBUTE MS-CHAP-Response 1 octets[50]
+ATTRIBUTE MS-CHAP-Error 2 string
+ATTRIBUTE MS-CHAP-CPW-1 3 octets[70]
+ATTRIBUTE MS-CHAP-CPW-2 4 octets[84]
+ATTRIBUTE MS-CHAP-LM-Enc-PW 5 octets
+ATTRIBUTE MS-CHAP-NT-Enc-PW 6 octets
+ATTRIBUTE MS-MPPE-Encryption-Policy 7 integer
+
+VALUE MS-MPPE-Encryption-Policy Encryption-Allowed 1
+VALUE MS-MPPE-Encryption-Policy Encryption-Required 2
+
+# This is referred to as both singular and plural in the RFC.
+# Plural seems to make more sense.
+ATTRIBUTE MS-MPPE-Encryption-Type 8 integer
+ATTRIBUTE MS-MPPE-Encryption-Types 8 integer
+
+VALUE MS-MPPE-Encryption-Types RC4-40bit-Allowed 1
+VALUE MS-MPPE-Encryption-Types RC4-128bit-Allowed 2
+VALUE MS-MPPE-Encryption-Types RC4-40or128-bit-Allowed 6
+
+ATTRIBUTE MS-RAS-Vendor 9 integer # content is Vendor-ID
+ATTRIBUTE MS-CHAP-Domain 10 string
+ATTRIBUTE MS-CHAP-Challenge 11 octets
+ATTRIBUTE MS-CHAP-MPPE-Keys 12 octets[24] encrypt=1
+ATTRIBUTE MS-BAP-Usage 13 integer
+ATTRIBUTE MS-Link-Utilization-Threshold 14 integer # values are 1-100
+ATTRIBUTE MS-Link-Drop-Time-Limit 15 integer
+ATTRIBUTE MS-MPPE-Send-Key 16 octets encrypt=2
+ATTRIBUTE MS-MPPE-Recv-Key 17 octets encrypt=2
+ATTRIBUTE MS-RAS-Version 18 string
+ATTRIBUTE MS-Old-ARAP-Password 19 octets
+ATTRIBUTE MS-New-ARAP-Password 20 octets
+ATTRIBUTE MS-ARAP-PW-Change-Reason 21 integer
+
+ATTRIBUTE MS-Filter 22 octets
+ATTRIBUTE MS-Acct-Auth-Type 23 integer
+ATTRIBUTE MS-Acct-EAP-Type 24 integer
+
+ATTRIBUTE MS-CHAP2-Response 25 octets[50]
+ATTRIBUTE MS-CHAP2-Success 26 octets
+ATTRIBUTE MS-CHAP2-CPW 27 octets[68]
+
+ATTRIBUTE MS-Primary-DNS-Server 28 ipaddr
+ATTRIBUTE MS-Secondary-DNS-Server 29 ipaddr
+ATTRIBUTE MS-Primary-NBNS-Server 30 ipaddr
+ATTRIBUTE MS-Secondary-NBNS-Server 31 ipaddr
+
+#ATTRIBUTE MS-ARAP-Challenge 33 octets[8]
+
+## MS-RNAP
+#
+# http://download.microsoft.com/download/9/5/E/95EF66AF-9026-4BB0-A41D-A4F81802D92C/%5BMS-RNAP%5D.pdf
+
+ATTRIBUTE MS-RAS-Client-Name 34 string
+ATTRIBUTE MS-RAS-Client-Version 35 string
+ATTRIBUTE MS-Quarantine-IPFilter 36 octets
+ATTRIBUTE MS-Quarantine-Session-Timeout 37 integer
+ATTRIBUTE MS-User-Security-Identity 40 string
+ATTRIBUTE MS-Identity-Type 41 integer
+ATTRIBUTE MS-Service-Class 42 string
+ATTRIBUTE MS-Quarantine-User-Class 44 string
+ATTRIBUTE MS-Quarantine-State 45 integer
+ATTRIBUTE MS-Quarantine-Grace-Time 46 integer
+ATTRIBUTE MS-Network-Access-Server-Type 47 integer
+ATTRIBUTE MS-AFW-Zone 48 integer
+
+VALUE MS-AFW-Zone MS-AFW-Zone-Boundary-Policy 1
+VALUE MS-AFW-Zone MS-AFW-Zone-Unprotected-Policy 2
+VALUE MS-AFW-Zone MS-AFW-Zone-Protected-Policy 3
+
+ATTRIBUTE MS-AFW-Protection-Level 49 integer
+
+VALUE MS-AFW-Protection-Level HECP-Response-Sign-Only 1
+VALUE MS-AFW-Protection-Level HECP-Response-Sign-And-Encrypt 2
+
+ATTRIBUTE MS-Machine-Name 50 string
+ATTRIBUTE MS-IPv6-Filter 51 octets
+ATTRIBUTE MS-IPv4-Remediation-Servers 52 octets
+ATTRIBUTE MS-IPv6-Remediation-Servers 53 octets
+ATTRIBUTE MS-RNAP-Not-Quarantine-Capable 54 integer
+
+VALUE MS-RNAP-Not-Quarantine-Capable SoH-Sent 0
+VALUE MS-RNAP-Not-Quarantine-Capable SoH-Not-Sent 1
+
+ATTRIBUTE MS-Quarantine-SOH 55 octets
+ATTRIBUTE MS-RAS-Correlation 56 octets
+
+# Or this might be 56?
+ATTRIBUTE MS-Extended-Quarantine-State 57 integer
+
+ATTRIBUTE MS-HCAP-User-Groups 58 string
+ATTRIBUTE MS-HCAP-Location-Group-Name 59 string
+ATTRIBUTE MS-HCAP-User-Name 60 string
+ATTRIBUTE MS-User-IPv4-Address 61 ipaddr
+ATTRIBUTE MS-User-IPv6-Address 62 ipv6addr
+ATTRIBUTE MS-TSG-Device-Redirection 63 integer
+
+#
+# Integer Translations
+#
+
+# MS-BAP-Usage Values
+
+VALUE MS-BAP-Usage Not-Allowed 0
+VALUE MS-BAP-Usage Allowed 1
+VALUE MS-BAP-Usage Required 2
+
+# MS-ARAP-Password-Change-Reason Values
+
+VALUE MS-ARAP-PW-Change-Reason Just-Change-Password 1
+VALUE MS-ARAP-PW-Change-Reason Expired-Password 2
+VALUE MS-ARAP-PW-Change-Reason Admin-Requires-Password-Change 3
+VALUE MS-ARAP-PW-Change-Reason Password-Too-Short 4
+
+# MS-Acct-Auth-Type Values
+
+VALUE MS-Acct-Auth-Type PAP 1
+VALUE MS-Acct-Auth-Type CHAP 2
+VALUE MS-Acct-Auth-Type MS-CHAP-1 3
+VALUE MS-Acct-Auth-Type MS-CHAP-2 4
+VALUE MS-Acct-Auth-Type EAP 5
+
+# MS-Acct-EAP-Type Values
+
+VALUE MS-Acct-EAP-Type MD5 4
+VALUE MS-Acct-EAP-Type OTP 5
+VALUE MS-Acct-EAP-Type Generic-Token-Card 6
+VALUE MS-Acct-EAP-Type TLS 13
+
+# MS-Identity-Type Values
+
+VALUE MS-Identity-Type Machine-Health-Check 1
+VALUE MS-Identity-Type Ignore-User-Lookup-Failure 2
+
+# MS-Quarantine-State Values
+
+VALUE MS-Quarantine-State Full-Access 0
+VALUE MS-Quarantine-State Quarantine 1
+VALUE MS-Quarantine-State Probation 2
+
+# MS-Network-Access-Server-Type Values
+
+VALUE MS-Network-Access-Server-Type Unspecified 0
+VALUE MS-Network-Access-Server-Type Terminal-Server-Gateway 1
+VALUE MS-Network-Access-Server-Type Remote-Access-Server 2
+VALUE MS-Network-Access-Server-Type DHCP-Server 3
+VALUE MS-Network-Access-Server-Type Wireless-Access-Point 4
+VALUE MS-Network-Access-Server-Type HRA 5
+VALUE MS-Network-Access-Server-Type HCAP-Server 6
+
+# MS-Extended-Quarantine-State Values
+
+VALUE MS-Extended-Quarantine-State Transition 1
+VALUE MS-Extended-Quarantine-State Infected 2
+VALUE MS-Extended-Quarantine-State Unknown 3
+VALUE MS-Extended-Quarantine-State No-Data 4
+
+END-VENDOR Microsoft
diff --git a/share/dictionary.mikrotik b/share/dictionary.mikrotik
new file mode 100644
index 0000000..778b35a
--- /dev/null
+++ b/share/dictionary.mikrotik
@@ -0,0 +1,68 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# http://www.mikrotik.com
+#
+# http://www.mikrotik.com/documentation//manual_2.9/dictionary
+#
+# Do NOT follow their instructions and replace the dictionary
+# in /etc/raddb with the one that they supply. It is NOT necessary.
+#
+# On top of that, the sample dictionary file they provide
+# DOES NOT WORK. Do NOT use it.
+#
+# $Id$
+#
+VENDOR Mikrotik 14988
+
+BEGIN-VENDOR Mikrotik
+
+ATTRIBUTE Mikrotik-Recv-Limit 1 integer
+ATTRIBUTE Mikrotik-Xmit-Limit 2 integer
+
+# this attribute is unused
+ATTRIBUTE Mikrotik-Group 3 string
+
+ATTRIBUTE Mikrotik-Wireless-Forward 4 integer
+ATTRIBUTE Mikrotik-Wireless-Skip-Dot1x 5 integer
+ATTRIBUTE Mikrotik-Wireless-Enc-Algo 6 integer
+ATTRIBUTE Mikrotik-Wireless-Enc-Key 7 string
+ATTRIBUTE Mikrotik-Rate-Limit 8 string
+ATTRIBUTE Mikrotik-Realm 9 string
+ATTRIBUTE Mikrotik-Host-IP 10 ipaddr
+ATTRIBUTE Mikrotik-Mark-Id 11 string
+ATTRIBUTE Mikrotik-Advertise-URL 12 string
+ATTRIBUTE Mikrotik-Advertise-Interval 13 integer
+ATTRIBUTE Mikrotik-Recv-Limit-Gigawords 14 integer
+ATTRIBUTE Mikrotik-Xmit-Limit-Gigawords 15 integer
+ATTRIBUTE Mikrotik-Wireless-PSK 16 string
+ATTRIBUTE Mikrotik-Total-Limit 17 integer
+ATTRIBUTE Mikrotik-Total-Limit-Gigawords 18 integer
+ATTRIBUTE Mikrotik-Address-List 19 string
+ATTRIBUTE Mikrotik-Wireless-MPKey 20 string
+ATTRIBUTE Mikrotik-Wireless-Comment 21 string
+ATTRIBUTE Mikrotik-Delegated-IPv6-Pool 22 string
+ATTRIBUTE Mikrotik-DHCP-Option-Set 23 string
+ATTRIBUTE Mikrotik-DHCP-Option-Param-STR1 24 string
+ATTRIBUTE Mikrotik-DHCP-Option-Param-STR2 25 string
+ATTRIBUTE Mikrotik-DHCP-Option-ParamSTR2 25 string
+ATTRIBUTE Mikrotik-Wireless-VLANID 26 integer
+ATTRIBUTE Mikrotik-Wireless-VLANIDtype 27 integer
+ATTRIBUTE Mikrotik-Wireless-VLANID-Type 27 integer
+ATTRIBUTE Mikrotik-Wireless-Minsignal 28 string
+ATTRIBUTE Mikrotik-Wireless-Maxsignal 29 string
+ATTRIBUTE Mikrotik-Switching-Filter 30 string
+
+# MikroTik Values
+
+VALUE Mikrotik-Wireless-Enc-Algo No-encryption 0
+VALUE Mikrotik-Wireless-Enc-Algo 40-bit-WEP 1
+VALUE Mikrotik-Wireless-Enc-Algo 104-bit-WEP 2
+VALUE Mikrotik-Wireless-Enc-Algo AES-CCM 3
+VALUE Mikrotik-Wireless-Enc-Algo TKIP 4
+
+VALUE Mikrotik-Wireless-VLANIDtype 802.1q 0
+VALUE Mikrotik-Wireless-VLANIDtype 802.1ad 1
+
+END-VENDOR Mikrotik
diff --git a/share/dictionary.mimosa b/share/dictionary.mimosa
new file mode 100644
index 0000000..f2138d8
--- /dev/null
+++ b/share/dictionary.mimosa
@@ -0,0 +1,39 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+
+VENDOR Mimosa 43356
+
+BEGIN-VENDOR Mimosa
+
+ATTRIBUTE Mimosa-Device-Configuration-Parameter 1 string
+ATTRIBUTE Mimosa-FirmwareVersion-Parameter 2 string
+ATTRIBUTE Mimosa-FirmwareLocation-Parameter 3 string
+ATTRIBUTE Mimosa-WirelessProtocol-Parameter 4 string
+ATTRIBUTE Mimosa-ManagementIPAddressMode-Parameter 5 string
+ATTRIBUTE Mimosa-ManagementIPAddress-Parameter 6 ipaddr
+ATTRIBUTE Mimosa-ManagementIPNetmask-Parameter 7 ipaddr
+ATTRIBUTE Mimosa-ManagementIPGateway-Parameter 8 ipaddr
+ATTRIBUTE Mimosa-ManagementVlanStatus-Parameter 9 byte
+ATTRIBUTE Mimosa-ManagementVlan-Parameter 10 string
+ATTRIBUTE Mimosa-ManagementPassword-Parameter 11 string
+ATTRIBUTE Mimosa-DeviceName-Parameter 12 string
+ATTRIBUTE Mimosa-TrafficShapingPeak-Parameter 13 string
+ATTRIBUTE Mimosa-TrafficShapingCommitted-Parameter 14 string
+ATTRIBUTE Mimosa-EthernetPortSpeed-Parameter 15 string
+ATTRIBUTE Mimosa-DNS1-Parameter 16 ipaddr
+ATTRIBUTE Mimosa-DNS2-Parameter 17 ipaddr
+ATTRIBUTE Mimosa-HTTPPort-Parameter 18 integer
+ATTRIBUTE Mimosa-EnableHTTPS-Parameter 19 byte
+ATTRIBUTE Mimosa-HTTPSPort-Parameter 20 integer
+ATTRIBUTE Mimosa-CloudManagement-Parameter 21 byte
+ATTRIBUTE Mimosa-EnableSNMP-Parameter 22 byte
+ATTRIBUTE Mimosa-SNMPCommunityString-Parameter 23 string
+ATTRIBUTE Mimosa-SNMPTrapServer-Parameter 24 ipaddr
+ATTRIBUTE Mimosa-NTPServerAddress-Parameter 25 string
+ATTRIBUTE Mimosa-EnableSyslog-Parameter 26 byte
+ATTRIBUTE Mimosa-SyslogServerAddress-Parameter 27 ipaddr
+ATTRIBUTE Mimosa-SyslogPort-Parameter 28 integer
+ATTRIBUTE Mimosa-SyslogProtocol-Parameter 29 string
+
+END-VENDOR Mimosa
diff --git a/share/dictionary.motorola b/share/dictionary.motorola
new file mode 100644
index 0000000..8513489
--- /dev/null
+++ b/share/dictionary.motorola
@@ -0,0 +1,74 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Motorola Canopy attributes.
+#
+# NOT included in the main dictionaries because of conflicts
+# with Ascend attributes.
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR Motorola 161
+
+BEGIN-VENDOR Motorola
+
+# Low Priority uplink CIR
+ATTRIBUTE Motorola-Canopy-LPULCIR 1 integer
+# Low Priority downlink CIR
+ATTRIBUTE Motorola-Canopy-LPDLCIR 2 integer
+# High Priority uplink CIR
+ATTRIBUTE Motorola-Canopy-HPULCIR 3 integer
+# High Priority downlink CIR
+ATTRIBUTE Motorola-Canopy-HPDLCIR 4 integer
+# High Priority Enable
+ATTRIBUTE Motorola-Canopy-HPENABLE 5 integer
+# Uplink Bit Rate/Sustained Uplink Rate
+ATTRIBUTE Motorola-Canopy-ULBR 6 integer
+# Uplink Bit Limit/Uplink Burst Allocation
+ATTRIBUTE Motorola-Canopy-ULBL 7 integer
+# Downlink Bit Rate/Sustained Downlink Rate
+ATTRIBUTE Motorola-Canopy-DLBR 8 integer
+# Downlink Bit Limit/Downlink Burst Allocation
+ATTRIBUTE Motorola-Canopy-DLBL 9 integer
+# VLAN Learning Enable
+ATTRIBUTE Motorola-Canopy-VLLEARNEN 14 integer
+# VLAN Frames Types allowed - all/Tag/Untagged
+ATTRIBUTE Motorola-Canopy-VLFRAMES 15 integer
+# VLAN Membership (1-4094)
+ATTRIBUTE Motorola-Canopy-VLIDSET 16 integer
+# VLAN Age Timeout
+ATTRIBUTE Motorola-Canopy-VLAGETO 20 integer
+# VLAN Ingress VLAN ID
+ATTRIBUTE Motorola-Canopy-VLIGVID 21 integer
+# VLAN Management VLAN ID
+ATTRIBUTE Motorola-Canopy-VLMGVID 22 integer
+# VLAN SM Management Passthrough Enable
+ATTRIBUTE Motorola-Canopy-VLSMMGPASS 23 integer
+# Broadcast Traffic Maximum Information Rate
+ATTRIBUTE Motorola-Canopy-BCASTMIR 24 integer
+# Userlevel permission for the User logging in remotely
+ATTRIBUTE Motorola-Canopy-UserLevel 50 integer
+
+VALUE Motorola-Canopy-HPENABLE Disable 0
+VALUE Motorola-Canopy-HPENABLE Enable 1
+
+VALUE Motorola-Canopy-VLLEARNEN Disable 0
+VALUE Motorola-Canopy-VLLEARNEN Enable 1
+
+VALUE Motorola-Canopy-VLFRAMES All 0
+VALUE Motorola-Canopy-VLFRAMES Tagged 1
+VALUE Motorola-Canopy-VLFRAMES Untagged 2
+
+VALUE Motorola-Canopy-VLSMMGPASS Enable 1
+VALUE Motorola-Canopy-VLSMMGPASS Disable 0
+
+VALUE Motorola-Canopy-UserLevel TECH 1
+VALUE Motorola-Canopy-UserLevel INSTALL 2
+VALUE Motorola-Canopy-UserLevel ADMIN 3
+
+END-VENDOR Motorola
diff --git a/share/dictionary.motorola.illegal b/share/dictionary.motorola.illegal
new file mode 100644
index 0000000..bbddb37
--- /dev/null
+++ b/share/dictionary.motorola.illegal
@@ -0,0 +1,29 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Motorola Canopy attributes.
+#
+# See also dictionary.motorola.illegal. You can use that one
+# by listing it in raddb/dictionary.
+#
+# $Id$
+#
+##############################################################################
+
+ATTRIBUTE Motorola-Canopy-Shared-Secret 224 string
+ATTRIBUTE Motorola-Canopy-SULDR 225 string
+ATTRIBUTE Motorola-Canopy-SDLDR 226 string
+ATTRIBUTE Motorola-Canopy-ULBA 227 string
+ATTRIBUTE Motorola-Canopy-DLBA 228 string
+ATTRIBUTE Motorola-Canopy-Enable 229 string
+ATTRIBUTE Motorola-Canopy-LPSULDR 230 string
+ATTRIBUTE Motorola-Canopy-LPSDLDR 231 string
+ATTRIBUTE Motorola-Canopy-HPCENABLE 232 string
+ATTRIBUTE Motorola-Canopy-HPSULDR 233 string
+ATTRIBUTE Motorola-Canopy-HPSDLDR 234 string
+ATTRIBUTE Motorola-Canopy-HIGHERBW 235 string
+ATTRIBUTE Motorola-Canopy-CIRENABLE 236 string
+
diff --git a/share/dictionary.motorola.wimax b/share/dictionary.motorola.wimax
new file mode 100644
index 0000000..5920af1
--- /dev/null
+++ b/share/dictionary.motorola.wimax
@@ -0,0 +1,37 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Motorola WiMAX attributes.
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR Motorola 161
+
+BEGIN-VENDOR Motorola
+
+ATTRIBUTE Motorola-WiMAX-MIP-MN-HOME-ADDRESS 10 ipaddr
+ATTRIBUTE Motorola-WiMAX-MIP-KEY 11 string encrypt=2
+ATTRIBUTE Motorola-WiMAX-MIP-SPI 12 integer
+ATTRIBUTE Motorola-WiMAX-MN-HA 13 ipaddr
+ATTRIBUTE Motorola-WiMAX-DNS-Server-IP-Address 20 octets
+ATTRIBUTE Motorola-WiMAX-User-NAI 22 string
+ATTRIBUTE Motorola-WiMAX-Network-Domain-Name 30 string
+ATTRIBUTE Motorola-WiMAX-EMS-Address 31 ipaddr
+ATTRIBUTE Motorola-WiMAX-Provisioning-Server 32 string
+ATTRIBUTE Motorola-WiMAX-NTP-Server 34 octets
+ATTRIBUTE Motorola-WiMAX-HO-SVC-CLASS 35 octets
+ATTRIBUTE Motorola-WiMAX-Home-BTS 50 octets
+ATTRIBUTE Motorola-WiMAX-Maximum-Total-Bandwidth 60 octets
+ATTRIBUTE Motorola-WiMAX-Maximum-Commit-Bandwidth 61 octets
+ATTRIBUTE Motorola-WiMAX-Convergence-Sublayer 63 octets
+ATTRIBUTE Motorola-WiMAX-Service-Flows 64 string
+ATTRIBUTE Motorola-WiMAX-VLAN-ID 65 octets
+
+ATTRIBUTE Motorola-Accounting-Message 80 string
+
+END-VENDOR Motorola
diff --git a/share/dictionary.navini b/share/dictionary.navini
new file mode 100644
index 0000000..24e644e
--- /dev/null
+++ b/share/dictionary.navini
@@ -0,0 +1,22 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# dictionary.navini
+#
+# By
+# "Paul Shields" <pshields@navini.com>
+#
+# Version: $Id$
+#
+
+VENDOR Navini 6504
+
+#
+# Standard attribute
+#
+BEGIN-VENDOR Navini
+
+ATTRIBUTE Navini-AVPair 1 string
+
+END-VENDOR Navini
diff --git a/share/dictionary.net b/share/dictionary.net
new file mode 100644
index 0000000..e14192a
--- /dev/null
+++ b/share/dictionary.net
@@ -0,0 +1,132 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# From https://support.sonus.net/display/UXDOC50/Vendor+Specific+Attributes+Reference
+
+VENDOR NET 177
+
+BEGIN-VENDOR NET
+
+# MSC/Media related attributes
+ATTRIBUTE NET-Fwd-Flow-In-Realm 11 string # unsupported
+ATTRIBUTE NET-Fwd-Flow-In-Src-Addr 12 string
+ATTRIBUTE NET-Fwd-Flow-In-Src-Port 13 integer
+ATTRIBUTE NET-Fwd-Flow-In-Dst-Addr 14 string
+ATTRIBUTE NET-Fwd-Flow-In-Dst-Port 15 integer
+ATTRIBUTE NET-Fwd-Flow-Out-Realm 16 string # unsupported
+ATTRIBUTE NET-Fwd-Flow-Out-Src-Addr 17 string
+ATTRIBUTE NET-Fwd-Flow-Out-Src-Port 18 integer
+ATTRIBUTE NET-Fwd-Flow-Out-Dst-Addr 19 string
+ATTRIBUTE NET-Fwd-Flow-Out-Dst-Port 20 integer
+ATTRIBUTE NET-Bwd-Flow-In-Realm 21 string # unsupported
+ATTRIBUTE NET-Bwd-Flow-In-Src-Addr 22 string
+ATTRIBUTE NET-Bwd-Flow-In-Src-Port 23 integer
+ATTRIBUTE NET-Bwd-Flow-In-Dst-Addr 24 string
+ATTRIBUTE NET-Bwd-Flow-In-Dst-Port 25 integer
+ATTRIBUTE NET-Bwd-Flow-Out-Realm 26 string # unsupported
+ATTRIBUTE NET-Bwd-Flow-Out-Src-Addr 27 string
+ATTRIBUTE NET-Bwd-Flow-Out-Src-Port 28 integer
+ATTRIBUTE NET-Bwd-Flow-Out-Dst-Addr 29 string
+ATTRIBUTE NET-Bwd-Flow-Out-Dst-Port 30 integer
+ATTRIBUTE NET-Fwd-Flow-Media-Type 31 string
+ATTRIBUTE NET-Fwd-Flow-PTime 32 integer
+ATTRIBUTE NET-Fwd-Octets 33 integer
+ATTRIBUTE NET-Fwd-Packets 34 integer
+ATTRIBUTE NET-Fwd-RTCP-Packets-Lost 35 integer # future
+ATTRIBUTE NET-Fwd-RTCP-Avg-Jitter 36 integer # future
+ATTRIBUTE NET-Fwd-RTP-Avg-Latency 37 integer
+ATTRIBUTE NET-Fwd-RTCP-MaxJitter 38 integer # future
+ATTRIBUTE NET-Fwd-RTP-MaxLatency 39 integer
+ATTRIBUTE NET-Fwd-RTP-Packets-Lost 40 integer
+ATTRIBUTE NET-Fwd-RTP-Avg-Jitter 41 integer
+ATTRIBUTE NET-Fwd-RTP-MaxJitter 42 integer
+ATTRIBUTE NET-Bwd-Octets 43 integer
+ATTRIBUTE NET-Bwd-Packets 44 integer
+ATTRIBUTE NET-Bwd-RTCP-Packets-Lost 45 integer # future
+ATTRIBUTE NET-Bwd-RTCP-Avg-Jitter 46 integer # future
+ATTRIBUTE NET-Bwd-RTP-Avg-Latency 47 integer
+ATTRIBUTE NET-Bwd-RTCP-MaxJitter 48 integer # future
+ATTRIBUTE NET-Bwd-RTP-MaxLatency 49 integer
+ATTRIBUTE NET-Bwd-RTP-Packets-Lost 50 integer
+ATTRIBUTE NET-Bwd-RTP-Avg-Jitter 51 integer
+ATTRIBUTE NET-Bwd-RTP-MaxJitter 52 integer
+
+# Generic Session and Signaling Group related metrics
+ATTRIBUTE NET-Session-Ingress-CallId 60 integer
+ATTRIBUTE NET-Session-Egress-CallId 61 integer
+ATTRIBUTE NET-Session-Generic-Id 62 integer
+ATTRIBUTE NET-Routing-Table-Number 63 integer
+ATTRIBUTE NET-Ingress-Signaling-Group 64 integer
+ATTRIBUTE NET-Egress-Signaling-Group 65 integer
+ATTRIBUTE NET-Primary-Routing-Number 66 string
+ATTRIBUTE NET-Egress-Final-Routing-Num 67 string
+ATTRIBUTE NET-Ingress-Channel-Number 68 integer
+ATTRIBUTE NET-Egress-Channel-Number 69 integer
+ATTRIBUTE NET-Call-Type 70 integer
+ATTRIBUTE NET-Call-Origin 71 integer
+ATTRIBUTE NET-Calling-Number 72 string
+ATTRIBUTE NET-Called-Number 73 string
+ATTRIBUTE NET-Calling-Name 74 string
+ATTRIBUTE NET-Disconnect-Cause 75 integer
+ATTRIBUTE NET-Abort-Cause 76 integer
+ATTRIBUTE NET-Ingress-Channel-Id 77 string
+ATTRIBUTE NET-Egress-Channel-Id 78 string
+ATTRIBUTE NET-Call-Priority 79 string
+
+# Generic Call related attributes
+ATTRIBUTE NET-Call-Number-Type 90 string
+ATTRIBUTE NET-Call-Plan 91 string
+ATTRIBUTE NET-Original-Called-Number 92 string
+ATTRIBUTE NET-Original-Called-Type 93 string
+ATTRIBUTE NET-Original-Called-Plan 94 string
+ATTRIBUTE NET-Called-Name 95 string
+ATTRIBUTE NET-Namespace 96 string
+ATTRIBUTE NET-Precedence 97 string
+ATTRIBUTE NET-Presentation 98 string
+ATTRIBUTE NET-Screening 99 string
+ATTRIBUTE NET-Transfer-Capability 100 string
+ATTRIBUTE NET-Transfer-Mode 101 string
+ATTRIBUTE NET-Transfer-Rate 102 string
+ATTRIBUTE NET-User-Rate 103 string
+
+# Generic time related attributes
+ATTRIBUTE NET-Setup-Time 110 string
+ATTRIBUTE NET-Alert-Time 111 string
+ATTRIBUTE NET-Connect-Time 112 string
+ATTRIBUTE NET-Disconnect-Time 113 string
+ATTRIBUTE NET-Inbound-Seize-Time 114 string
+ATTRIBUTE NET-Outbound-Seize-Time 115 string
+ATTRIBUTE NET-Call-Duration 116 integer
+ATTRIBUTE NET-Post-Dial-Delay 117 integer
+ATTRIBUTE NET-Disconnect-Initiator 118 integer
+
+# SIP related
+ATTRIBUTE NET-P-Asserted-ID 130 string
+ATTRIBUTE NET-SIP-Diversion 131 string
+ATTRIBUTE NET-Ingress-Local-Addr 132 string
+ATTRIBUTE NET-Ingress-Remote-Addr 133 string
+ATTRIBUTE NET-Egress-Local-Addr 134 string
+ATTRIBUTE NET-Egress-Remote-Addr 135 string
+ATTRIBUTE NET-Ingress-Net-Interface-Id 136 integer
+ATTRIBUTE NET-Egress-Net-Interface-Id 137 integer
+ATTRIBUTE NET-Refer-Call-Transfer-Id 138 string
+ATTRIBUTE NET-Session-Forked-Call-Id 139 string
+ATTRIBUTE NET-Redirect-Number 140 string
+ATTRIBUTE NET-Redirect-Ip-Address 141 string
+ATTRIBUTE NET-Session-Ingress-Realm 142 string
+ATTRIBUTE NET-Session-Egress-Realm 143 string
+ATTRIBUTE NET-Ingress-Signaling-Port-Num 144 integer
+ATTRIBUTE NET-Egress-Signaling-Port-Num 145 integer
+ATTRIBUTE NET-Transport-Type 146 integer
+ATTRIBUTE NET-P-Preferred-ID 147 string
+ATTRIBUTE NET-Replaced-Header 148 string
+
+# Generic parameters
+ATTRIBUTE NET-Firmware-Version 160 string
+ATTRIBUTE NET-Local-Time-Zone 161 string
+ATTRIBUTE NET-Gw-Id 162 string
+ATTRIBUTE NET-Time-And-Day 163 string
+ATTRIBUTE NET-Log-Time 164 string
+
+END-VENDOR NET
diff --git a/share/dictionary.netelastic b/share/dictionary.netelastic
new file mode 100644
index 0000000..96cdef0
--- /dev/null
+++ b/share/dictionary.netelastic
@@ -0,0 +1,55 @@
+# -*- text -*-
+# Copyright (C) 2022 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Dictionary for NetElastic.
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR NetElastic 54268
+
+BEGIN-VENDOR NetElastic
+
+ATTRIBUTE NetElastic-Input-Burst-Size 1 integer
+ATTRIBUTE NetElastic-Input-Average-Rate 2 integer
+ATTRIBUTE NetElastic-Input-Peak-Rate 3 integer
+ATTRIBUTE NetElastic-Output-Burst-Size 4 integer
+ATTRIBUTE NetElastic-Output-Average-Rate 5 integer
+ATTRIBUTE NetElastic-Output-Peak-Rate 6 integer
+ATTRIBUTE NetElastic-Remanent-Volume 15 integer
+ATTRIBUTE NetElastic-ISP-ID 17 string
+ATTRIBUTE NetElastic-PortalURL 27 string
+ATTRIBUTE NetElastic-Qos-Profile-Name 31 string
+ATTRIBUTE NetElastic-Lease-Time 74 integer
+ATTRIBUTE NetElastic-Input-Peak-Burst-Size 77 integer
+ATTRIBUTE NetElastic-Output-Peak-Burst-Size 78 integer
+ATTRIBUTE NetElastic-Data-Filter 82 string
+ATTRIBUTE NetElastic-Portal-Mode 85 integer
+ATTRIBUTE NetElastic-Policy-Name 95 string
+ATTRIBUTE NetElastic-Primary-DNS 135 ipaddr
+ATTRIBUTE NetElastic-Secondary-DNS 136 ipaddr
+ATTRIBUTE NetElastic-Domain-Name 138 string
+ATTRIBUTE NetElastic-HTTP-Redirect-URL 140 string
+ATTRIBUTE NetElastic-Acct-IPv6-Input-Octets 144 integer
+ATTRIBUTE NetElastic-Acct-IPv6-Output-Octets 145 integer
+ATTRIBUTE NetElastic-Acct-IPv6-Input-Packets 146 integer
+ATTRIBUTE NetElastic-Acct-IPv6-Output-Packets 147 integer
+ATTRIBUTE NetElastic-Acct-IPv6-Input-Gigawords 148 integer
+ATTRIBUTE NetElastic-Acct-IPv6-Output-Gigawords 149 integer
+ATTRIBUTE NetElastic-User-Mac 153 string
+ATTRIBUTE NetElastic-Framed-IPv6-Address 158 ipv6addr
+ATTRIBUTE NetElastic-NAT-Public-Address 161 ipaddr
+ATTRIBUTE NetElastic-NAT-Start-Port 162 integer
+ATTRIBUTE NetElastic-NAT-End-Port 163 integer
+ATTRIBUTE NetElastic-Tariff-Input-Octets 247 string
+ATTRIBUTE NetElastic-Tariff-Output-Octets 248 string
+ATTRIBUTE NetElastic-Tariff-Input-Gigawords 249 string
+ATTRIBUTE NetElastic-Tariff-Output-Gigawords 250 string
+ATTRIBUTE NetElastic-Remanent-Volume-Type 251 integer
+ATTRIBUTE NetElastic-Web-COA 252 integer
+
+END-VENDOR NetElastic
diff --git a/share/dictionary.netscreen b/share/dictionary.netscreen
new file mode 100644
index 0000000..3419b5e
--- /dev/null
+++ b/share/dictionary.netscreen
@@ -0,0 +1,34 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# From:
+# http://www.netscreen.com/support/downloads/4.0_configuring_screenOS_for_NTdomain_v11.pdf
+#
+
+VENDOR Netscreen 3224
+
+BEGIN-VENDOR Netscreen
+
+ATTRIBUTE NS-Admin-Privilege 1 integer
+ATTRIBUTE NS-VSYS-Name 2 string
+ATTRIBUTE NS-User-Group 3 string
+ATTRIBUTE NS-Primary-DNS 4 ipaddr
+ATTRIBUTE NS-Secondary-DNS 5 ipaddr
+ATTRIBUTE NS-Primary-WINS 6 ipaddr
+ATTRIBUTE NS-Secondary-WINS 7 ipaddr
+
+ATTRIBUTE NS-NSM-User-Domain-Name 220 string
+ATTRIBUTE NS-NSM-User-Role-Mapping 221 string
+
+#
+# Values VSYS-Admin and Read-Only-VSYS-Admin require a NS-VSYS-Name
+# attribute in the response packet.
+#
+VALUE NS-Admin-Privilege Root-Admin 1
+VALUE NS-Admin-Privilege All-VSYS-Root-Admin 2
+VALUE NS-Admin-Privilege VSYS-Admin 3
+VALUE NS-Admin-Privilege Read-Only-Admin 4
+VALUE NS-Admin-Privilege Read-Only-VSYS-Admin 5
+
+END-VENDOR Netscreen
diff --git a/share/dictionary.networkphysics b/share/dictionary.networkphysics
new file mode 100644
index 0000000..7e09519
--- /dev/null
+++ b/share/dictionary.networkphysics
@@ -0,0 +1,19 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# NetworkPhysics dictionary
+# $Id$
+#
+VENDOR NetworkPhysics 7119
+
+BEGIN-VENDOR NetworkPhysics
+
+ATTRIBUTE NetSensory-Privilege 33 string
+
+#VALUE NetSensory-Privilege InsightsOnly 'insight'
+#VALUE NetSensory-Privilege Restricted 'npread'
+#VALUE NetSensory-Privilege Standard 'npuser'
+#VALUE NetSensory-Privilege Administrative 'npadmin'
+
+END-VENDOR NetworkPhysics
diff --git a/share/dictionary.nexans b/share/dictionary.nexans
new file mode 100644
index 0000000..a4f6210
--- /dev/null
+++ b/share/dictionary.nexans
@@ -0,0 +1,21 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+# Nexans Active Networking Systems dictionary http://www.nexans.de/ans
+#
+# Version: $Id$
+#
+# Hubert Theissen <h.theissen@nexans.com>
+#
+##############################################################################
+
+VENDOR Nexans 266
+
+BEGIN-VENDOR Nexans
+
+ATTRIBUTE Nexans-Port-Default-VLAN-ID 1 integer
+ATTRIBUTE Nexans-Port-Voice-VLAN-ID 2 integer
+
+END-VENDOR Nexans
diff --git a/share/dictionary.nile b/share/dictionary.nile
new file mode 100644
index 0000000..95f9545
--- /dev/null
+++ b/share/dictionary.nile
@@ -0,0 +1,20 @@
+# -*- text -*-
+# Copyright (C) 2022 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# https://nilesecure.co/
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR Nile 58313
+BEGIN-VENDOR Nile
+
+ATTRIBUTE Nile-Redirect-URL 1 string
+ATTRIBUTE Nile-Netseg 2 string
+ATTRIBUTE Nile-AVPair 3 string
+
+END-VENDOR Nile
diff --git a/share/dictionary.nokia b/share/dictionary.nokia
new file mode 100644
index 0000000..d522ff7
--- /dev/null
+++ b/share/dictionary.nokia
@@ -0,0 +1,41 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+######################################################################
+#
+# Nokia dictionary
+# $Id$
+#
+######################################################################
+
+VENDOR Nokia 94
+
+BEGIN-VENDOR Nokia
+
+ATTRIBUTE Nokia-AVPair 1 string
+ATTRIBUTE Nokia-User-Profile 2 string
+ATTRIBUTE Nokia-Service-Name 3 octets # magic format
+ATTRIBUTE Nokia-Service-Id 4 octets # magic format
+ATTRIBUTE Nokia-Service-Username 5 octets # magic format
+ATTRIBUTE Nokia-Service-Password 6 octets # magic format
+ATTRIBUTE Nokia-Service-Primary-Indicator 7 octets
+ATTRIBUTE Nokia-Service-Charging-Type 8 octets # magic format
+ATTRIBUTE Nokia-Service-Encrypted-Password 9 octets # magic format
+ATTRIBUTE Nokia-Session-Access-Method 10 octets
+ATTRIBUTE Nokia-Session-Charging-Type 11 octets
+ATTRIBUTE Nokia-OCS-ID1 12 integer
+ATTRIBUTE Nokia-OCS-ID2 13 integer
+ATTRIBUTE Nokia-TREC-Index 14 integer
+ATTRIBUTE Nokia-Requested-APN 15 string
+END-VENDOR Nokia
+
+#
+# The format of some Nokia attributes is binary coded decimal
+# (BCD) with the last four bits all set to 1 if there are an odd
+# number of digits,
+#
+# e.g 123 is encoded as hexadecimal bytes 21 F3
+#
+# This is an incredibly stupid way of encoding the data.
+#
diff --git a/share/dictionary.nokia.conflict b/share/dictionary.nokia.conflict
new file mode 100644
index 0000000..5ff9fda
--- /dev/null
+++ b/share/dictionary.nokia.conflict
@@ -0,0 +1,32 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Nokia dictionary for attributes that conflict with other dictionaries.
+#
+# $Id$
+#
+##############################################################################
+
+#
+# Enable by putting the line "$INCLUDE dictionary.nokia.conflict" into
+# the main dictionary file. Don't forget to comment out the
+# $INCLUDE dictionary.ascend, because these over-lap with the
+# standard RADIUS attributes, which are also illegitimately used
+# by Ascend.
+#
+# It's apparently rocket science for people to define their own
+# VSA's.
+#
+
+ATTRIBUTE Nokia-Primary-DNS-Server 135 ipaddr
+ATTRIBUTE Nokia-Secondary-DNS-Server 136 ipaddr
+
+ATTRIBUTE Nokia-IMSI 224 octets
+ATTRIBUTE Nokia-Charging-Id 225 integer
+ATTRIBUTE Nokia-Prepaid-Ind 226 integer
+ATTRIBUTE Nokia-GGSN-IP-Address 227 ipaddr
+ATTRIBUTE Nokia-SGSN-IP-Address 228 ipaddr
+
diff --git a/share/dictionary.nomadix b/share/dictionary.nomadix
new file mode 100644
index 0000000..31938ba
--- /dev/null
+++ b/share/dictionary.nomadix
@@ -0,0 +1,34 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Version: $Id$
+#
+VENDOR Nomadix 3309
+#
+BEGIN-VENDOR Nomadix
+
+ATTRIBUTE Nomadix-Bw-Up 1 integer
+ATTRIBUTE Nomadix-Bw-Down 2 integer
+ATTRIBUTE Nomadix-URL-Redirection 3 string
+ATTRIBUTE Nomadix-IP-Upsell 4 integer
+ATTRIBUTE Nomadix-Expiration 5 string
+ATTRIBUTE Nomadix-Subnet 6 string
+ATTRIBUTE Nomadix-MaxBytesUp 7 integer
+ATTRIBUTE Nomadix-MaxBytesDown 8 integer
+ATTRIBUTE Nomadix-EndofSession 9 integer
+ATTRIBUTE Nomadix-Logoff-URL 10 string
+ATTRIBUTE Nomadix-Net-VLAN 11 integer
+ATTRIBUTE Nomadix-Config-URL 12 string
+ATTRIBUTE Nomadix-Goodbye-URL 13 string
+ATTRIBUTE Nomadix-Qos-Policy 14 string
+ATTRIBUTE Nomadix-SMTP-Redirect 17 integer
+ATTRIBUTE Nomadix-Centralized-Mgmt 18 string
+ATTRIBUTE Nomadix-Group-Policy-Id 19 integer
+ATTRIBUTE Nomadix-Group-Bw-Max-Up 20 integer
+ATTRIBUTE Nomadix-Group-Bw-Max-Down 21 integer
+
+VALUE Nomadix-IP-Upsell PrivatePool 0
+VALUE Nomadix-IP-Upsell PublicPool 1
+
+END-VENDOR Nomadix
diff --git a/share/dictionary.nortel b/share/dictionary.nortel
new file mode 100644
index 0000000..9f6ac83
--- /dev/null
+++ b/share/dictionary.nortel
@@ -0,0 +1,77 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+# Version $Id$
+##############################################################################
+#
+# Nortel Passport 8600 VSA's.
+#
+# http://www142.nortelnetworks.com/bvdoc/setips/july04/engineeringtipstricksv12.pdf
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR Nortel 562
+BEGIN-VENDOR Nortel
+
+ATTRIBUTE Nortel-User-Role 110 string
+
+ATTRIBUTE Nortel-Privilege-Level 166 integer
+
+ATTRIBUTE Fabric-Attach-VLAN-Create 170 integer
+ATTRIBUTE Fabric-Attach-VLAN-ISID 171 string
+ATTRIBUTE Fabric-Attach-VLAN-PVID 172 integer
+
+ATTRIBUTE Fabric-Attach-Switch-Mode 180 integer
+ATTRIBUTE Fabric-Attach-Client-Id 181 string
+ATTRIBUTE Fabric-Attach-Client-Type 182 string
+ATTRIBUTE Fabric-Attach-Client-PSK 183 integer
+ATTRIBUTE Fabric-Attach-Client-Trust 184 integer
+ATTRIBUTE Fabric-Attach-Client-Trusted-Binding 185 string
+ATTRIBUTE Fabric-Attach-Service-Request 186 string
+
+ATTRIBUTE Passport-Command-Scope 200 integer
+ATTRIBUTE Passport-Command-Impact 201 integer
+ATTRIBUTE Passport-Customer-Identifier 202 integer
+ATTRIBUTE Passport-Allowed-Access 203 integer
+ATTRIBUTE Passport-AllowedOut-Access 204 integer
+ATTRIBUTE Passport-Login-Directory 205 string
+ATTRIBUTE Passport-Timeout-Protocol 206 integer
+ATTRIBUTE Passport-Role 207 string
+
+VALUE Fabric-Attach-VLAN-Create No 0
+VALUE Fabric-Attach-VLAN-Create Yes 1
+
+VALUE Nortel-Privilege-Level VoiceMailAdmin 0
+VALUE Nortel-Privilege-Level ContactCenter 1
+VALUE Nortel-Privilege-Level SBAInstaller 2
+VALUE Nortel-Privilege-Level SBASystemCoord 3
+VALUE Nortel-Privilege-Level SBASystemCoordBasic 4
+VALUE Nortel-Privilege-Level SBABasic 5
+VALUE Nortel-Privilege-Level Security 6
+VALUE Nortel-Privilege-Level CTEApp 7
+VALUE Nortel-Privilege-Level SBA-IPSetRegistration 8
+VALUE Nortel-Privilege-Level Application-BCMMonitor 9
+VALUE Nortel-Privilege-Level CDRApp 10
+VALUE Nortel-Privilege-Level ModemLogin 11
+VALUE Nortel-Privilege-Level GuestLogin 12
+VALUE Nortel-Privilege-Level AdminDownload 13
+VALUE Nortel-Privilege-Level ExclusiveAccess 14
+VALUE Nortel-Privilege-Level Admin 15
+VALUE Nortel-Privilege-Level DataAdmin 16
+VALUE Nortel-Privilege-Level RemoteAccess 17
+VALUE Nortel-Privilege-Level Guest 18
+VALUE Nortel-Privilege-Level VoiceAdmin 19
+VALUE Nortel-Privilege-Level BackupOperator 20
+VALUE Nortel-Privilege-Level RemoteMonitoring 21
+VALUE Nortel-Privilege-Level SoftwareUpgrade 22
+VALUE Nortel-Privilege-Level AlarmViewer 24
+VALUE Nortel-Privilege-Level OperationalLogs 26
+VALUE Nortel-Privilege-Level DiagnosticLogs 27
+VALUE Nortel-Privilege-Level ApplicationIVR 28
+VALUE Nortel-Privilege-Level ISDN-Dial-in 30
+VALUE Nortel-Privilege-Level WAN-Dial-in 32
+VALUE Nortel-Privilege-Level System-SerialPort 36
+
+END-VENDOR Nortel
diff --git a/share/dictionary.ntua b/share/dictionary.ntua
new file mode 100644
index 0000000..7b35423
--- /dev/null
+++ b/share/dictionary.ntua
@@ -0,0 +1,46 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+VENDOR NTUA 969
+
+BEGIN-VENDOR NTUA
+
+#
+# Authentication Attributes
+#
+ATTRIBUTE UserLogon-Uid 10 integer
+ATTRIBUTE UserLogon-Gid 11 integer
+ATTRIBUTE UserLogon-HomeDir 12 string
+ATTRIBUTE UserLogon-Type 13 integer
+ATTRIBUTE UserLogon-QuotaBytes 14 integer
+ATTRIBUTE UserLogon-QuotaFiles 15 integer
+ATTRIBUTE UserLogon-Shell 16 string
+ATTRIBUTE UserLogon-Restriction 17 integer
+ATTRIBUTE UserLogon-GroupNames 18 string
+ATTRIBUTE UserLogon-DriveNames 19 string
+ATTRIBUTE UserLogon-UserDescription 20 string
+ATTRIBUTE UserLogon-UserFullName 21 string
+ATTRIBUTE UserLogon-UserDomain 22 string
+ATTRIBUTE UserLogon-LogonTask 23 string
+ATTRIBUTE UserLogon-LogoffTask 24 string
+ATTRIBUTE UserLogon-Expiration 25 string
+ATTRIBUTE UserLogon-UserProfile 26 string
+#
+# Accounting Attributes
+#
+ATTRIBUTE UserLogon-Acct-TerminateCause 50 string
+
+VALUE UserLogon-Type FTP 1
+VALUE UserLogon-Type WEB 2
+VALUE UserLogon-Type POP 3
+VALUE UserLogon-Type IMAP 4
+VALUE UserLogon-Type Windows-Logon 5
+VALUE UserLogon-Type Unix-Logon 6
+VALUE UserLogon-Type SMTP-Auth 7
+VALUE UserLogon-Type Other 200
+
+VALUE UserLogon-Restriction Anonymous-User 1
+VALUE UserLogon-Restriction Admin-User 2
+
+END-VENDOR NTUA
diff --git a/share/dictionary.openser b/share/dictionary.openser
new file mode 100644
index 0000000..86e7a2a
--- /dev/null
+++ b/share/dictionary.openser
@@ -0,0 +1,43 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# OpenSER dictionary.
+#
+# This dictionary is NOT included by default, because it conflicts
+# with attributes defined in the RADIUS standard. Vendors SHOULD
+# be using a VSA space to assign attributes.
+#
+# Be aware that if you DO include this dictionary in the main
+# dictionary file, other parts of your configuration may break!
+#
+# http://www.openser.org/docs/openser-radius-1.0.x.html
+#
+# $Id$
+#
+##############################################################################
+
+ATTRIBUTE Sip-Method 101 integer
+ATTRIBUTE Sip-Response-Code 102 integer
+ATTRIBUTE Sip-Cseq 103 string
+ATTRIBUTE Sip-To-Tag 104 string
+ATTRIBUTE Sip-From-Tag 105 string
+ATTRIBUTE Sip-Translated-Request-URI 107 string
+ATTRIBUTE Sip-Src-IP 108 string
+ATTRIBUTE Sip-Src-Port 109 string
+ATTRIBUTE Sip-Uri-User 208 string
+ATTRIBUTE Sip-Group 211 string
+ATTRIBUTE Sip-Rpid 213 string
+ATTRIBUTE SIP-AVP 225 string
+
+VALUE Service-Type Group-Check 12
+VALUE Service-Type Sip-Session 15
+VALUE Service-Type SIP-Caller-AVPs 30
+VALUE Service-Type SIP-Callee-AVPs 31
+
+VALUE Sip-Method INVITE 1
+VALUE Sip-Method CANCEL 2
+VALUE Sip-Method ACK 4
+VALUE Sip-Method BYE 8
diff --git a/share/dictionary.packeteer b/share/dictionary.packeteer
new file mode 100644
index 0000000..d538ac1
--- /dev/null
+++ b/share/dictionary.packeteer
@@ -0,0 +1,26 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Packeteer VSAs, who followed the Cisco way of putting everything
+# into one text string.
+#
+# Packeteer was acquired by Blue Coat in 2008.
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR Packeteer 2334
+
+#
+# Standard attribute
+#
+BEGIN-VENDOR Packeteer
+
+ATTRIBUTE Packeteer-AVPair 1 string
+ATTRIBUTE Packeteer-PC-AVPair 2 string
+
+END-VENDOR Packeteer
diff --git a/share/dictionary.paloalto b/share/dictionary.paloalto
new file mode 100644
index 0000000..2025932
--- /dev/null
+++ b/share/dictionary.paloalto
@@ -0,0 +1,29 @@
+# -*- text -*-
+# Copyright (C) 2021 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+# Version $Id$
+#
+##############################################################################
+#
+# Palo Alto Networks.
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR PaloAlto 25461
+
+BEGIN-VENDOR PaloAlto
+
+ATTRIBUTE PaloAlto-Admin-Role 1 string
+ATTRIBUTE PaloAlto-Admin-Access-Domain 2 string
+ATTRIBUTE PaloAlto-Panorama-Admin-Role 3 string
+ATTRIBUTE PaloAlto-Panorama-Admin-Access-Domain 4 string
+ATTRIBUTE PaloAlto-User-Group 5 string
+ATTRIBUTE PaloAlto-User-Domain 6 string
+ATTRIBUTE PaloAlto-Client-Source-IP 7 string
+ATTRIBUTE PaloAlto-Client-OS 8 string
+ATTRIBUTE PaloAlto-Client-Hostname 9 string
+ATTRIBUTE PaloAlto-GlobalProtect-Client-Version 10 string
+
+END-VENDOR PaloAlto
diff --git a/share/dictionary.patton b/share/dictionary.patton
new file mode 100644
index 0000000..66b41c7
--- /dev/null
+++ b/share/dictionary.patton
@@ -0,0 +1,156 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# dictionary.patton
+# Dictionary for Patton IADs.
+# Written by Pawel Pierscionek <pawel@voiceworks.pl>
+# based on specifications available from vendor
+#
+# Version: @(#)dictionary.patton 5.00 urtho 20-Jan-2010
+# Version: @(#)dictionary.patton 1.00 urtho 08-Sep-2006
+# $Id$
+
+VENDOR Patton 1768
+
+BEGIN-VENDOR Patton
+
+ATTRIBUTE Patton-Protocol 16 string
+ATTRIBUTE Patton-Group 17 string
+ATTRIBUTE Patton-Web-Privilege-Level 18 string
+ATTRIBUTE Patton-Setup-Time 32 string
+ATTRIBUTE Patton-Connect-Time 33 string
+ATTRIBUTE Patton-Disconnect-Time 34 string
+ATTRIBUTE Patton-Disconnect-Cause 35 integer
+ATTRIBUTE Patton-Disconnect-Source 36 string
+ATTRIBUTE Patton-Disconnect-Reason 37 string
+ATTRIBUTE Patton-Called-Unique-Id 48 string
+ATTRIBUTE Patton-Called-IP-Address 49 ipaddr
+ATTRIBUTE Patton-Called-Numbering-Plan 50 string
+ATTRIBUTE Patton-Called-Type-Of-Number 51 string
+ATTRIBUTE Patton-Called-Name 52 string
+ATTRIBUTE Patton-Called-Station-Id 53 string
+ATTRIBUTE Patton-Called-Rx-Octets 64 integer
+ATTRIBUTE Patton-Called-Tx-Octets 65 integer
+ATTRIBUTE Patton-Called-Rx-Packets 66 integer
+ATTRIBUTE Patton-Called-Tx-Packets 67 integer
+ATTRIBUTE Patton-Called-Rx-Lost-Packets 68 integer
+ATTRIBUTE Patton-Called-Tx-Lost-Packets 69 integer
+ATTRIBUTE Patton-Called-Rx-Jitter 70 integer
+ATTRIBUTE Patton-Called-Tx-Jitter 71 integer
+ATTRIBUTE Patton-Called-Codec 72 string
+ATTRIBUTE Patton-Called-Remote-Ip 73 integer
+ATTRIBUTE Patton-Called-Remote-Udp-Port 74 integer
+ATTRIBUTE Patton-Called-Local-Udp-Port 75 integer
+ATTRIBUTE Patton-Called-Qos 76 integer
+ATTRIBUTE Patton-Called-MOS 77 integer
+ATTRIBUTE Patton-Called-Round-Trip-Time 78 integer
+ATTRIBUTE Patton-Calling-Unique-Id 80 string
+ATTRIBUTE Patton-Calling-IP-Address 81 ipaddr
+ATTRIBUTE Patton-Calling-Numbering-Plan 82 string
+ATTRIBUTE Patton-Calling-Type-Of-Number 83 string
+ATTRIBUTE Patton-Calling-Presentation-Indicator 88 string
+ATTRIBUTE Patton-Calling-Screening-Indicator 89 string
+ATTRIBUTE Patton-Calling-Name 84 string
+ATTRIBUTE Patton-Calling-Station-Id 85 string
+ATTRIBUTE Patton-Calling-Rx-Octets 96 integer
+ATTRIBUTE Patton-Calling-Tx-Octets 97 integer
+ATTRIBUTE Patton-Calling-Rx-Packets 98 integer
+ATTRIBUTE Patton-Calling-Tx-Packets 99 integer
+ATTRIBUTE Patton-Calling-Lost-Tx-Packets 100 integer
+ATTRIBUTE Patton-Calling-Lost-Rx-Packets 101 integer
+ATTRIBUTE Patton-Calling-Rx-Jitter 102 integer
+ATTRIBUTE Patton-Calling-Tx-Jitter 103 integer
+ATTRIBUTE Patton-Calling-Codec 104 string
+ATTRIBUTE Patton-Calling-Remote-Ip 105 integer
+ATTRIBUTE Patton-Calling-Remote-Udp-Port 106 integer
+ATTRIBUTE Patton-Calling-Local-Udp-Port 107 integer
+ATTRIBUTE Patton-Calling-Qos 108 integer
+ATTRIBUTE Patton-Calling-MOS 109 integer
+ATTRIBUTE Patton-Calling-Round-Trip-Time 110 integer
+
+VALUE Patton-Disconnect-Cause Valid-cause-code-not-yet-received 0x00
+VALUE Patton-Disconnect-Cause Unallocated-runassigned-number 0x01
+VALUE Patton-Disconnect-Cause No-route-to-specified-transit-network-WAN 0x02
+VALUE Patton-Disconnect-Cause No-route-to-destination 0x03
+VALUE Patton-Disconnect-Cause send-special-information-tone 0x04
+VALUE Patton-Disconnect-Cause misdialled-trunk-prefix 0x05
+VALUE Patton-Disconnect-Cause Channel-unacceptable 0x06
+VALUE Patton-Disconnect-Cause Call-awarded-and-being-delivered-in-an-established-channel 0x07
+VALUE Patton-Disconnect-Cause Prefix-0-dialed-but-not-allowed 0x08
+VALUE Patton-Disconnect-Cause Prefix-1-dialed-but-not-allowed 0x09
+VALUE Patton-Disconnect-Cause Prefix-1-dialed-but-not-required 0x0A
+VALUE Patton-Disconnect-Cause More-digits-received-than-allowed-call-is-proceeding 0x0B
+VALUE Patton-Disconnect-Cause Normal-call-clearing 0x10
+VALUE Patton-Disconnect-Cause User-busy 0x11
+VALUE Patton-Disconnect-Cause No-user-responding 0x12
+VALUE Patton-Disconnect-Cause no-answer-from-user 0x13
+VALUE Patton-Disconnect-Cause Call-rejected 0x15
+VALUE Patton-Disconnect-Cause Number-changed 0x16
+VALUE Patton-Disconnect-Cause Reverse-charging-rejected 0x17
+VALUE Patton-Disconnect-Cause Call-suspended 0x18
+VALUE Patton-Disconnect-Cause Call-resumed 0x19
+VALUE Patton-Disconnect-Cause Non-selected-user-clearing 0x1A
+VALUE Patton-Disconnect-Cause Destination-out-of-order 0x1B
+VALUE Patton-Disconnect-Cause Invalid-number-format-incomplete-number 0x1C
+VALUE Patton-Disconnect-Cause Facility-rejected 0x1D
+VALUE Patton-Disconnect-Cause Response-to-STATUS-ENQUIRY 0x1E
+VALUE Patton-Disconnect-Cause Normal-unspecified 0x1F
+VALUE Patton-Disconnect-Cause Circuit-out-of-order 0x21
+VALUE Patton-Disconnect-Cause No-circuit/channel-available 0x22
+VALUE Patton-Disconnect-Cause Destination-unattainable 0x23
+VALUE Patton-Disconnect-Cause Degraded-service 0x25
+VALUE Patton-Disconnect-Cause Network-WAN-out-of-order 0x26
+VALUE Patton-Disconnect-Cause Transit-delay-range-cannot-be-achieved 0x27
+VALUE Patton-Disconnect-Cause Throughput-range-cannot-be-achieved 0x28
+VALUE Patton-Disconnect-Cause Temporary-failure 0x29
+VALUE Patton-Disconnect-Cause Switching-equipment-congestion 0x2A
+VALUE Patton-Disconnect-Cause Access-information-discarded 0x2B
+VALUE Patton-Disconnect-Cause Requested-circuit-channel-not-available 0x2C
+VALUE Patton-Disconnect-Cause Pre-empted 0x2D
+VALUE Patton-Disconnect-Cause Precedence-call-blocked 0x2E
+VALUE Patton-Disconnect-Cause Resource-unavailable-unspecified 0x2F
+VALUE Patton-Disconnect-Cause Quality-of-service-unavailable 0x31
+VALUE Patton-Disconnect-Cause Requested-facility-not-subscribed 0x32
+VALUE Patton-Disconnect-Cause Reverse-charging-not-allowed 0x33
+VALUE Patton-Disconnect-Cause Outgoing-calls-barred 0x34
+VALUE Patton-Disconnect-Cause Outgoing-calls-barred-within-CUG 0x35
+VALUE Patton-Disconnect-Cause Incoming-calls-barred 0x36
+VALUE Patton-Disconnect-Cause Incoming-calls-barred-within-CUG 0x37
+VALUE Patton-Disconnect-Cause Call-waiting-not-subscribed 0x38
+VALUE Patton-Disconnect-Cause Bearer-capability-not-authorized 0x39
+VALUE Patton-Disconnect-Cause Bearer-capability-not-presently-available 0x3A
+VALUE Patton-Disconnect-Cause Service-or-option-not-available-unspecified 0x3F
+VALUE Patton-Disconnect-Cause Bearer-service-not-implemented 0x41
+VALUE Patton-Disconnect-Cause Channel-type-not-implemented 0x42
+VALUE Patton-Disconnect-Cause Transit-network-selection-not-implemented 0x43
+VALUE Patton-Disconnect-Cause Message-not-implemented 0x44
+VALUE Patton-Disconnect-Cause Requested-facility-not-implemented 0x45
+VALUE Patton-Disconnect-Cause Only-restricted-digital-information-bearer-capability-is-avail 0x46
+VALUE Patton-Disconnect-Cause Service-or-option-not-implemented-unspecified 0x4F
+VALUE Patton-Disconnect-Cause Invalid-call-reference-value 0x51
+VALUE Patton-Disconnect-Cause Identified-channel-does-not-exist 0x52
+VALUE Patton-Disconnect-Cause A-suspended-call-exists-but-this-call-identity-does-not 0x53
+VALUE Patton-Disconnect-Cause Call-identity-in-use 0x54
+VALUE Patton-Disconnect-Cause No-call-suspended 0x55
+VALUE Patton-Disconnect-Cause Call-having-the-requested-call-identity-has-been-cleared 0x56
+VALUE Patton-Disconnect-Cause Called-user-not-member-of-CUG 0x57
+VALUE Patton-Disconnect-Cause Incompatible-destination 0x58
+VALUE Patton-Disconnect-Cause Non-existent-abbreviated-address-entry 0x59
+VALUE Patton-Disconnect-Cause Destination-address-missing-and-direct-call-not-subscribed 0x5A
+VALUE Patton-Disconnect-Cause Invalid-transit-network-selection-national-use 0x5B
+VALUE Patton-Disconnect-Cause Invalid-facility-parameter 0x5C
+VALUE Patton-Disconnect-Cause Mandatory-information-element-is-missing 0x5D
+VALUE Patton-Disconnect-Cause Invalid-message-unspecified 0x5F
+VALUE Patton-Disconnect-Cause Mandatory-information-element-is-missing-2 0x60
+VALUE Patton-Disconnect-Cause Message-type-non-existent-or-not-implemented 0x61
+VALUE Patton-Disconnect-Cause Message-not-compatible-with-call-state 0x62
+VALUE Patton-Disconnect-Cause information-element-nonexistant-or-not-implemented 0x63
+VALUE Patton-Disconnect-Cause Invalid-information-element-contents 0x64
+VALUE Patton-Disconnect-Cause Message-not-compatible-with-call-state-2 0x65
+VALUE Patton-Disconnect-Cause Recovery-on-timer-expiry 0x66
+VALUE Patton-Disconnect-Cause parameter-non-existent-or-not-implemented-passed-on 0x67
+VALUE Patton-Disconnect-Cause Protocol-error-unspecified 0x6F
+VALUE Patton-Disconnect-Cause Internetworking-unspecified 0x7F
+
+END-VENDOR Patton
diff --git a/share/dictionary.perle b/share/dictionary.perle
new file mode 100644
index 0000000..01242c6
--- /dev/null
+++ b/share/dictionary.perle
@@ -0,0 +1,525 @@
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Perle dictionary.
+#
+# Perle Systems Ltd.
+# http://www.perle.com/
+#
+# Version: 1.30 21-May-2008 Add attribute for clustered port access
+# Version: 1.20 30-Nov-2005 Add new line access right values for ports
+# up to 49.
+# Version: 1.10 11-Nov-2003 Add new line access right values
+# Version: 1.00 17-Jul-2003 original release for vendor specific field support
+#
+
+VENDOR Perle 1966
+
+BEGIN-VENDOR Perle
+
+# Perle Extensions
+ATTRIBUTE Perle-Clustered-Port-Access 99 integer
+ATTRIBUTE Perle-User-Level 100 integer
+ATTRIBUTE Perle-Line-Access-Port-1 101 integer
+ATTRIBUTE Perle-Line-Access-Port-2 102 integer
+ATTRIBUTE Perle-Line-Access-Port-3 103 integer
+ATTRIBUTE Perle-Line-Access-Port-4 104 integer
+ATTRIBUTE Perle-Line-Access-Port-5 105 integer
+ATTRIBUTE Perle-Line-Access-Port-6 106 integer
+ATTRIBUTE Perle-Line-Access-Port-7 107 integer
+ATTRIBUTE Perle-Line-Access-Port-8 108 integer
+ATTRIBUTE Perle-Line-Access-Port-9 109 integer
+ATTRIBUTE Perle-Line-Access-Port-10 110 integer
+ATTRIBUTE Perle-Line-Access-Port-11 111 integer
+ATTRIBUTE Perle-Line-Access-Port-12 112 integer
+ATTRIBUTE Perle-Line-Access-Port-13 113 integer
+ATTRIBUTE Perle-Line-Access-Port-14 114 integer
+ATTRIBUTE Perle-Line-Access-Port-15 115 integer
+ATTRIBUTE Perle-Line-Access-Port-16 116 integer
+ATTRIBUTE Perle-Line-Access-Port-17 117 integer
+ATTRIBUTE Perle-Line-Access-Port-18 118 integer
+ATTRIBUTE Perle-Line-Access-Port-19 119 integer
+ATTRIBUTE Perle-Line-Access-Port-20 120 integer
+ATTRIBUTE Perle-Line-Access-Port-21 121 integer
+ATTRIBUTE Perle-Line-Access-Port-22 122 integer
+ATTRIBUTE Perle-Line-Access-Port-23 123 integer
+ATTRIBUTE Perle-Line-Access-Port-24 124 integer
+ATTRIBUTE Perle-Line-Access-Port-25 125 integer
+ATTRIBUTE Perle-Line-Access-Port-26 126 integer
+ATTRIBUTE Perle-Line-Access-Port-27 127 integer
+ATTRIBUTE Perle-Line-Access-Port-28 128 integer
+ATTRIBUTE Perle-Line-Access-Port-29 129 integer
+ATTRIBUTE Perle-Line-Access-Port-30 130 integer
+ATTRIBUTE Perle-Line-Access-Port-31 131 integer
+ATTRIBUTE Perle-Line-Access-Port-32 132 integer
+ATTRIBUTE Perle-Line-Access-Port-33 133 integer
+ATTRIBUTE Perle-Line-Access-Port-34 134 integer
+ATTRIBUTE Perle-Line-Access-Port-35 135 integer
+ATTRIBUTE Perle-Line-Access-Port-36 136 integer
+ATTRIBUTE Perle-Line-Access-Port-37 137 integer
+ATTRIBUTE Perle-Line-Access-Port-38 138 integer
+ATTRIBUTE Perle-Line-Access-Port-39 139 integer
+ATTRIBUTE Perle-Line-Access-Port-40 140 integer
+ATTRIBUTE Perle-Line-Access-Port-41 141 integer
+ATTRIBUTE Perle-Line-Access-Port-42 142 integer
+ATTRIBUTE Perle-Line-Access-Port-43 143 integer
+ATTRIBUTE Perle-Line-Access-Port-44 144 integer
+ATTRIBUTE Perle-Line-Access-Port-45 145 integer
+ATTRIBUTE Perle-Line-Access-Port-46 146 integer
+ATTRIBUTE Perle-Line-Access-Port-47 147 integer
+ATTRIBUTE Perle-Line-Access-Port-48 148 integer
+ATTRIBUTE Perle-Line-Access-Port-49 149 integer
+
+# Perle Clustered Port Access Values
+VALUE Perle-Clustered-Port-Access Disabled 0
+VALUE Perle-Clustered-Port-Access Enabled 1
+
+# Perle User Level Values
+VALUE Perle-User-Level Admin 1
+VALUE Perle-User-Level Normal 2
+VALUE Perle-User-Level Restricted 3
+VALUE Perle-User-Level Menu 4
+
+# Perle Line Access Right Values
+VALUE Perle-Line-Access-Port-1 Disabled 0
+VALUE Perle-Line-Access-Port-1 Read-Write 1
+VALUE Perle-Line-Access-Port-1 Read-Input 2
+VALUE Perle-Line-Access-Port-1 Read-Input-Write 3
+VALUE Perle-Line-Access-Port-1 Read-Output 4
+VALUE Perle-Line-Access-Port-1 Read-Output-Write 5
+VALUE Perle-Line-Access-Port-1 Read-Output-Input 6
+VALUE Perle-Line-Access-Port-1 Read-Output-Input-Write 7
+
+VALUE Perle-Line-Access-Port-2 Disabled 0
+VALUE Perle-Line-Access-Port-2 Read-Write 1
+VALUE Perle-Line-Access-Port-2 Read-Input 2
+VALUE Perle-Line-Access-Port-2 Read-Input-Write 3
+VALUE Perle-Line-Access-Port-2 Read-Output 4
+VALUE Perle-Line-Access-Port-2 Read-Output-Write 5
+VALUE Perle-Line-Access-Port-2 Read-Output-Input 6
+VALUE Perle-Line-Access-Port-2 Read-Output-Input-Write 7
+
+VALUE Perle-Line-Access-Port-3 Disabled 0
+VALUE Perle-Line-Access-Port-3 Read-Write 1
+VALUE Perle-Line-Access-Port-3 Read-Input 2
+VALUE Perle-Line-Access-Port-3 Read-Input-Write 3
+VALUE Perle-Line-Access-Port-3 Read-Output 4
+VALUE Perle-Line-Access-Port-3 Read-Output-Write 5
+VALUE Perle-Line-Access-Port-3 Read-Output-Input 6
+VALUE Perle-Line-Access-Port-3 Read-Output-Input-Write 7
+
+VALUE Perle-Line-Access-Port-4 Disabled 0
+VALUE Perle-Line-Access-Port-4 Read-Write 1
+VALUE Perle-Line-Access-Port-4 Read-Input 2
+VALUE Perle-Line-Access-Port-4 Read-Input-Write 3
+VALUE Perle-Line-Access-Port-4 Read-Output 4
+VALUE Perle-Line-Access-Port-4 Read-Output-Write 5
+VALUE Perle-Line-Access-Port-4 Read-Output-Input 6
+VALUE Perle-Line-Access-Port-4 Read-Output-Input-Write 7
+
+VALUE Perle-Line-Access-Port-5 Disabled 0
+VALUE Perle-Line-Access-Port-5 Read-Write 1
+VALUE Perle-Line-Access-Port-5 Read-Input 2
+VALUE Perle-Line-Access-Port-5 Read-Input-Write 3
+VALUE Perle-Line-Access-Port-5 Read-Output 4
+VALUE Perle-Line-Access-Port-5 Read-Output-Write 5
+VALUE Perle-Line-Access-Port-5 Read-Output-Input 6
+VALUE Perle-Line-Access-Port-5 Read-Output-Input-Write 7
+
+VALUE Perle-Line-Access-Port-6 Disabled 0
+VALUE Perle-Line-Access-Port-6 Read-Write 1
+VALUE Perle-Line-Access-Port-6 Read-Input 2
+VALUE Perle-Line-Access-Port-6 Read-Input-Write 3
+VALUE Perle-Line-Access-Port-6 Read-Output 4
+VALUE Perle-Line-Access-Port-6 Read-Output-Write 5
+VALUE Perle-Line-Access-Port-6 Read-Output-Input 6
+VALUE Perle-Line-Access-Port-6 Read-Output-Input-Write 7
+
+VALUE Perle-Line-Access-Port-7 Disabled 0
+VALUE Perle-Line-Access-Port-7 Read-Write 1
+VALUE Perle-Line-Access-Port-7 Read-Input 2
+VALUE Perle-Line-Access-Port-7 Read-Input-Write 3
+VALUE Perle-Line-Access-Port-7 Read-Output 4
+VALUE Perle-Line-Access-Port-7 Read-Output-Write 5
+VALUE Perle-Line-Access-Port-7 Read-Output-Input 6
+VALUE Perle-Line-Access-Port-7 Read-Output-Input-Write 7
+
+VALUE Perle-Line-Access-Port-8 Disabled 0
+VALUE Perle-Line-Access-Port-8 Read-Write 1
+VALUE Perle-Line-Access-Port-8 Read-Input 2
+VALUE Perle-Line-Access-Port-8 Read-Input-Write 3
+VALUE Perle-Line-Access-Port-8 Read-Output 4
+VALUE Perle-Line-Access-Port-8 Read-Output-Write 5
+VALUE Perle-Line-Access-Port-8 Read-Output-Input 6
+VALUE Perle-Line-Access-Port-8 Read-Output-Input-Write 7
+
+VALUE Perle-Line-Access-Port-9 Disabled 0
+VALUE Perle-Line-Access-Port-9 Read-Write 1
+VALUE Perle-Line-Access-Port-9 Read-Input 2
+VALUE Perle-Line-Access-Port-9 Read-Input-Write 3
+VALUE Perle-Line-Access-Port-9 Read-Output 4
+VALUE Perle-Line-Access-Port-9 Read-Output-Write 5
+VALUE Perle-Line-Access-Port-9 Read-Output-Input 6
+VALUE Perle-Line-Access-Port-9 Read-Output-Input-Write 7
+
+VALUE Perle-Line-Access-Port-10 Disabled 0
+VALUE Perle-Line-Access-Port-10 Read-Write 1
+VALUE Perle-Line-Access-Port-10 Read-Input 2
+VALUE Perle-Line-Access-Port-10 Read-Input-Write 3
+VALUE Perle-Line-Access-Port-10 Read-Output 4
+VALUE Perle-Line-Access-Port-10 Read-Output-Write 5
+VALUE Perle-Line-Access-Port-10 Read-Output-Input 6
+VALUE Perle-Line-Access-Port-10 Read-Output-Input-Write 7
+
+VALUE Perle-Line-Access-Port-11 Disabled 0
+VALUE Perle-Line-Access-Port-11 Read-Write 1
+VALUE Perle-Line-Access-Port-11 Read-Input 2
+VALUE Perle-Line-Access-Port-11 Read-Input-Write 3
+VALUE Perle-Line-Access-Port-11 Read-Output 4
+VALUE Perle-Line-Access-Port-11 Read-Output-Write 5
+VALUE Perle-Line-Access-Port-11 Read-Output-Input 6
+VALUE Perle-Line-Access-Port-11 Read-Output-Input-Write 7
+
+VALUE Perle-Line-Access-Port-12 Disabled 0
+VALUE Perle-Line-Access-Port-12 Read-Write 1
+VALUE Perle-Line-Access-Port-12 Read-Input 2
+VALUE Perle-Line-Access-Port-12 Read-Input-Write 3
+VALUE Perle-Line-Access-Port-12 Read-Output 4
+VALUE Perle-Line-Access-Port-12 Read-Output-Write 5
+VALUE Perle-Line-Access-Port-12 Read-Output-Input 6
+VALUE Perle-Line-Access-Port-12 Read-Output-Input-Write 7
+
+VALUE Perle-Line-Access-Port-13 Disabled 0
+VALUE Perle-Line-Access-Port-13 Read-Write 1
+VALUE Perle-Line-Access-Port-13 Read-Input 2
+VALUE Perle-Line-Access-Port-13 Read-Input-Write 3
+VALUE Perle-Line-Access-Port-13 Read-Output 4
+VALUE Perle-Line-Access-Port-13 Read-Output-Write 5
+VALUE Perle-Line-Access-Port-13 Read-Output-Input 6
+VALUE Perle-Line-Access-Port-13 Read-Output-Input-Write 7
+
+VALUE Perle-Line-Access-Port-14 Disabled 0
+VALUE Perle-Line-Access-Port-14 Read-Write 1
+VALUE Perle-Line-Access-Port-14 Read-Input 2
+VALUE Perle-Line-Access-Port-14 Read-Input-Write 3
+VALUE Perle-Line-Access-Port-14 Read-Output 4
+VALUE Perle-Line-Access-Port-14 Read-Output-Write 5
+VALUE Perle-Line-Access-Port-14 Read-Output-Input 6
+VALUE Perle-Line-Access-Port-14 Read-Output-Input-Write 7
+
+VALUE Perle-Line-Access-Port-15 Disabled 0
+VALUE Perle-Line-Access-Port-15 Read-Write 1
+VALUE Perle-Line-Access-Port-15 Read-Input 2
+VALUE Perle-Line-Access-Port-15 Read-Input-Write 3
+VALUE Perle-Line-Access-Port-15 Read-Output 4
+VALUE Perle-Line-Access-Port-15 Read-Output-Write 5
+VALUE Perle-Line-Access-Port-15 Read-Output-Input 6
+VALUE Perle-Line-Access-Port-15 Read-Output-Input-Write 7
+
+VALUE Perle-Line-Access-Port-16 Disabled 0
+VALUE Perle-Line-Access-Port-16 Read-Write 1
+VALUE Perle-Line-Access-Port-16 Read-Input 2
+VALUE Perle-Line-Access-Port-16 Read-Input-Write 3
+VALUE Perle-Line-Access-Port-16 Read-Output 4
+VALUE Perle-Line-Access-Port-16 Read-Output-Write 5
+VALUE Perle-Line-Access-Port-16 Read-Output-Input 6
+VALUE Perle-Line-Access-Port-16 Read-Output-Input-Write 7
+
+VALUE Perle-Line-Access-Port-17 Disabled 0
+VALUE Perle-Line-Access-Port-17 Read-Write 1
+VALUE Perle-Line-Access-Port-17 Read-Input 2
+VALUE Perle-Line-Access-Port-17 Read-Input-Write 3
+VALUE Perle-Line-Access-Port-17 Read-Output 4
+VALUE Perle-Line-Access-Port-17 Read-Output-Write 5
+VALUE Perle-Line-Access-Port-17 Read-Output-Input 6
+VALUE Perle-Line-Access-Port-17 Read-Output-Input-Write 7
+
+VALUE Perle-Line-Access-Port-18 Disabled 0
+VALUE Perle-Line-Access-Port-18 Read-Write 1
+VALUE Perle-Line-Access-Port-18 Read-Input 2
+VALUE Perle-Line-Access-Port-18 Read-Input-Write 3
+VALUE Perle-Line-Access-Port-18 Read-Output 4
+VALUE Perle-Line-Access-Port-18 Read-Output-Write 5
+VALUE Perle-Line-Access-Port-18 Read-Output-Input 6
+VALUE Perle-Line-Access-Port-18 Read-Output-Input-Write 7
+
+VALUE Perle-Line-Access-Port-19 Disabled 0
+VALUE Perle-Line-Access-Port-19 Read-Write 1
+VALUE Perle-Line-Access-Port-19 Read-Input 2
+VALUE Perle-Line-Access-Port-19 Read-Input-Write 3
+VALUE Perle-Line-Access-Port-19 Read-Output 4
+VALUE Perle-Line-Access-Port-19 Read-Output-Write 5
+VALUE Perle-Line-Access-Port-19 Read-Output-Input 6
+VALUE Perle-Line-Access-Port-19 Read-Output-Input-Write 7
+
+VALUE Perle-Line-Access-Port-20 Disabled 0
+VALUE Perle-Line-Access-Port-20 Read-Write 1
+VALUE Perle-Line-Access-Port-20 Read-Input 2
+VALUE Perle-Line-Access-Port-20 Read-Input-Write 3
+VALUE Perle-Line-Access-Port-20 Read-Output 4
+VALUE Perle-Line-Access-Port-20 Read-Output-Write 5
+VALUE Perle-Line-Access-Port-20 Read-Output-Input 6
+VALUE Perle-Line-Access-Port-20 Read-Output-Input-Write 7
+
+VALUE Perle-Line-Access-Port-21 Disabled 0
+VALUE Perle-Line-Access-Port-21 Read-Write 1
+VALUE Perle-Line-Access-Port-21 Read-Input 2
+VALUE Perle-Line-Access-Port-21 Read-Input-Write 3
+VALUE Perle-Line-Access-Port-21 Read-Output 4
+VALUE Perle-Line-Access-Port-21 Read-Output-Write 5
+VALUE Perle-Line-Access-Port-21 Read-Output-Input 6
+VALUE Perle-Line-Access-Port-21 Read-Output-Input-Write 7
+
+VALUE Perle-Line-Access-Port-22 Disabled 0
+VALUE Perle-Line-Access-Port-22 Read-Write 1
+VALUE Perle-Line-Access-Port-22 Read-Input 2
+VALUE Perle-Line-Access-Port-22 Read-Input-Write 3
+VALUE Perle-Line-Access-Port-22 Read-Output 4
+VALUE Perle-Line-Access-Port-22 Read-Output-Write 5
+VALUE Perle-Line-Access-Port-22 Read-Output-Input 6
+VALUE Perle-Line-Access-Port-22 Read-Output-Input-Write 7
+
+VALUE Perle-Line-Access-Port-23 Disabled 0
+VALUE Perle-Line-Access-Port-23 Read-Write 1
+VALUE Perle-Line-Access-Port-23 Read-Input 2
+VALUE Perle-Line-Access-Port-23 Read-Input-Write 3
+VALUE Perle-Line-Access-Port-23 Read-Output 4
+VALUE Perle-Line-Access-Port-23 Read-Output-Write 5
+VALUE Perle-Line-Access-Port-23 Read-Output-Input 6
+VALUE Perle-Line-Access-Port-23 Read-Output-Input-Write 7
+
+VALUE Perle-Line-Access-Port-24 Disabled 0
+VALUE Perle-Line-Access-Port-24 Read-Write 1
+VALUE Perle-Line-Access-Port-24 Read-Input 2
+VALUE Perle-Line-Access-Port-24 Read-Input-Write 3
+VALUE Perle-Line-Access-Port-24 Read-Output 4
+VALUE Perle-Line-Access-Port-24 Read-Output-Write 5
+VALUE Perle-Line-Access-Port-24 Read-Output-Input 6
+VALUE Perle-Line-Access-Port-24 Read-Output-Input-Write 7
+
+VALUE Perle-Line-Access-Port-25 Disabled 0
+VALUE Perle-Line-Access-Port-25 Read-Write 1
+VALUE Perle-Line-Access-Port-25 Read-Input 2
+VALUE Perle-Line-Access-Port-25 Read-Input-Write 3
+VALUE Perle-Line-Access-Port-25 Read-Output 4
+VALUE Perle-Line-Access-Port-25 Read-Output-Write 5
+VALUE Perle-Line-Access-Port-25 Read-Output-Input 6
+VALUE Perle-Line-Access-Port-25 Read-Output-Input-Write 7
+
+VALUE Perle-Line-Access-Port-26 Disabled 0
+VALUE Perle-Line-Access-Port-26 Read-Write 1
+VALUE Perle-Line-Access-Port-26 Read-Input 2
+VALUE Perle-Line-Access-Port-26 Read-Input-Write 3
+VALUE Perle-Line-Access-Port-26 Read-Output 4
+VALUE Perle-Line-Access-Port-26 Read-Output-Write 5
+VALUE Perle-Line-Access-Port-26 Read-Output-Input 6
+VALUE Perle-Line-Access-Port-26 Read-Output-Input-Write 7
+
+VALUE Perle-Line-Access-Port-27 Disabled 0
+VALUE Perle-Line-Access-Port-27 Read-Write 1
+VALUE Perle-Line-Access-Port-27 Read-Input 2
+VALUE Perle-Line-Access-Port-27 Read-Input-Write 3
+VALUE Perle-Line-Access-Port-27 Read-Output 4
+VALUE Perle-Line-Access-Port-27 Read-Output-Write 5
+VALUE Perle-Line-Access-Port-27 Read-Output-Input 6
+VALUE Perle-Line-Access-Port-27 Read-Output-Input-Write 7
+
+VALUE Perle-Line-Access-Port-28 Disabled 0
+VALUE Perle-Line-Access-Port-28 Read-Write 1
+VALUE Perle-Line-Access-Port-28 Read-Input 2
+VALUE Perle-Line-Access-Port-28 Read-Input-Write 3
+VALUE Perle-Line-Access-Port-28 Read-Output 4
+VALUE Perle-Line-Access-Port-28 Read-Output-Write 5
+VALUE Perle-Line-Access-Port-28 Read-Output-Input 6
+VALUE Perle-Line-Access-Port-28 Read-Output-Input-Write 7
+
+VALUE Perle-Line-Access-Port-29 Disabled 0
+VALUE Perle-Line-Access-Port-29 Read-Write 1
+VALUE Perle-Line-Access-Port-29 Read-Input 2
+VALUE Perle-Line-Access-Port-29 Read-Input-Write 3
+VALUE Perle-Line-Access-Port-29 Read-Output 4
+VALUE Perle-Line-Access-Port-29 Read-Output-Write 5
+VALUE Perle-Line-Access-Port-29 Read-Output-Input 6
+VALUE Perle-Line-Access-Port-29 Read-Output-Input-Write 7
+
+VALUE Perle-Line-Access-Port-30 Disabled 0
+VALUE Perle-Line-Access-Port-30 Read-Write 1
+VALUE Perle-Line-Access-Port-30 Read-Input 2
+VALUE Perle-Line-Access-Port-30 Read-Input-Write 3
+VALUE Perle-Line-Access-Port-30 Read-Output 4
+VALUE Perle-Line-Access-Port-30 Read-Output-Write 5
+VALUE Perle-Line-Access-Port-30 Read-Output-Input 6
+VALUE Perle-Line-Access-Port-30 Read-Output-Input-Write 7
+
+VALUE Perle-Line-Access-Port-31 Disabled 0
+VALUE Perle-Line-Access-Port-31 Read-Write 1
+VALUE Perle-Line-Access-Port-31 Read-Input 2
+VALUE Perle-Line-Access-Port-31 Read-Input-Write 3
+VALUE Perle-Line-Access-Port-31 Read-Output 4
+VALUE Perle-Line-Access-Port-31 Read-Output-Write 5
+VALUE Perle-Line-Access-Port-31 Read-Output-Input 6
+VALUE Perle-Line-Access-Port-31 Read-Output-Input-Write 7
+
+VALUE Perle-Line-Access-Port-32 Disabled 0
+VALUE Perle-Line-Access-Port-32 Read-Write 1
+VALUE Perle-Line-Access-Port-32 Read-Input 2
+VALUE Perle-Line-Access-Port-32 Read-Input-Write 3
+VALUE Perle-Line-Access-Port-32 Read-Output 4
+VALUE Perle-Line-Access-Port-32 Read-Output-Write 5
+VALUE Perle-Line-Access-Port-32 Read-Output-Input 6
+VALUE Perle-Line-Access-Port-32 Read-Output-Input-Write 7
+
+VALUE Perle-Line-Access-Port-33 Disabled 0
+VALUE Perle-Line-Access-Port-33 Read-Write 1
+VALUE Perle-Line-Access-Port-33 Read-Input 2
+VALUE Perle-Line-Access-Port-33 Read-Input-Write 3
+VALUE Perle-Line-Access-Port-33 Read-Output 4
+VALUE Perle-Line-Access-Port-33 Read-Output-Write 5
+VALUE Perle-Line-Access-Port-33 Read-Output-Input 6
+VALUE Perle-Line-Access-Port-33 Read-Output-Input-Write 7
+
+VALUE Perle-Line-Access-Port-34 Disabled 0
+VALUE Perle-Line-Access-Port-34 Read-Write 1
+VALUE Perle-Line-Access-Port-34 Read-Input 2
+VALUE Perle-Line-Access-Port-34 Read-Input-Write 3
+VALUE Perle-Line-Access-Port-34 Read-Output 4
+VALUE Perle-Line-Access-Port-34 Read-Output-Write 5
+VALUE Perle-Line-Access-Port-34 Read-Output-Input 6
+VALUE Perle-Line-Access-Port-34 Read-Output-Input-Write 7
+
+VALUE Perle-Line-Access-Port-35 Disabled 0
+VALUE Perle-Line-Access-Port-35 Read-Write 1
+VALUE Perle-Line-Access-Port-35 Read-Input 2
+VALUE Perle-Line-Access-Port-35 Read-Input-Write 3
+VALUE Perle-Line-Access-Port-35 Read-Output 4
+VALUE Perle-Line-Access-Port-35 Read-Output-Write 5
+VALUE Perle-Line-Access-Port-35 Read-Output-Input 6
+VALUE Perle-Line-Access-Port-35 Read-Output-Input-Write 7
+
+VALUE Perle-Line-Access-Port-36 Disabled 0
+VALUE Perle-Line-Access-Port-36 Read-Write 1
+VALUE Perle-Line-Access-Port-36 Read-Input 2
+VALUE Perle-Line-Access-Port-36 Read-Input-Write 3
+VALUE Perle-Line-Access-Port-36 Read-Output 4
+VALUE Perle-Line-Access-Port-36 Read-Output-Write 5
+VALUE Perle-Line-Access-Port-36 Read-Output-Input 6
+VALUE Perle-Line-Access-Port-36 Read-Output-Input-Write 7
+
+VALUE Perle-Line-Access-Port-37 Disabled 0
+VALUE Perle-Line-Access-Port-37 Read-Write 1
+VALUE Perle-Line-Access-Port-37 Read-Input 2
+VALUE Perle-Line-Access-Port-37 Read-Input-Write 3
+VALUE Perle-Line-Access-Port-37 Read-Output 4
+VALUE Perle-Line-Access-Port-37 Read-Output-Write 5
+VALUE Perle-Line-Access-Port-37 Read-Output-Input 6
+VALUE Perle-Line-Access-Port-37 Read-Output-Input-Write 7
+
+VALUE Perle-Line-Access-Port-38 Disabled 0
+VALUE Perle-Line-Access-Port-38 Read-Write 1
+VALUE Perle-Line-Access-Port-38 Read-Input 2
+VALUE Perle-Line-Access-Port-38 Read-Input-Write 3
+VALUE Perle-Line-Access-Port-38 Read-Output 4
+VALUE Perle-Line-Access-Port-38 Read-Output-Write 5
+VALUE Perle-Line-Access-Port-38 Read-Output-Input 6
+VALUE Perle-Line-Access-Port-38 Read-Output-Input-Write 7
+
+VALUE Perle-Line-Access-Port-39 Disabled 0
+VALUE Perle-Line-Access-Port-39 Read-Write 1
+VALUE Perle-Line-Access-Port-39 Read-Input 2
+VALUE Perle-Line-Access-Port-39 Read-Input-Write 3
+VALUE Perle-Line-Access-Port-39 Read-Output 4
+VALUE Perle-Line-Access-Port-39 Read-Output-Write 5
+VALUE Perle-Line-Access-Port-39 Read-Output-Input 6
+VALUE Perle-Line-Access-Port-39 Read-Output-Input-Write 7
+
+VALUE Perle-Line-Access-Port-40 Disabled 0
+VALUE Perle-Line-Access-Port-40 Read-Write 1
+VALUE Perle-Line-Access-Port-40 Read-Input 2
+VALUE Perle-Line-Access-Port-40 Read-Input-Write 3
+VALUE Perle-Line-Access-Port-40 Read-Output 4
+VALUE Perle-Line-Access-Port-40 Read-Output-Write 5
+VALUE Perle-Line-Access-Port-40 Read-Output-Input 6
+VALUE Perle-Line-Access-Port-40 Read-Output-Input-Write 7
+
+VALUE Perle-Line-Access-Port-41 Disabled 0
+VALUE Perle-Line-Access-Port-41 Read-Write 1
+VALUE Perle-Line-Access-Port-41 Read-Input 2
+VALUE Perle-Line-Access-Port-41 Read-Input-Write 3
+VALUE Perle-Line-Access-Port-41 Read-Output 4
+VALUE Perle-Line-Access-Port-41 Read-Output-Write 5
+VALUE Perle-Line-Access-Port-41 Read-Output-Input 6
+VALUE Perle-Line-Access-Port-41 Read-Output-Input-Write 7
+
+VALUE Perle-Line-Access-Port-42 Disabled 0
+VALUE Perle-Line-Access-Port-42 Read-Write 1
+VALUE Perle-Line-Access-Port-42 Read-Input 2
+VALUE Perle-Line-Access-Port-42 Read-Input-Write 3
+VALUE Perle-Line-Access-Port-42 Read-Output 4
+VALUE Perle-Line-Access-Port-42 Read-Output-Write 5
+VALUE Perle-Line-Access-Port-42 Read-Output-Input 6
+VALUE Perle-Line-Access-Port-42 Read-Output-Input-Write 7
+
+VALUE Perle-Line-Access-Port-43 Disabled 0
+VALUE Perle-Line-Access-Port-43 Read-Write 1
+VALUE Perle-Line-Access-Port-43 Read-Input 2
+VALUE Perle-Line-Access-Port-43 Read-Input-Write 3
+VALUE Perle-Line-Access-Port-43 Read-Output 4
+VALUE Perle-Line-Access-Port-43 Read-Output-Write 5
+VALUE Perle-Line-Access-Port-43 Read-Output-Input 6
+VALUE Perle-Line-Access-Port-43 Read-Output-Input-Write 7
+
+VALUE Perle-Line-Access-Port-44 Disabled 0
+VALUE Perle-Line-Access-Port-44 Read-Write 1
+VALUE Perle-Line-Access-Port-44 Read-Input 2
+VALUE Perle-Line-Access-Port-44 Read-Input-Write 3
+VALUE Perle-Line-Access-Port-44 Read-Output 4
+VALUE Perle-Line-Access-Port-44 Read-Output-Write 5
+VALUE Perle-Line-Access-Port-44 Read-Output-Input 6
+VALUE Perle-Line-Access-Port-44 Read-Output-Input-Write 7
+
+VALUE Perle-Line-Access-Port-45 Disabled 0
+VALUE Perle-Line-Access-Port-45 Read-Write 1
+VALUE Perle-Line-Access-Port-45 Read-Input 2
+VALUE Perle-Line-Access-Port-45 Read-Input-Write 3
+VALUE Perle-Line-Access-Port-45 Read-Output 4
+VALUE Perle-Line-Access-Port-45 Read-Output-Write 5
+VALUE Perle-Line-Access-Port-45 Read-Output-Input 6
+VALUE Perle-Line-Access-Port-45 Read-Output-Input-Write 7
+
+VALUE Perle-Line-Access-Port-46 Disabled 0
+VALUE Perle-Line-Access-Port-46 Read-Write 1
+VALUE Perle-Line-Access-Port-46 Read-Input 2
+VALUE Perle-Line-Access-Port-46 Read-Input-Write 3
+VALUE Perle-Line-Access-Port-46 Read-Output 4
+VALUE Perle-Line-Access-Port-46 Read-Output-Write 5
+VALUE Perle-Line-Access-Port-46 Read-Output-Input 6
+VALUE Perle-Line-Access-Port-46 Read-Output-Input-Write 7
+
+VALUE Perle-Line-Access-Port-47 Disabled 0
+VALUE Perle-Line-Access-Port-47 Read-Write 1
+VALUE Perle-Line-Access-Port-47 Read-Input 2
+VALUE Perle-Line-Access-Port-47 Read-Input-Write 3
+VALUE Perle-Line-Access-Port-47 Read-Output 4
+VALUE Perle-Line-Access-Port-47 Read-Output-Write 5
+VALUE Perle-Line-Access-Port-47 Read-Output-Input 6
+VALUE Perle-Line-Access-Port-47 Read-Output-Input-Write 7
+
+VALUE Perle-Line-Access-Port-48 Disabled 0
+VALUE Perle-Line-Access-Port-48 Read-Write 1
+VALUE Perle-Line-Access-Port-48 Read-Input 2
+VALUE Perle-Line-Access-Port-48 Read-Input-Write 3
+VALUE Perle-Line-Access-Port-48 Read-Output 4
+VALUE Perle-Line-Access-Port-48 Read-Output-Write 5
+VALUE Perle-Line-Access-Port-48 Read-Output-Input 6
+VALUE Perle-Line-Access-Port-48 Read-Output-Input-Write 7
+
+VALUE Perle-Line-Access-Port-49 Disabled 0
+VALUE Perle-Line-Access-Port-49 Read-Write 1
+VALUE Perle-Line-Access-Port-49 Read-Input 2
+VALUE Perle-Line-Access-Port-49 Read-Input-Write 3
+VALUE Perle-Line-Access-Port-49 Read-Output 4
+VALUE Perle-Line-Access-Port-49 Read-Output-Write 5
+VALUE Perle-Line-Access-Port-49 Read-Output-Input 6
+VALUE Perle-Line-Access-Port-49 Read-Output-Input-Write 7
+
+END-VENDOR Perle
diff --git a/share/dictionary.pfsense b/share/dictionary.pfsense
new file mode 100644
index 0000000..c211a6f
--- /dev/null
+++ b/share/dictionary.pfsense
@@ -0,0 +1,18 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+#
+# dictionary.pfsense
+# pfSense Captive Portal Dictionary
+#
+# https://github.com/pfsense/pfsense/blob/master/src/usr/share/doc/radius/dictionary.pfsense
+#
+
+VENDOR pfSense 13644
+
+BEGIN-VENDOR pfSense
+
+ATTRIBUTE pfSense-Bandwidth-Max-Up 1 integer
+ATTRIBUTE pfSense-Bandwidth-Max-Down 2 integer
+ATTRIBUTE pfSense-Max-Total-Octets 3 integer
+
+END-VENDOR pfSense
diff --git a/share/dictionary.pica8 b/share/dictionary.pica8
new file mode 100644
index 0000000..e3a15aa
--- /dev/null
+++ b/share/dictionary.pica8
@@ -0,0 +1,20 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+# Version $Id$
+#
+# Pica8 RADIUS attributes
+# For general information please visit:
+# http://www.pica8.com
+#
+
+VENDOR Pica8 35098
+
+BEGIN-VENDOR Pica8
+
+ATTRIBUTE Pica8-AVPair 1 string
+ATTRIBUTE Pica8-IP-Downloadable-ACL-Rule 2 string
+ATTRIBUTE Pica8-IP-Downloadable-ACL-Name 3 string
+ATTRIBUTE Pica8-Redirect-URL 4 string
+
+END-VENDOR Pica8
diff --git a/share/dictionary.propel b/share/dictionary.propel
new file mode 100644
index 0000000..d3eaac9
--- /dev/null
+++ b/share/dictionary.propel
@@ -0,0 +1,17 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# $Id$
+#
+
+VENDOR Propel 14895
+
+BEGIN-VENDOR Propel
+ATTRIBUTE Propel-Accelerate 1 integer
+ATTRIBUTE Propel-Dialed-Digits 2 string
+ATTRIBUTE Propel-Client-IP-Address 3 ipaddr
+ATTRIBUTE Propel-Client-NAS-IP-Address 4 ipaddr
+ATTRIBUTE Propel-Client-Source-ID 5 integer
+ATTRIBUTE Propel-Content-Filter-ID 6 integer
+END-VENDOR Propel
diff --git a/share/dictionary.prosoft b/share/dictionary.prosoft
new file mode 100644
index 0000000..7b20339
--- /dev/null
+++ b/share/dictionary.prosoft
@@ -0,0 +1,44 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Prosoft, as posted to the list.
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR Prosoft 4735
+
+#
+# Custom Prosoft attributes.
+#
+
+BEGIN-VENDOR Prosoft
+
+ATTRIBUTE Prosoft-Home-Agent-Address 0 ipaddr
+ATTRIBUTE Prosoft-Default-Gateway 1 ipaddr
+ATTRIBUTE Prosoft-Primary-DNS 2 ipaddr
+ATTRIBUTE Prosoft-Secondary-DNS 3 ipaddr
+ATTRIBUTE Prosoft-Security-Parameter-Index 4 integer
+ATTRIBUTE Prosoft-Security-Key 5 string
+ATTRIBUTE Prosoft-MAC-Address 7 string
+ATTRIBUTE Prosoft-Authentication-Reason 8 integer
+ATTRIBUTE Prosoft-ATM-Interface 9 integer
+ATTRIBUTE Prosoft-ATM-VPI 10 integer
+ATTRIBUTE Prosoft-ATM-VCI 11 integer
+ATTRIBUTE Prosoft-RSC-Identifier 12 string
+ATTRIBUTE Prosoft-NPM-Identifier 13 string
+ATTRIBUTE Prosoft-NPM-IP 14 string
+ATTRIBUTE Prosoft-Sector-ID 15 string
+ATTRIBUTE Prosoft-Auth-Role 16 integer
+
+VALUE Prosoft-Auth-Role Read-Status 0
+VALUE Prosoft-Auth-Role Read-Config 1
+VALUE Prosoft-Auth-Role Read-Write 2
+VALUE Prosoft-Auth-Role Admin 3
+VALUE Prosoft-Auth-Role Super-user 4
+
+END-VENDOR Prosoft
diff --git a/share/dictionary.proxim b/share/dictionary.proxim
new file mode 100644
index 0000000..58f29d7
--- /dev/null
+++ b/share/dictionary.proxim
@@ -0,0 +1,94 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Dictionary for Proxim Wireless.
+#
+# $Id$
+#
+
+VENDOR Proxim 841
+
+BEGIN-VENDOR Proxim
+
+# SU Management VLAN and Ethernet 1 VLAN parameters
+ATTRIBUTE Proxim_E1_VLAN_MODE 4 integer
+ATTRIBUTE Proxim_SU_VLAN_NAME 5 string
+
+ATTRIBUTE Proxim_E1_Access_VLAN_ID 6 integer
+ATTRIBUTE Proxim_E1_Access_VLAN_Pri 7 integer
+
+ATTRIBUTE Proxim_Mgmt_VLAN_ID 8 integer
+ATTRIBUTE Proxim_Mgmt_VLAN_Pri 9 integer
+
+ATTRIBUTE Proxim_E1_TrunkID_01 10 integer
+ATTRIBUTE Proxim_E1_TrunkID_02 11 integer
+ATTRIBUTE Proxim_E1_TrunkID_03 12 integer
+ATTRIBUTE Proxim_E1_TrunkID_04 13 integer
+ATTRIBUTE Proxim_E1_TrunkID_05 14 integer
+ATTRIBUTE Proxim_E1_TrunkID_06 15 integer
+ATTRIBUTE Proxim_E1_TrunkID_07 16 integer
+ATTRIBUTE Proxim_E1_TrunkID_08 17 integer
+ATTRIBUTE Proxim_E1_TrunkID_09 18 integer
+ATTRIBUTE Proxim_E1_TrunkID_10 19 integer
+ATTRIBUTE Proxim_E1_TrunkID_11 20 integer
+ATTRIBUTE Proxim_E1_TrunkID_12 21 integer
+ATTRIBUTE Proxim_E1_TrunkID_13 22 integer
+ATTRIBUTE Proxim_E1_TrunkID_14 23 integer
+ATTRIBUTE Proxim_E1_TrunkID_15 24 integer
+ATTRIBUTE Proxim_E1_TrunkID_16 25 integer
+
+ATTRIBUTE Proxim_SU_VLAN_Table_Status 26 integer
+
+ATTRIBUTE Proxim_Service_VLAN_ID 32 integer
+ATTRIBUTE Proxim_Service_VLAN_Pri 33 integer
+
+# QoS Attributes
+ATTRIBUTE Proxim_QoS_Class_Index 34 integer
+ATTRIBUTE Proxim_QoS_Class_SU_Status 35 integer
+
+# The attributes listed above are applicable to Tsunami MP/QB 8XXX
+# series and MP.11/QB.11 series products. While, the attributes listed
+# below are applicable to Tsunami MP/QB 8XXX series products only.
+
+# SU Ethernet 2 VLAN parameters
+ATTRIBUTE Proxim_E2_VLAN_MODE 40 integer
+
+ATTRIBUTE Proxim_E2_Access_VLAN_ID 41 integer
+ATTRIBUTE Proxim_E2_Access_VLAN_Pri 42 integer
+
+ATTRIBUTE Proxim_E2_TrunkID_01 43 integer
+ATTRIBUTE Proxim_E2_TrunkID_02 44 integer
+ATTRIBUTE Proxim_E2_TrunkID_03 45 integer
+ATTRIBUTE Proxim_E2_TrunkID_04 46 integer
+ATTRIBUTE Proxim_E2_TrunkID_05 47 integer
+ATTRIBUTE Proxim_E2_TrunkID_06 48 integer
+ATTRIBUTE Proxim_E2_TrunkID_07 49 integer
+ATTRIBUTE Proxim_E2_TrunkID_08 50 integer
+ATTRIBUTE Proxim_E2_TrunkID_09 51 integer
+ATTRIBUTE Proxim_E2_TrunkID_10 52 integer
+ATTRIBUTE Proxim_E2_TrunkID_11 53 integer
+ATTRIBUTE Proxim_E2_TrunkID_12 54 integer
+ATTRIBUTE Proxim_E2_TrunkID_13 55 integer
+ATTRIBUTE Proxim_E2_TrunkID_14 56 integer
+ATTRIBUTE Proxim_E2_TrunkID_15 57 integer
+ATTRIBUTE Proxim_E2_TrunkID_16 58 integer
+
+# QinQ VLAN Attributes
+ATTRIBUTE Proxim_QinQ_Status 59 integer
+ATTRIBUTE Proxim_Service_VLAN_TPID 60 integer
+
+# Trunk mode Port VLAN ID
+ATTRIBUTE Proxim_E1_Port_VLAN_ID 61 integer
+ATTRIBUTE Proxim_E1_Port_VLAN_Pri 62 integer
+ATTRIBUTE Proxim_E1_Allow_Untag 63 integer
+
+ATTRIBUTE Proxim_E2_Port_VLAN_ID 64 integer
+ATTRIBUTE Proxim_E2_Port_VLAN_Pri 65 integer
+ATTRIBUTE Proxim_E2_Allow_Untag 66 integer
+
+# Access Mode Allow untagged traffic
+ATTRIBUTE Proxim_E1_SU_Allow_Untag_Mgmt 68 integer
+ATTRIBUTE Proxim_E2_SU_Allow_Untag_Mgmt 69 integer
+
+END-VENDOR Proxim
diff --git a/share/dictionary.purewave b/share/dictionary.purewave
new file mode 100644
index 0000000..7944e82
--- /dev/null
+++ b/share/dictionary.purewave
@@ -0,0 +1,53 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Purewave Networks Base Station
+#
+# $Id$
+#
+VENDOR Purewave 21074
+
+BEGIN-VENDOR Purewave
+
+ATTRIBUTE Purewave-Client-Profile 1 integer
+
+ATTRIBUTE Purewave-CS-Type 2 integer
+ATTRIBUTE Purewave-Max-Downlink-Rate 3 integer
+ATTRIBUTE Purewave-Max-Uplink-Rate 4 integer
+
+# the following two attributes are needed when cs-Type is IPV4_CS
+#
+ATTRIBUTE Purewave-IP-Address 5 ipaddr
+ATTRIBUTE Purewave-IP-Netmask 6 ipaddr
+
+#
+# Attribute Purewave-Service-Enable (optional parameter)
+# Purpose Enable or Disable service
+# Range 0-1
+# Default value 1
+#
+ATTRIBUTE Purewave-Service-Enable 7 integer
+
+VALUE Purewave-CS-Type ETHERNET_CS 1
+VALUE Purewave-CS-Type IPV4_CS 0
+
+VALUE Purewave-Max-Downlink-Rate QPSK_1/2 3
+VALUE Purewave-Max-Downlink-Rate QPSK_3/4 4
+VALUE Purewave-Max-Downlink-Rate QAM16_1/2 5
+VALUE Purewave-Max-Downlink-Rate QAM16_3/4 6
+VALUE Purewave-Max-Downlink-Rate QAM64_1/2 7
+VALUE Purewave-Max-Downlink-Rate QAM64_2/3 8
+VALUE Purewave-Max-Downlink-Rate QAM64_3/4 9
+VALUE Purewave-Max-Downlink-Rate QAM64_5/6 10
+
+VALUE Purewave-Max-Uplink-Rate QPSK_1/2 3
+VALUE Purewave-Max-Uplink-Rate QPSK_3/4 4
+VALUE Purewave-Max-Uplink-Rate QAM16_1/2 5
+VALUE Purewave-Max-Uplink-Rate QAM16_3/4 6
+VALUE Purewave-Max-Uplink-Rate QAM64_1/2 7
+VALUE Purewave-Max-Uplink-Rate QAM64_2/3 8
+VALUE Purewave-Max-Uplink-Rate QAM64_3/4 9
+VALUE Purewave-Max-Uplink-Rate QAM64_5/6 10
+
+END-VENDOR Purewave
diff --git a/share/dictionary.quiconnect b/share/dictionary.quiconnect
new file mode 100644
index 0000000..5504cc2
--- /dev/null
+++ b/share/dictionary.quiconnect
@@ -0,0 +1,21 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Quiconnect VSA's.
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR Quiconnect 14436
+
+BEGIN-VENDOR Quiconnect
+
+ATTRIBUTE Quiconnect-AVPair 1 string
+ATTRIBUTE Quiconnect-VNP-Information 2 string
+ATTRIBUTE Quiconnect-HSP-Information 3 string
+
+END-VENDOR Quiconnect
diff --git a/share/dictionary.quintum b/share/dictionary.quintum
new file mode 100644
index 0000000..1750645
--- /dev/null
+++ b/share/dictionary.quintum
@@ -0,0 +1,52 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# dictionary.quintum
+#
+# Copied mostly from the Cisco dictionary, by
+# Jeremy McNamara <jj@indie.org>
+#
+# Version: $Id$
+#
+
+VENDOR Quintum 6618
+
+#
+# Standard attribute
+#
+BEGIN-VENDOR Quintum
+
+ATTRIBUTE Quintum-AVPair 1 string
+ATTRIBUTE Quintum-NAS-Port 2 string
+
+#
+# Voice over IP attributes.
+#
+ATTRIBUTE Quintum-h323-remote-address 23 string
+ATTRIBUTE Quintum-h323-conf-id 24 string
+ATTRIBUTE Quintum-h323-setup-time 25 string
+ATTRIBUTE Quintum-h323-call-origin 26 string
+ATTRIBUTE Quintum-h323-call-type 27 string
+ATTRIBUTE Quintum-h323-connect-time 28 string
+ATTRIBUTE Quintum-h323-disconnect-time 29 string
+ATTRIBUTE Quintum-h323-disconnect-cause 30 string
+ATTRIBUTE Quintum-h323-voice-quality 31 string
+ATTRIBUTE Quintum-h323-gw-id 33 string
+ATTRIBUTE Quintum-h323-incoming-conf-id 35 string
+
+ATTRIBUTE Quintum-h323-credit-amount 101 string
+ATTRIBUTE Quintum-h323-credit-time 102 string
+ATTRIBUTE Quintum-h323-return-code 103 string
+ATTRIBUTE Quintum-h323-prompt-id 104 string
+ATTRIBUTE Quintum-h323-time-and-day 105 string
+ATTRIBUTE Quintum-h323-redirect-number 106 string
+ATTRIBUTE Quintum-h323-preferred-lang 107 string
+ATTRIBUTE Quintum-h323-redirect-ip-address 108 string
+ATTRIBUTE Quintum-h323-billing-model 109 string
+ATTRIBUTE Quintum-h323-currency-type 110 string
+
+ATTRIBUTE Quintum-Trunkid-In 230 string
+ATTRIBUTE Quintum-Trunkid-Out 231 string
+
+END-VENDOR Quintum
diff --git a/share/dictionary.rcntec b/share/dictionary.rcntec
new file mode 100644
index 0000000..a1cdae1
--- /dev/null
+++ b/share/dictionary.rcntec
@@ -0,0 +1,19 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+# Version $Id$
+###########################################################
+# Resilient Cloud Network Technologies (RCNTEC)
+# Dictionary for RCNTEC's RPCM hardware, https://rpcm.pro
+# Contributed by Sergey Minakov <ser@rcntec.com>
+#
+#
+###########################################################
+
+VENDOR RCNTEC 46235
+BEGIN-VENDOR RCNTEC
+
+ATTRIBUTE RCNTEC-RPCM-Group 1 string
+ATTRIBUTE RCNTEC-RPCM-Session-Expire 2 integer
+
+END-VENDOR RCNTEC
diff --git a/share/dictionary.redcreek b/share/dictionary.redcreek
new file mode 100644
index 0000000..d8a5f86
--- /dev/null
+++ b/share/dictionary.redcreek
@@ -0,0 +1,23 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# http://www.redcreek.com
+# $Id$
+#
+
+VENDOR RedCreek 1958
+
+BEGIN-VENDOR RedCreek
+
+ATTRIBUTE RedCreek-Tunneled-IP-Addr 5 ipaddr
+ATTRIBUTE RedCreek-Tunneled-IP-Netmask 6 ipaddr
+ATTRIBUTE RedCreek-Tunneled-Gateway 7 ipaddr
+ATTRIBUTE RedCreek-Tunneled-DNS-Server 8 string
+ATTRIBUTE RedCreek-Tunneled-WINS-Server1 9 string
+ATTRIBUTE RedCreek-Tunneled-WINS-Server2 10 string
+ATTRIBUTE RedCreek-Tunneled-HostName 11 string
+ATTRIBUTE RedCreek-Tunneled-DomainName 12 string
+ATTRIBUTE RedCreek-Tunneled-Search-List 13 string
+
+END-VENDOR RedCreek
diff --git a/share/dictionary.rfc2865 b/share/dictionary.rfc2865
new file mode 100644
index 0000000..6e2319a
--- /dev/null
+++ b/share/dictionary.rfc2865
@@ -0,0 +1,139 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Attributes and values defined in RFC 2865.
+# http://www.ietf.org/rfc/rfc2865.txt
+#
+# $Id$
+#
+ATTRIBUTE User-Name 1 string
+ATTRIBUTE User-Password 2 string encrypt=1
+ATTRIBUTE CHAP-Password 3 octets
+ATTRIBUTE NAS-IP-Address 4 ipaddr
+ATTRIBUTE NAS-Port 5 integer
+ATTRIBUTE Service-Type 6 integer
+ATTRIBUTE Framed-Protocol 7 integer
+ATTRIBUTE Framed-IP-Address 8 ipaddr
+ATTRIBUTE Framed-IP-Netmask 9 ipaddr
+ATTRIBUTE Framed-Routing 10 integer
+ATTRIBUTE Filter-Id 11 string
+ATTRIBUTE Framed-MTU 12 integer
+ATTRIBUTE Framed-Compression 13 integer
+ATTRIBUTE Login-IP-Host 14 ipaddr
+ATTRIBUTE Login-Service 15 integer
+ATTRIBUTE Login-TCP-Port 16 integer
+# Attribute 17 is undefined
+ATTRIBUTE Reply-Message 18 string
+ATTRIBUTE Callback-Number 19 string
+ATTRIBUTE Callback-Id 20 string
+# Attribute 21 is undefined
+ATTRIBUTE Framed-Route 22 string
+ATTRIBUTE Framed-IPX-Network 23 ipaddr
+ATTRIBUTE State 24 octets
+ATTRIBUTE Class 25 octets
+ATTRIBUTE Vendor-Specific 26 vsa
+ATTRIBUTE Session-Timeout 27 integer
+ATTRIBUTE Idle-Timeout 28 integer
+ATTRIBUTE Termination-Action 29 integer
+ATTRIBUTE Called-Station-Id 30 string
+ATTRIBUTE Calling-Station-Id 31 string
+ATTRIBUTE NAS-Identifier 32 string
+ATTRIBUTE Proxy-State 33 octets
+ATTRIBUTE Login-LAT-Service 34 string
+ATTRIBUTE Login-LAT-Node 35 string
+ATTRIBUTE Login-LAT-Group 36 octets
+ATTRIBUTE Framed-AppleTalk-Link 37 integer
+ATTRIBUTE Framed-AppleTalk-Network 38 integer
+ATTRIBUTE Framed-AppleTalk-Zone 39 string
+
+ATTRIBUTE CHAP-Challenge 60 octets
+ATTRIBUTE NAS-Port-Type 61 integer
+ATTRIBUTE Port-Limit 62 integer
+ATTRIBUTE Login-LAT-Port 63 string
+
+#
+# Integer Translations
+#
+
+# Service types
+
+VALUE Service-Type Login-User 1
+VALUE Service-Type Framed-User 2
+VALUE Service-Type Callback-Login-User 3
+VALUE Service-Type Callback-Framed-User 4
+VALUE Service-Type Outbound-User 5
+VALUE Service-Type Administrative-User 6
+VALUE Service-Type NAS-Prompt-User 7
+VALUE Service-Type Authenticate-Only 8
+VALUE Service-Type Callback-NAS-Prompt 9
+VALUE Service-Type Call-Check 10
+VALUE Service-Type Callback-Administrative 11
+
+# Framed Protocols
+
+VALUE Framed-Protocol PPP 1
+VALUE Framed-Protocol SLIP 2
+VALUE Framed-Protocol ARAP 3
+VALUE Framed-Protocol Gandalf-SLML 4
+VALUE Framed-Protocol Xylogics-IPX-SLIP 5
+VALUE Framed-Protocol X.75-Synchronous 6
+
+# Framed Routing Values
+
+VALUE Framed-Routing None 0
+VALUE Framed-Routing Broadcast 1
+VALUE Framed-Routing Listen 2
+VALUE Framed-Routing Broadcast-Listen 3
+
+# Framed Compression Types
+
+VALUE Framed-Compression None 0
+VALUE Framed-Compression Van-Jacobson-TCP-IP 1
+VALUE Framed-Compression IPX-Header-Compression 2
+VALUE Framed-Compression Stac-LZS 3
+
+# Login Services
+
+VALUE Login-Service Telnet 0
+VALUE Login-Service Rlogin 1
+VALUE Login-Service TCP-Clear 2
+VALUE Login-Service PortMaster 3
+VALUE Login-Service LAT 4
+VALUE Login-Service X25-PAD 5
+VALUE Login-Service X25-T3POS 6
+VALUE Login-Service TCP-Clear-Quiet 8
+
+# Login-TCP-Port (see /etc/services for more examples)
+
+VALUE Login-TCP-Port Telnet 23
+VALUE Login-TCP-Port Rlogin 513
+VALUE Login-TCP-Port Rsh 514
+
+# Termination Options
+
+VALUE Termination-Action Default 0
+VALUE Termination-Action RADIUS-Request 1
+
+# NAS Port Types
+
+VALUE NAS-Port-Type Async 0
+VALUE NAS-Port-Type Sync 1
+VALUE NAS-Port-Type ISDN 2
+VALUE NAS-Port-Type ISDN-V120 3
+VALUE NAS-Port-Type ISDN-V110 4
+VALUE NAS-Port-Type Virtual 5
+VALUE NAS-Port-Type PIAFS 6
+VALUE NAS-Port-Type HDLC-Clear-Channel 7
+VALUE NAS-Port-Type X.25 8
+VALUE NAS-Port-Type X.75 9
+VALUE NAS-Port-Type G.3-Fax 10
+VALUE NAS-Port-Type SDSL 11
+VALUE NAS-Port-Type ADSL-CAP 12
+VALUE NAS-Port-Type ADSL-DMT 13
+VALUE NAS-Port-Type IDSL 14
+VALUE NAS-Port-Type Ethernet 15
+VALUE NAS-Port-Type xDSL 16
+VALUE NAS-Port-Type Cable 17
+VALUE NAS-Port-Type Wireless-Other 18
+VALUE NAS-Port-Type Wireless-802.11 19
diff --git a/share/dictionary.rfc2866 b/share/dictionary.rfc2866
new file mode 100644
index 0000000..4b6bda4
--- /dev/null
+++ b/share/dictionary.rfc2866
@@ -0,0 +1,59 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors#
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Attributes and values defined in RFC 2866.
+# http://www.ietf.org/rfc/rfc2866.txt
+#
+# $Id$
+#
+ATTRIBUTE Acct-Status-Type 40 integer
+ATTRIBUTE Acct-Delay-Time 41 integer
+ATTRIBUTE Acct-Input-Octets 42 integer
+ATTRIBUTE Acct-Output-Octets 43 integer
+ATTRIBUTE Acct-Session-Id 44 string
+ATTRIBUTE Acct-Authentic 45 integer
+ATTRIBUTE Acct-Session-Time 46 integer
+ATTRIBUTE Acct-Input-Packets 47 integer
+ATTRIBUTE Acct-Output-Packets 48 integer
+ATTRIBUTE Acct-Terminate-Cause 49 integer
+ATTRIBUTE Acct-Multi-Session-Id 50 string
+ATTRIBUTE Acct-Link-Count 51 integer
+
+# Accounting Status Types
+
+VALUE Acct-Status-Type Start 1
+VALUE Acct-Status-Type Stop 2
+VALUE Acct-Status-Type Alive 3 # dup
+VALUE Acct-Status-Type Interim-Update 3
+VALUE Acct-Status-Type Accounting-On 7
+VALUE Acct-Status-Type Accounting-Off 8
+VALUE Acct-Status-Type Failed 15
+
+# Authentication Types
+
+VALUE Acct-Authentic RADIUS 1
+VALUE Acct-Authentic Local 2
+VALUE Acct-Authentic Remote 3
+VALUE Acct-Authentic Diameter 4
+
+# Acct Terminate Causes
+
+VALUE Acct-Terminate-Cause User-Request 1
+VALUE Acct-Terminate-Cause Lost-Carrier 2
+VALUE Acct-Terminate-Cause Lost-Service 3
+VALUE Acct-Terminate-Cause Idle-Timeout 4
+VALUE Acct-Terminate-Cause Session-Timeout 5
+VALUE Acct-Terminate-Cause Admin-Reset 6
+VALUE Acct-Terminate-Cause Admin-Reboot 7
+VALUE Acct-Terminate-Cause Port-Error 8
+VALUE Acct-Terminate-Cause NAS-Error 9
+VALUE Acct-Terminate-Cause NAS-Request 10
+VALUE Acct-Terminate-Cause NAS-Reboot 11
+VALUE Acct-Terminate-Cause Port-Unneeded 12
+VALUE Acct-Terminate-Cause Port-Preempted 13
+VALUE Acct-Terminate-Cause Port-Suspended 14
+VALUE Acct-Terminate-Cause Service-Unavailable 15
+VALUE Acct-Terminate-Cause Callback 16
+VALUE Acct-Terminate-Cause User-Error 17
+VALUE Acct-Terminate-Cause Host-Request 18
diff --git a/share/dictionary.rfc2867 b/share/dictionary.rfc2867
new file mode 100644
index 0000000..821f860
--- /dev/null
+++ b/share/dictionary.rfc2867
@@ -0,0 +1,18 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Attributes and values defined in RFC 2867.
+# http://www.ietf.org/rfc/rfc2867.txt
+#
+# $Id$
+#
+ATTRIBUTE Acct-Tunnel-Connection 68 string
+ATTRIBUTE Acct-Tunnel-Packets-Lost 86 integer
+
+VALUE Acct-Status-Type Tunnel-Start 9
+VALUE Acct-Status-Type Tunnel-Stop 10
+VALUE Acct-Status-Type Tunnel-Reject 11
+VALUE Acct-Status-Type Tunnel-Link-Start 12
+VALUE Acct-Status-Type Tunnel-Link-Stop 13
+VALUE Acct-Status-Type Tunnel-Link-Reject 14
diff --git a/share/dictionary.rfc2868 b/share/dictionary.rfc2868
new file mode 100644
index 0000000..8535eef
--- /dev/null
+++ b/share/dictionary.rfc2868
@@ -0,0 +1,56 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Attributes and values defined in RFC 2868.
+# http://www.ietf.org/rfc/rfc2868.txt
+#
+# $Id$
+#
+ATTRIBUTE Tunnel-Type 64 integer has_tag
+ATTRIBUTE Tunnel-Medium-Type 65 integer has_tag
+ATTRIBUTE Tunnel-Client-Endpoint 66 string has_tag
+ATTRIBUTE Tunnel-Server-Endpoint 67 string has_tag
+
+ATTRIBUTE Tunnel-Password 69 string has_tag,encrypt=2
+
+ATTRIBUTE Tunnel-Private-Group-Id 81 string has_tag
+ATTRIBUTE Tunnel-Assignment-Id 82 string has_tag
+ATTRIBUTE Tunnel-Preference 83 integer has_tag
+
+ATTRIBUTE Tunnel-Client-Auth-Id 90 string has_tag
+ATTRIBUTE Tunnel-Server-Auth-Id 91 string has_tag
+
+# Tunnel Type
+
+VALUE Tunnel-Type PPTP 1
+VALUE Tunnel-Type L2F 2
+VALUE Tunnel-Type L2TP 3
+VALUE Tunnel-Type ATMP 4
+VALUE Tunnel-Type VTP 5
+VALUE Tunnel-Type AH 6
+VALUE Tunnel-Type IP 7
+VALUE Tunnel-Type MIN-IP 8
+VALUE Tunnel-Type ESP 9
+VALUE Tunnel-Type GRE 10
+VALUE Tunnel-Type DVS 11
+VALUE Tunnel-Type IP-in-IP 12
+
+# Tunnel Medium Type
+
+VALUE Tunnel-Medium-Type IP 1
+VALUE Tunnel-Medium-Type IPv4 1
+VALUE Tunnel-Medium-Type IPv6 2
+VALUE Tunnel-Medium-Type NSAP 3
+VALUE Tunnel-Medium-Type HDLC 4
+VALUE Tunnel-Medium-Type BBN-1822 5
+VALUE Tunnel-Medium-Type IEEE-802 6
+VALUE Tunnel-Medium-Type E.163 7
+VALUE Tunnel-Medium-Type E.164 8
+VALUE Tunnel-Medium-Type F.69 9
+VALUE Tunnel-Medium-Type X.121 10
+VALUE Tunnel-Medium-Type IPX 11
+VALUE Tunnel-Medium-Type Appletalk 12
+VALUE Tunnel-Medium-Type DecNet-IV 13
+VALUE Tunnel-Medium-Type Banyan-Vines 14
+VALUE Tunnel-Medium-Type E.164-NSAP 15
diff --git a/share/dictionary.rfc2869 b/share/dictionary.rfc2869
new file mode 100644
index 0000000..4dd40fe
--- /dev/null
+++ b/share/dictionary.rfc2869
@@ -0,0 +1,41 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Attributes and values defined in RFC 2869.
+# http://www.ietf.org/rfc/rfc2869.txt
+#
+# $Id$
+#
+ATTRIBUTE Acct-Input-Gigawords 52 integer
+ATTRIBUTE Acct-Output-Gigawords 53 integer
+
+ATTRIBUTE Event-Timestamp 55 date
+
+ATTRIBUTE ARAP-Password 70 octets[16]
+ATTRIBUTE ARAP-Features 71 octets[14]
+ATTRIBUTE ARAP-Zone-Access 72 integer
+ATTRIBUTE ARAP-Security 73 integer
+ATTRIBUTE ARAP-Security-Data 74 string
+ATTRIBUTE Password-Retry 75 integer
+ATTRIBUTE Prompt 76 integer
+ATTRIBUTE Connect-Info 77 string
+ATTRIBUTE Configuration-Token 78 string
+ATTRIBUTE EAP-Message 79 octets concat
+ATTRIBUTE Message-Authenticator 80 octets
+
+ATTRIBUTE ARAP-Challenge-Response 84 octets[8]
+ATTRIBUTE Acct-Interim-Interval 85 integer
+# 86: RFC 2867
+ATTRIBUTE NAS-Port-Id 87 string
+ATTRIBUTE Framed-Pool 88 string
+
+# ARAP Zone Access
+
+VALUE ARAP-Zone-Access Default-Zone 1
+VALUE ARAP-Zone-Access Zone-Filter-Inclusive 2
+VALUE ARAP-Zone-Access Zone-Filter-Exclusive 4
+
+# Prompt
+VALUE Prompt No-Echo 0
+VALUE Prompt Echo 1
diff --git a/share/dictionary.rfc3162 b/share/dictionary.rfc3162
new file mode 100644
index 0000000..e90e387
--- /dev/null
+++ b/share/dictionary.rfc3162
@@ -0,0 +1,15 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Attributes and values defined in RFC 3162.
+# http://www.ietf.org/rfc/rfc3162.txt
+#
+# $Id$
+#
+ATTRIBUTE NAS-IPv6-Address 95 ipv6addr
+ATTRIBUTE Framed-Interface-Id 96 ifid
+ATTRIBUTE Framed-IPv6-Prefix 97 ipv6prefix
+ATTRIBUTE Login-IPv6-Host 98 ipv6addr
+ATTRIBUTE Framed-IPv6-Route 99 string
+ATTRIBUTE Framed-IPv6-Pool 100 string
diff --git a/share/dictionary.rfc3576 b/share/dictionary.rfc3576
new file mode 100644
index 0000000..9ad0920
--- /dev/null
+++ b/share/dictionary.rfc3576
@@ -0,0 +1,32 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Attributes and values defined in RFC 3576.
+# http://www.ietf.org/rfc/rfc3576.txt
+#
+# $Id$
+#
+ATTRIBUTE Error-Cause 101 integer
+
+# Service Types
+
+VALUE Service-Type Authorize-Only 17
+
+# Error causes
+
+VALUE Error-Cause Residual-Context-Removed 201
+VALUE Error-Cause Invalid-EAP-Packet 202
+VALUE Error-Cause Unsupported-Attribute 401
+VALUE Error-Cause Missing-Attribute 402
+VALUE Error-Cause NAS-Identification-Mismatch 403
+VALUE Error-Cause Invalid-Request 404
+VALUE Error-Cause Unsupported-Service 405
+VALUE Error-Cause Unsupported-Extension 406
+VALUE Error-Cause Administratively-Prohibited 501
+VALUE Error-Cause Proxy-Request-Not-Routable 502
+VALUE Error-Cause Session-Context-Not-Found 503
+VALUE Error-Cause Session-Context-Not-Removable 504
+VALUE Error-Cause Proxy-Processing-Error 505
+VALUE Error-Cause Resources-Unavailable 506
+VALUE Error-Cause Request-Initiated 507
diff --git a/share/dictionary.rfc3580 b/share/dictionary.rfc3580
new file mode 100644
index 0000000..2340768
--- /dev/null
+++ b/share/dictionary.rfc3580
@@ -0,0 +1,18 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Attributes and values defined in RFC 3580.
+# http://www.ietf.org/rfc/rfc3580.txt
+#
+# $Id$
+#
+VALUE Acct-Terminate-Cause Supplicant-Restart 19
+VALUE Acct-Terminate-Cause Reauthentication-Failure 20
+VALUE Acct-Terminate-Cause Port-Reinit 21
+VALUE Acct-Terminate-Cause Port-Disabled 22
+
+VALUE NAS-Port-Type Token-Ring 20
+VALUE NAS-Port-Type FDDI 21
+
+VALUE Tunnel-Type VLAN 13
diff --git a/share/dictionary.rfc4072 b/share/dictionary.rfc4072
new file mode 100644
index 0000000..3bb543f
--- /dev/null
+++ b/share/dictionary.rfc4072
@@ -0,0 +1,11 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Attributes and values defined in RFC 4072
+# http://www.ietf.org/rfc/rfc4072.txt
+#
+# $Id$
+#
+
+ATTRIBUTE EAP-Key-Name 102 octets
diff --git a/share/dictionary.rfc4372 b/share/dictionary.rfc4372
new file mode 100644
index 0000000..c7a4ea3
--- /dev/null
+++ b/share/dictionary.rfc4372
@@ -0,0 +1,10 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Attributes and values defined in RFC 4372.
+# http://www.ietf.org/rfc/rfc4372.txt
+#
+# $Id$
+#
+ATTRIBUTE Chargeable-User-Identity 89 octets
diff --git a/share/dictionary.rfc4603 b/share/dictionary.rfc4603
new file mode 100644
index 0000000..f7ab495
--- /dev/null
+++ b/share/dictionary.rfc4603
@@ -0,0 +1,19 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Attributes and values defined in RFC 4603.
+# http://www.ietf.org/rfc/rfc4603.txt
+#
+# $Id$
+#
+##############################################################################
+
+VALUE NAS-Port-Type PPPoA 30
+VALUE NAS-Port-Type PPPoEoA 31
+VALUE NAS-Port-Type PPPoEoE 32
+VALUE NAS-Port-Type PPPoEoVLAN 33
+VALUE NAS-Port-Type PPPoEoQinQ 34
+
diff --git a/share/dictionary.rfc4675 b/share/dictionary.rfc4675
new file mode 100644
index 0000000..6c3b64d
--- /dev/null
+++ b/share/dictionary.rfc4675
@@ -0,0 +1,30 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Attributes and values defined in RFC 4675.
+# http://www.ietf.org/rfc/rfc4675.txt
+#
+# $Id$
+#
+
+#
+# High byte = '1' (0x31) means the frames are tagged.
+# High byte = '2' (0x32) means the frames are untagged.
+#
+# Next 12 bits MUST be zero.
+#
+# Lower 12 bits is the IEEE-802.1Q VLAN VID.
+#
+ATTRIBUTE Egress-VLANID 56 integer
+ATTRIBUTE Ingress-Filters 57 integer
+
+#
+# First byte == '1' (0x31) means that the frames are tagged.
+# First byte == '2' (0x32) means that the frames are untagged.
+#
+ATTRIBUTE Egress-VLAN-Name 58 string
+ATTRIBUTE User-Priority-Table 59 octets # 8
+
+VALUE Ingress-Filters Enabled 1
+VALUE Ingress-Filters Disabled 2
diff --git a/share/dictionary.rfc4679 b/share/dictionary.rfc4679
new file mode 100644
index 0000000..86d7f27
--- /dev/null
+++ b/share/dictionary.rfc4679
@@ -0,0 +1,74 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Attributes and values defined in RFC 4679.
+# http://www.ietf.org/rfc/rfc4679.txt
+#
+# $Id$
+#
+
+VENDOR ADSL-Forum 3561
+
+BEGIN-VENDOR ADSL-Forum
+
+#
+# Glue attribute to allow decoding of ADSL-Form vendor specific
+# DHCP options.
+#
+ATTRIBUTE ADSL-Forum-DHCP-Vendor-Specific 255 tlv
+ATTRIBUTE ADSL-Forum-Device-Manufacturer-OUI 255.1 octets
+ATTRIBUTE ADSL-Forum-Device-Serial-Number 255.2 string
+ATTRIBUTE ADSL-Forum-Device-Product-Class 255.3 string
+ATTRIBUTE ADSL-Forum-Gateway-Manufacturer-OUI 255.4 octets
+
+#
+# The first two attributes are prefixed with "ADSL-" because of
+# conflicting names in dictionary.redback.
+#
+ATTRIBUTE ADSL-Agent-Circuit-Id 1 octets
+ATTRIBUTE ADSL-Agent-Remote-Id 2 octets
+ATTRIBUTE Actual-Data-Rate-Upstream 129 integer
+ATTRIBUTE Actual-Data-Rate-Downstream 130 integer
+ATTRIBUTE Minimum-Data-Rate-Upstream 131 integer
+ATTRIBUTE Minimum-Data-Rate-Downstream 132 integer
+ATTRIBUTE Attainable-Data-Rate-Upstream 133 integer
+ATTRIBUTE Attainable-Data-Rate-Downstream 134 integer
+ATTRIBUTE Maximum-Data-Rate-Upstream 135 integer
+ATTRIBUTE Maximum-Data-Rate-Downstream 136 integer
+ATTRIBUTE Minimum-Data-Rate-Upstream-Low-Power 137 integer
+ATTRIBUTE Minimum-Data-Rate-Downstream-Low-Power 138 integer
+ATTRIBUTE Maximum-Interleaving-Delay-Upstream 139 integer
+ATTRIBUTE Actual-Interleaving-Delay-Upstream 140 integer
+ATTRIBUTE Maximum-Interleaving-Delay-Downstream 141 integer
+ATTRIBUTE Actual-Interleaving-Delay-Downstream 142 integer
+
+#
+# This next attribute has a weird encoding.
+#
+# Octet[0] - 0x01 AAL5
+# Octet[0] - 0x02 Ethernet
+
+# Octet[1] - 0x00 Not Available
+# Octet[1] - 0x01 Untagged Ethernet
+# Octet[1] - 0x02 Single-Tagged Ethernet
+
+# Octet[2] - 0x00 Not available
+# Octet[2] - 0x01 PPPoA LLC
+# Octet[2] - 0x02 PPPoA Null
+# Octet[2] - 0x03 IPoA LLC
+# Octet[2] - 0x04 IPoA NULL
+# Octet[2] - 0x05 Ethernet over AAL5 LLC with FCS
+# Octet[2] - 0x06 Ethernet over AAL5 LLC without FCS
+# Octet[2] - 0x07 Ethernet over AAL5 Null with FCS
+# Octet[2] - 0x08 Ethernet over AAL5 Null without FCS
+#
+ATTRIBUTE Access-Loop-Encapsulation 144 octets # 3
+
+#
+# If this attribute exists, it means that IFW has been performed
+# for the subscribers session.
+#
+ATTRIBUTE IWF-Session 254 octets # 0
+
+END-VENDOR ADSL-Forum
diff --git a/share/dictionary.rfc4818 b/share/dictionary.rfc4818
new file mode 100644
index 0000000..cc56252
--- /dev/null
+++ b/share/dictionary.rfc4818
@@ -0,0 +1,14 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Attributes and values defined in RFC 4818.
+# http://www.ietf.org/rfc/rfc4818.txt
+#
+# $Id$
+#
+##############################################################################
+
+ATTRIBUTE Delegated-IPv6-Prefix 123 ipv6prefix
diff --git a/share/dictionary.rfc4849 b/share/dictionary.rfc4849
new file mode 100644
index 0000000..3ddb0ef
--- /dev/null
+++ b/share/dictionary.rfc4849
@@ -0,0 +1,10 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Attributes and values defined in RFC 4849.
+# http://www.ietf.org/rfc/rfc4849.txt
+#
+# $Id$
+#
+ATTRIBUTE NAS-Filter-Rule 92 string
diff --git a/share/dictionary.rfc5090 b/share/dictionary.rfc5090
new file mode 100644
index 0000000..2531b26
--- /dev/null
+++ b/share/dictionary.rfc5090
@@ -0,0 +1,29 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Attributes and values defined in RFC 5090.
+# http://www.ietf.org/rfc/rfc5090.txt
+#
+# $Id$
+#
+ATTRIBUTE Digest-Response 103 string
+ATTRIBUTE Digest-Realm 104 string
+ATTRIBUTE Digest-Nonce 105 string
+ATTRIBUTE Digest-Response-Auth 106 string
+ATTRIBUTE Digest-Nextnonce 107 string
+ATTRIBUTE Digest-Method 108 string
+ATTRIBUTE Digest-URI 109 string
+ATTRIBUTE Digest-Qop 110 string
+ATTRIBUTE Digest-Algorithm 111 string
+ATTRIBUTE Digest-Entity-Body-Hash 112 string
+ATTRIBUTE Digest-CNonce 113 string
+ATTRIBUTE Digest-Nonce-Count 114 string
+ATTRIBUTE Digest-Username 115 string
+ATTRIBUTE Digest-Opaque 116 string
+ATTRIBUTE Digest-Auth-Param 117 string
+ATTRIBUTE Digest-AKA-Auts 118 string
+ATTRIBUTE Digest-Domain 119 string
+ATTRIBUTE Digest-Stale 120 string
+ATTRIBUTE Digest-HA1 121 string
+ATTRIBUTE SIP-AOR 122 string
diff --git a/share/dictionary.rfc5176 b/share/dictionary.rfc5176
new file mode 100644
index 0000000..118fa07
--- /dev/null
+++ b/share/dictionary.rfc5176
@@ -0,0 +1,11 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Attributes and values defined in RFC 5176.
+# http://www.ietf.org/rfc/rfc5176.txt
+#
+# $Id$
+#
+VALUE Error-Cause Invalid-Attribute-Value 407
+VALUE Error-Cause Multiple-Session-Selection-Unsupported 508
diff --git a/share/dictionary.rfc5447 b/share/dictionary.rfc5447
new file mode 100644
index 0000000..f54758a
--- /dev/null
+++ b/share/dictionary.rfc5447
@@ -0,0 +1,17 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Attributes and values defined in RFC 5447.
+# http://www.ietf.org/rfc/rfc5447.txt
+#
+# $Id$
+#
+
+# 64-bit bit field
+ATTRIBUTE MIP6-Feature-Vector 124 integer64
+
+#
+# Encoded as one octet prefix, followed by 16 octets of address information.
+#
+ATTRIBUTE MIP6-Home-Link-Prefix 125 octets
diff --git a/share/dictionary.rfc5580 b/share/dictionary.rfc5580
new file mode 100644
index 0000000..07de61e
--- /dev/null
+++ b/share/dictionary.rfc5580
@@ -0,0 +1,43 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Attributes and values defined in RFC 5580.
+# http://www.ietf.org/rfc/rfc5580.txt
+#
+# $Id$
+#
+
+# One ASCII character of Namespace ID
+# 0 = TADIG (GSM)
+# 1 = Realm
+# 2 = E212
+#
+#
+# Followed by the actual string
+ATTRIBUTE Operator-Name 126 string
+
+#
+# Large blobs of stuff
+#
+ATTRIBUTE Location-Information 127 octets
+ATTRIBUTE Location-Data 128 octets
+ATTRIBUTE Basic-Location-Policy-Rules 129 octets
+ATTRIBUTE Extended-Location-Policy-Rules 130 string
+
+#
+# Really a bit-packed field
+#
+ATTRIBUTE Location-Capable 131 integer
+VALUE Location-Capable Civic-Location 1
+VALUE Location-Capable Geo-Location 2
+VALUE Location-Capable Users-Location 4
+VALUE Location-Capable NAS-Location 8
+
+ATTRIBUTE Requested-Location-Info 132 integer
+VALUE Requested-Location-Info Civic-Location 1
+VALUE Requested-Location-Info Geo-Location 2
+VALUE Requested-Location-Info Users-Location 4
+VALUE Requested-Location-Info NAS-Location 8
+VALUE Requested-Location-Info Future-Requests 16
+VALUE Requested-Location-Info None 32
diff --git a/share/dictionary.rfc5607 b/share/dictionary.rfc5607
new file mode 100644
index 0000000..ef47c5d
--- /dev/null
+++ b/share/dictionary.rfc5607
@@ -0,0 +1,32 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Attributes and values defined in RFC 5607.
+# http://www.ietf.org/rfc/rfc5607.txt
+#
+# $Id$
+#
+
+VALUE Service-Type Framed-Management 18
+
+ATTRIBUTE Framed-Management 133 integer
+
+VALUE Framed-Management SNMP 1
+VALUE Framed-Management Web-Based 2
+VALUE Framed-Management Netconf 3
+VALUE Framed-Management FTP 4
+VALUE Framed-Management TFTP 5
+VALUE Framed-Management SFTP 6
+VALUE Framed-Management RCP 7
+VALUE Framed-Management SCP 8
+
+ATTRIBUTE Management-Transport-Protection 134 integer
+
+VALUE Management-Transport-Protection No-Protection 1
+VALUE Management-Transport-Protection Integrity-Protection 2
+VALUE Management-Transport-Protection Integrity-Confidentiality-Protection 3
+
+ATTRIBUTE Management-Policy-Id 135 string
+
+ATTRIBUTE Management-Privilege-Level 136 integer
diff --git a/share/dictionary.rfc5904 b/share/dictionary.rfc5904
new file mode 100644
index 0000000..7f2cf2d
--- /dev/null
+++ b/share/dictionary.rfc5904
@@ -0,0 +1,24 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Attributes and values defined in RFC 5904.
+# http://www.ietf.org/rfc/rfc5904.txt
+#
+# $Id$
+#
+
+# The next two attributes are continued, like EAP-Message
+ATTRIBUTE PKM-SS-Cert 137 octets concat
+ATTRIBUTE PKM-CA-Cert 138 octets concat
+
+# 28 bytes of data, 7 integers
+ATTRIBUTE PKM-Config-Settings 139 octets
+ATTRIBUTE PKM-Cryptosuite-List 140 octets
+ATTRIBUTE PKM-SAID 141 short
+
+# 6 bytes of data: SAID, 1 byte of type, 3 of cryptosuite
+ATTRIBUTE PKM-SA-Descriptor 142 octets
+
+# 133 bytes of data: integer lifetime, 1 byte sequence, 128 bytes of key
+ATTRIBUTE PKM-Auth-Key 143 octets
diff --git a/share/dictionary.rfc6519 b/share/dictionary.rfc6519
new file mode 100644
index 0000000..0a0bc32
--- /dev/null
+++ b/share/dictionary.rfc6519
@@ -0,0 +1,11 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Attributes and values defined in RFC 6519.
+# http://www.ietf.org/rfc/rfc6519.txt
+#
+# $Id$
+#
+
+ATTRIBUTE DS-Lite-Tunnel-Name 144 octets
diff --git a/share/dictionary.rfc6572 b/share/dictionary.rfc6572
new file mode 100644
index 0000000..65cc95b
--- /dev/null
+++ b/share/dictionary.rfc6572
@@ -0,0 +1,28 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Attributes and values defined in RFC 6572.
+# http://www.ietf.org/rfc/rfc6572.txt
+#
+# $Id$
+#
+
+ATTRIBUTE Mobile-Node-Identifier 145 octets
+ATTRIBUTE Service-Selection 146 string
+ATTRIBUTE PMIP6-Home-LMA-IPv6-Address 147 ipv6addr
+ATTRIBUTE PMIP6-Visited-LMA-IPv6-Address 148 ipv6addr
+ATTRIBUTE PMIP6-Home-LMA-IPv4-Address 149 ipaddr
+ATTRIBUTE PMIP6-Visited-LMA-IPv4-Address 150 ipaddr
+ATTRIBUTE PMIP6-Home-HN-Prefix 151 ipv6prefix
+ATTRIBUTE PMIP6-Visited-HN-Prefix 152 ipv6prefix
+ATTRIBUTE PMIP6-Home-Interface-ID 153 ifid
+ATTRIBUTE PMIP6-Visited-Interface-ID 154 ifid
+ATTRIBUTE PMIP6-Home-IPv4-HoA 155 ipv4prefix
+ATTRIBUTE PMIP6-Visited-IPv4-HoA 156 ipv4prefix
+ATTRIBUTE PMIP6-Home-DHCP4-Server-Address 157 ipaddr
+ATTRIBUTE PMIP6-Visited-DHCP4-Server-Address 158 ipaddr
+ATTRIBUTE PMIP6-Home-DHCP6-Server-Address 159 ipv6addr
+ATTRIBUTE PMIP6-Visited-DHCP6-Server-Address 160 ipv6addr
+ATTRIBUTE PMIP6-Home-IPv4-Gateway 161 ipaddr
+ATTRIBUTE PMIP6-Visited-IPv4-Gateway 162 ipaddr
diff --git a/share/dictionary.rfc6677 b/share/dictionary.rfc6677
new file mode 100644
index 0000000..923e241
--- /dev/null
+++ b/share/dictionary.rfc6677
@@ -0,0 +1,20 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Attributes and values defined in RFC 6677
+# http://www.ietf.org/rfc/rfc6677.txt
+#
+
+ATTRIBUTE EAP-Lower-Layer 163 integer
+
+VALUE EAP-Lower-Layer Wired-IEEE-802.1X 1
+VALUE EAP-Lower-Layer IEEE-802.1X-No-Preauth 2
+VALUE EAP-Lower-Layer IEEE-802.1X-Preauth 3
+VALUE EAP-Lower-Layer IEEE-802.16e 4
+VALUE EAP-Lower-Layer IKEv2 5
+VALUE EAP-Lower-Layer PPP 6
+VALUE EAP-Lower-Layer PANA-No-Preauth 7
+VALUE EAP-Lower-Layer GSS-API 8
+VALUE EAP-Lower-Layer PANA-Preauth 9
+
diff --git a/share/dictionary.rfc6911 b/share/dictionary.rfc6911
new file mode 100644
index 0000000..ccf6aa4
--- /dev/null
+++ b/share/dictionary.rfc6911
@@ -0,0 +1,13 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Attributes and values defined in RFC 6911
+# http://www.ietf.org/rfc/rfc6911.txt
+#
+
+ATTRIBUTE Framed-IPv6-Address 168 ipv6addr
+ATTRIBUTE DNS-Server-IPv6-Address 169 ipv6addr
+ATTRIBUTE Route-IPv6-Information 170 ipv6prefix
+ATTRIBUTE Delegated-IPv6-Prefix-Pool 171 string
+ATTRIBUTE Stateful-IPv6-Address-Pool 172 string
diff --git a/share/dictionary.rfc6929 b/share/dictionary.rfc6929
new file mode 100644
index 0000000..a4ad990
--- /dev/null
+++ b/share/dictionary.rfc6929
@@ -0,0 +1,26 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Attributes and values defined in RFC 6929
+# http://www.ietf.org/rfc/rfc6929.txt
+
+#
+# These attributes in this dictionary are "place-holder". They
+# should NEVER be used by name. The "extended" and "long-extended"
+# and "evs" data types should NEVER be used in any other dictionary.
+#
+#
+ATTRIBUTE Extended-Attribute-1 241 extended
+ATTRIBUTE Extended-Attribute-2 242 extended
+ATTRIBUTE Extended-Attribute-3 243 extended
+ATTRIBUTE Extended-Attribute-4 244 extended
+ATTRIBUTE Extended-Attribute-5 245 long-extended
+ATTRIBUTE Extended-Attribute-6 246 long-extended
+
+ATTRIBUTE Extended-Vendor-Specific-1 241.26 evs
+ATTRIBUTE Extended-Vendor-Specific-2 242.26 evs
+ATTRIBUTE Extended-Vendor-Specific-3 243.26 evs
+ATTRIBUTE Extended-Vendor-Specific-4 244.26 evs
+ATTRIBUTE Extended-Vendor-Specific-5 245.26 evs
+ATTRIBUTE Extended-Vendor-Specific-6 246.26 evs
diff --git a/share/dictionary.rfc6930 b/share/dictionary.rfc6930
new file mode 100644
index 0000000..db2b439
--- /dev/null
+++ b/share/dictionary.rfc6930
@@ -0,0 +1,12 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Attributes and values defined in RFC 6930
+# http://www.ietf.org/rfc/rfc6930.txt
+#
+
+ATTRIBUTE IPv6-6rd-Configuration 173 tlv
+ATTRIBUTE IPv6-6rd-IPv4MaskLen 173.1 integer
+ATTRIBUTE IPv6-6rd-Prefix 173.2 ipv6prefix
+ATTRIBUTE IPv6-6rd-BR-IPv4-Address 173.3 ipaddr
diff --git a/share/dictionary.rfc7055 b/share/dictionary.rfc7055
new file mode 100644
index 0000000..f0400cd
--- /dev/null
+++ b/share/dictionary.rfc7055
@@ -0,0 +1,12 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Attributes and values defined in RFC 7055
+# http://www.ietf.org/rfc/rfc7055.txt
+#
+
+ATTRIBUTE GSS-Acceptor-Service-Name 164 string
+ATTRIBUTE GSS-Acceptor-Host-Name 165 string
+ATTRIBUTE GSS-Acceptor-Service-Specifics 166 string
+ATTRIBUTE GSS-Acceptor-Realm-Name 167 string
diff --git a/share/dictionary.rfc7155 b/share/dictionary.rfc7155
new file mode 100644
index 0000000..9aa64db
--- /dev/null
+++ b/share/dictionary.rfc7155
@@ -0,0 +1,12 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Attributes and values defined in RFC 7155
+# http://www.ietf.org/rfc/rfc7155.txt
+#
+
+# The Value field contains two octets (00 - 99). ANSI T1.113 and
+# BELLCORE 394 can be used for additional information about these
+# values and their use.
+ATTRIBUTE Originating-Line-Info 94 octets[2]
diff --git a/share/dictionary.rfc7268 b/share/dictionary.rfc7268
new file mode 100644
index 0000000..8ac2b34
--- /dev/null
+++ b/share/dictionary.rfc7268
@@ -0,0 +1,70 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Attributes and values defined in RFC 7268
+# http://www.ietf.org/rfc/rfc7268.txt
+#
+# $Id$
+#
+
+ATTRIBUTE Allowed-Called-Station-Id 174 string
+ATTRIBUTE EAP-Peer-Id 175 octets
+ATTRIBUTE EAP-Server-Id 176 octets
+ATTRIBUTE Mobility-Domain-Id 177 integer
+ATTRIBUTE Preauth-Timeout 178 integer
+ATTRIBUTE Network-Id-Name 179 octets
+
+# TLVs in the format defined in Figure 11-8 of Section 11.12 of
+# "IEEE Standard for Local and metropolitan area
+# networks - Port-Based Network Access Control", IEEE Std
+# 802.1X-2010.
+#
+# These are <drum roll> 7 bit TLV-Type, and 9-bit TLV-Length
+#
+# If the TLVs are too large for 253 octets, they are fragmented
+# into multiple attributes.
+ATTRIBUTE EAPoL-Announcement 180 octets concat
+
+ATTRIBUTE WLAN-HESSID 181 string
+
+# The upper two octets MUST be zero.
+# low two octets are Venue-Group and Venue-Type.
+# Defined in Section 8.4.1.34 of the above IEEE document.
+ATTRIBUTE WLAN-Venue-Info 182 integer
+
+# A two or 3 character language code selected from ISO-639.
+# If it's two characters, a trailing zero byte is added
+ATTRIBUTE WLAN-Venue-Language 183 octets[3]
+
+ATTRIBUTE WLAN-Venue-Name 184 string
+
+# two least significant octets contain the Reason Code values defined
+# in Table 8-36 of Section 8.4.1.7 of the above IEEE document.
+ATTRIBUTE WLAN-Reason-Code 185 integer
+
+# The next four attributes are binary packed. The first 3 octets is
+# the OUI. The last octet is the Suite Type.
+
+# in Suite selector format as specified in Figure 8-187 within Section
+# 8.4.2.27.2 of [IEEE-802.11], with values of OUI and Suite Type drawn
+# from Table 8-99.
+ATTRIBUTE WLAN-Pairwise-Cipher 186 integer
+
+# same as WLAN-Pairwise-Cipher
+ATTRIBUTE WLAN-Group-Cipher 187 integer
+
+# in Suite selector format as specified in Figure 8-187
+# within Section 8.4.2.27.2 of [IEEE-802.11], with values of OUI and
+# Suite Type drawn from Table 8-101:
+ATTRIBUTE WLAN-AKM-Suite 188 integer
+
+# same as WLAN-Pairwise-Cipher
+ATTRIBUTE WLAN-Group-Mgmt-Cipher 189 integer
+
+# the upper 3 octets are zero
+# the low octet contains the RF Band field, whose values are defined
+# by the IEEE 802.11 Band ID field (Table 8-53a of [IEEE-802.11ad])
+
+ATTRIBUTE WLAN-RF-Band 190 integer
+
diff --git a/share/dictionary.rfc7499 b/share/dictionary.rfc7499
new file mode 100644
index 0000000..2231b8f
--- /dev/null
+++ b/share/dictionary.rfc7499
@@ -0,0 +1,18 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Attributes and values defined in RFC 7499.
+# http://www.ietf.org/rfc/rfc7499.txt
+#
+# $Id$
+#
+
+ATTRIBUTE Frag-Status 241.1 integer
+ATTRIBUTE Proxy-State-Length 241.2 integer
+
+VALUE Frag-Status Reserved 0
+VALUE Frag-Status Fragmentation-Supported 1
+VALUE Frag-Status More-Data-Pending 2
+VALUE Frag-Status More-Data-Request 3
+
diff --git a/share/dictionary.rfc7930 b/share/dictionary.rfc7930
new file mode 100644
index 0000000..0b4667b
--- /dev/null
+++ b/share/dictionary.rfc7930
@@ -0,0 +1,10 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Attributes and values defined in RFC 7930
+# http://www.ietf.org/rfc/rfc7930.txt
+#
+
+ATTRIBUTE Response-Length 241.3 integer
+ATTRIBUTE Original-Packet-Code 241.4 integer
diff --git a/share/dictionary.rfc8045 b/share/dictionary.rfc8045
new file mode 100644
index 0000000..51fd76e
--- /dev/null
+++ b/share/dictionary.rfc8045
@@ -0,0 +1,65 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+# Version $Id$
+#
+# Attributes and values defined in RFC 8045
+# http://www.ietf.org/rfc/rfc8045.txt
+#
+
+ATTRIBUTE IP-Port-Limit-Info 241.5 tlv
+ATTRIBUTE IP-Port-Range 241.6 tlv
+ATTRIBUTE IP-Port-Forwarding-Map 241.7 tlv
+
+#
+# These attributes can appear in all of the above TLVs. There is
+# currently no way to describe this using the existing dictionary
+# format.
+#
+ATTRIBUTE IP-Port-Type 241.5.1 integer
+ATTRIBUTE IP-Port-Limit 241.5.2 integer
+ATTRIBUTE IP-Port-Ext-IPv4-Addr 241.5.3 ipaddr
+ATTRIBUTE IP-Port-Int-IPv4-Addr 241.5.4 ipaddr
+ATTRIBUTE IP-Port-Int-IPv6-Addr 241.5.5 ipv6addr
+ATTRIBUTE IP-Port-Int-Port 241.5.6 integer
+ATTRIBUTE IP-Port-Ext-Port 241.5.7 integer
+ATTRIBUTE IP-Port-Alloc 241.5.8 integer
+ATTRIBUTE IP-Port-Range-Start 241.5.9 integer
+ATTRIBUTE IP-Port-Range-End 241.5.10 integer
+ATTRIBUTE IP-Port-Local-Id 241.5.11 string
+
+VALUE IP-Port-Alloc Reserved 0
+VALUE IP-Port-Alloc Allocation 1
+VALUE IP-Port-Alloc Deallocation 2
+
+ATTRIBUTE IP-Port-Range-Type 241.6.1 integer
+ATTRIBUTE IP-Port-Range-Limit 241.6.2 integer
+ATTRIBUTE IP-Port-Range-Ext-IPv4-Addr 241.6.3 ipaddr
+ATTRIBUTE IP-Port-Range-Int-IPv4-Addr 241.6.4 ipaddr
+ATTRIBUTE IP-Port-Range-Int-IPv6-Addr 241.6.5 ipv6addr
+ATTRIBUTE IP-Port-Range-Int-Port 241.6.6 integer
+ATTRIBUTE IP-Port-Range-Ext-Port 241.6.7 integer
+ATTRIBUTE IP-Port-Range-Alloc 241.6.8 integer
+ATTRIBUTE IP-Port-Range-Range-Start 241.6.9 integer
+ATTRIBUTE IP-Port-Range-Range-End 241.6.10 integer
+ATTRIBUTE IP-Port-Range-Local-Id 241.6.11 string
+
+VALUE IP-Port-Range-Alloc Reserved 0
+VALUE IP-Port-Range-Alloc Allocation 1
+VALUE IP-Port-Range-Alloc Deallocation 2
+
+ATTRIBUTE IP-Port-Map-Type 241.7.1 integer
+ATTRIBUTE IP-Port-Map-Limit 241.7.2 integer
+ATTRIBUTE IP-Port-Map-Ext-IPv4-Addr 241.7.3 ipaddr
+ATTRIBUTE IP-Port-Map-Int-IPv4-Addr 241.7.4 ipaddr
+ATTRIBUTE IP-Port-Map-Int-IPv6-Addr 241.7.5 ipv6addr
+ATTRIBUTE IP-Port-Map-Int-Port 241.7.6 integer
+ATTRIBUTE IP-Port-Map-Ext-Port 241.7.7 integer
+ATTRIBUTE IP-Port-Map-Alloc 241.7.8 integer
+ATTRIBUTE IP-Port-Map-Range-Start 241.7.9 integer
+ATTRIBUTE IP-Port-Map-Range-End 241.7.10 integer
+ATTRIBUTE IP-Port-Map-Local-Id 241.7.11 string
+
+VALUE IP-Port-Map-Alloc Reserved 0
+VALUE IP-Port-Map-Alloc Allocation 1
+VALUE IP-Port-Map-Alloc Deallocation 2
diff --git a/share/dictionary.rfc8559 b/share/dictionary.rfc8559
new file mode 100644
index 0000000..4d3659c
--- /dev/null
+++ b/share/dictionary.rfc8559
@@ -0,0 +1,9 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Attributes and values defined in RFC 8859
+# http://www.ietf.org/rfc/rfc8859
+#
+
+ATTRIBUTE Operator-NAS-Identifier 241.8 octets
diff --git a/share/dictionary.riverbed b/share/dictionary.riverbed
new file mode 100644
index 0000000..8d3b501
--- /dev/null
+++ b/share/dictionary.riverbed
@@ -0,0 +1,21 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Riverbed VSAs
+#
+# https://support.riverbed.com/bin/support/static/doc/steelhead/8.5.2/html/sh_8.5.2_dg/wwhelp/wwhimpl/common/html/wwhelp.htm#href=radius_tacacs.22.04.html&single=true
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR Riverbed 17163
+
+BEGIN-VENDOR Riverbed
+
+ATTRIBUTE Riverbed-Local-User 1 string
+
+END-VENDOR Riverbed
diff --git a/share/dictionary.riverstone b/share/dictionary.riverstone
new file mode 100644
index 0000000..d941b26
--- /dev/null
+++ b/share/dictionary.riverstone
@@ -0,0 +1,45 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Riverstone Networks' RADIUS VSAs
+# *** For RapidOS Versions 9.1 and above ONLY ***
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR Riverstone 5567
+
+#
+# Riverstone-Command
+#
+# This attribute is sent in Accounting-Requests, and contains text
+# from the admin's CLI session.
+#
+BEGIN-VENDOR Riverstone
+
+ATTRIBUTE Riverstone-Command 1 string
+
+#
+# This attribute is sent in Accounting-Requests, as a duplicate
+# of syslog for system event messages.
+#
+ATTRIBUTE Riverstone-System-Event 2 string
+
+#
+# This attribute is sent in Accounting-Requests, to log changes
+# made via SNMP.
+#
+ATTRIBUTE Riverstone-SNMP-Config-Change 3 string
+
+#
+# This attribute should be sent in Access-Accept packets, to set
+# the privilege level. It MUST be sent when the device is operating
+# in Mult-User Access mode.
+#
+ATTRIBUTE Riverstone-User-Level 4 integer
+
+END-VENDOR Riverstone
diff --git a/share/dictionary.roaringpenguin b/share/dictionary.roaringpenguin
new file mode 100644
index 0000000..95cba28
--- /dev/null
+++ b/share/dictionary.roaringpenguin
@@ -0,0 +1,32 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Roaring Penguin attributes
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR Roaring-Penguin 10055
+
+BEGIN-VENDOR Roaring-Penguin
+
+# Upstream speed limit in kb/s
+ATTRIBUTE RP-Upstream-Speed-Limit 1 integer
+
+# Downstream speed limit in kb/s
+ATTRIBUTE RP-Downstream-Speed-Limit 2 integer
+
+# Send a HURL
+ATTRIBUTE RP-HURL 3 string
+
+# Send a MOTM
+ATTRIBUTE RP-MOTM 4 string
+
+# Maximum sessions per user
+ATTRIBUTE RP-Max-Sessions-Per-User 5 integer
+
+END-VENDOR Roaring-Penguin
diff --git a/share/dictionary.ruckus b/share/dictionary.ruckus
new file mode 100644
index 0000000..41e8959
--- /dev/null
+++ b/share/dictionary.ruckus
@@ -0,0 +1,155 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Ruckus Wireless, Inc. dictionary
+#
+#
+
+VENDOR Ruckus 25053
+
+BEGIN-VENDOR Ruckus
+
+# Value Format: group_attr1,group_attr2,...
+ATTRIBUTE Ruckus-User-Groups 1 string
+ATTRIBUTE Ruckus-Sta-RSSI 2 integer
+ATTRIBUTE Ruckus-SSID 3 string
+ATTRIBUTE Ruckus-Wlan-Id 4 integer
+ATTRIBUTE Ruckus-Location 5 string
+ATTRIBUTE Ruckus-Grace-Period 6 integer
+ATTRIBUTE Ruckus-SCG-CBlade-IP 7 integer
+ATTRIBUTE Ruckus-SCG-DBlade-IP 8 integer
+ATTRIBUTE Ruckus-VLAN-ID 9 integer
+ATTRIBUTE Ruckus-Sta-Expiration 10 integer # not used by AP anymore. Please check SCG-33602
+ATTRIBUTE Ruckus-Sta-UUID 11 string
+ATTRIBUTE Ruckus-Accept-Enhancement-Reason 12 integer
+ATTRIBUTE Ruckus-Sta-Inner-Id 13 string
+ATTRIBUTE Ruckus-BSSID 14 octets
+
+ATTRIBUTE Ruckus-FlexAuth-AVP 20 string
+
+ATTRIBUTE Ruckus-WSG-User 10 string
+
+ATTRIBUTE Ruckus-Triplets 101 octets
+ATTRIBUTE Ruckus-IMSI 102 octets
+ATTRIBUTE Ruckus-MSISDN 103 octets
+ATTRIBUTE Ruckus-APN-NI 104 string
+ATTRIBUTE Ruckus-QoS 105 octets
+ATTRIBUTE Ruckus-Selection-Mode 106 integer
+ATTRIBUTE Ruckus-APN-Resolution-Req 107 integer
+ATTRIBUTE Ruckus-Start-Time 108 octets
+ATTRIBUTE Ruckus-NAS-Type 109 integer
+ATTRIBUTE Ruckus-Status 110 integer
+ATTRIBUTE Ruckus-APN-OI 111 string
+ATTRIBUTE Ruckus-Auth-Type 112 integer
+ATTRIBUTE Ruckus-Gn-User-Name 113 string
+ATTRIBUTE Ruckus-Brand-Code 114 string
+ATTRIBUTE Ruckus-Policy-Name 115 string
+ATTRIBUTE Ruckus-Client-Local-IP 116 ipaddr
+ATTRIBUTE Ruckus-SGSN-IP 117 ipaddr
+ATTRIBUTE Ruckus-Charging-Charac 118 octets
+ATTRIBUTE Ruckus-PDP-Type 119 octets
+ATTRIBUTE Ruckus-Dynamic-Address-Flag 120 octets
+ATTRIBUTE Ruckus-ChCh-Selection-Mode 121 octets
+ATTRIBUTE Ruckus-AAA-IP 122 ipaddr
+ATTRIBUTE Ruckus-CDR-TYPE 123 integer
+ATTRIBUTE Ruckus-SGSN-Number 124 octets
+ATTRIBUTE Ruckus-Session-Type 125 integer
+ATTRIBUTE Ruckus-Accounting-Status 126 integer
+ATTRIBUTE Ruckus-Zone-Id 127 string
+ATTRIBUTE Ruckus-Auth-Server-Id 128 string
+ATTRIBUTE Ruckus-Utp-Id 129 string
+ATTRIBUTE Ruckus-Area-Code 130 octets
+ATTRIBUTE Ruckus-Cell-Identifier 131 octets
+ATTRIBUTE Ruckus-Wispr-Redirect-Policy 132 string
+ATTRIBUTE Ruckus-Eth-Profile-Id 133 integer
+ATTRIBUTE Ruckus-Zone-Name 134 string
+ATTRIBUTE Ruckus-Wlan-Name 135 string
+ATTRIBUTE Ruckus-AP-Roamed 136 integer
+ATTRIBUTE Ruckus-Read-Preference 137 octets
+ATTRIBUTE Ruckus-Client-Host-Name 138 string
+ATTRIBUTE Ruckus-Client-Os-Type 139 string
+ATTRIBUTE Ruckus-Client-Os-Class 140 string
+ATTRIBUTE Ruckus-Vlan-Pool 141 string
+ATTRIBUTE Ruckus-Dpsk 142 octets
+ATTRIBUTE Ruckus-CP-Token 143 string
+ATTRIBUTE Ruckus-Max-DL-UL-Quota 144 integer
+ATTRIBUTE Ruckus-Traffic-Class-Attribute-Ids 145 string
+ATTRIBUTE Ruckus-TC-Attr-Ids-With-Quota 146 tlv
+ATTRIBUTE Ruckus-TC-Name-Quota 146.1 string
+ATTRIBUTE Ruckus-TC-Quota 146.2 octets
+
+ATTRIBUTE Ruckus-Nat-Pool-Name 147 string
+ATTRIBUTE Ruckus-Sta-SVlan-Id 148 integer
+ATTRIBUTE Ruckus-TC-Acct-Ctrs 149 tlv
+ATTRIBUTE Ruckus-Acct-Ctrs_TC-Name 149.1 string
+ATTRIBUTE Ruckus-Acct-Ctrs_Input-Octets 149.2 integer
+ATTRIBUTE Ruckus-Acct-Ctrs_Output-Octets 149.3 integer
+ATTRIBUTE Ruckus-Acct-Ctrs_Input-Packets 149.4 integer
+ATTRIBUTE Ruckus-Acct-Ctrs_Output-Packets 149.5 integer
+
+ATTRIBUTE Ruckus-AAA-Id 152 string
+ATTRIBUTE Ruckus-DPSK-Params 153 tlv
+ATTRIBUTE Ruckus-DPSK-AKM-Suite 153.1 octets
+ATTRIBUTE Ruckus-DPSK-Cipher 153.2 byte
+ATTRIBUTE Ruckus-DPSK-Anonce 153.3 octets
+ATTRIBUTE Ruckus-DPSK-EAPOL-Key-Frame 153.4 octets
+
+# Ruckus SmartCell Insight Attributes
+ATTRIBUTE Ruckus-SCI-Role 200 string
+ATTRIBUTE Ruckus-SCI-Resource-Group 201 string
+
+#
+# Integer Translations
+#
+
+# Ruckus-Selection-Mode Values
+
+VALUE Ruckus-Selection-Mode Subscribed 0
+VALUE Ruckus-Selection-Mode SentByMS 1
+VALUE Ruckus-Selection-Mode ChosenBySGSN 2
+
+# Ruckus-APN-Resolution-Req Values
+
+VALUE Ruckus-APN-Resolution-Req NotRequired 0
+VALUE Ruckus-APN-Resolution-Req Required 1
+
+# Ruckus-Status Values
+
+VALUE Ruckus-Status Success 0
+VALUE Ruckus-Status Failure 1
+
+# Ruckus-Auth-Type Values
+
+VALUE Ruckus-Auth-Type PPP-SIM 1
+VALUE Ruckus-Auth-Type DummyIMSI 2
+VALUE Ruckus-Auth-Type SoftSIM 3
+VALUE Ruckus-Auth-Type RadiusSIM 4
+VALUE Ruckus-Auth-Type Postpaid 5
+VALUE Ruckus-Auth-Type Prepaid 6
+VALUE Ruckus-Auth-Type LocalRadius 7
+VALUE Ruckus-Auth-Type ProxyRadius 8
+VALUE Ruckus-Auth-Type Voucher 9
+VALUE Ruckus-Auth-Type EAP-SIM 10
+
+# Ruckus-Session-Type Values
+# Updated as per SCG2.1
+#Value (1) No more valid for SCG2.1
+VALUE Ruckus-Session-Type TTG 2
+VALUE Ruckus-Session-Type Local-Breakout 3
+VALUE Ruckus-Session-Type Local-Breakout-AP 4
+VALUE Ruckus-Session-Type L3GRE 5
+VALUE Ruckus-Session-Type L2GRE 6
+VALUE Ruckus-Session-Type QinQL3 7
+VALUE Ruckus-Session-Type PMIP 8
+
+#RUCKUS-NAS_Type
+
+VALUE Ruckus-NAS-Type SCG 1
+VALUE Ruckus-NAS-Type Others 2
+
+#Ruckus-Accounting-Status
+VALUE Ruckus-Accounting-Status Accounting-On 1
+VALUE Ruckus-Accounting-Status Accounting-Off 0
+
+END-VENDOR Ruckus
diff --git a/share/dictionary.ruggedcom b/share/dictionary.ruggedcom
new file mode 100644
index 0000000..0f839fc
--- /dev/null
+++ b/share/dictionary.ruggedcom
@@ -0,0 +1,12 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+
+VENDOR RuggedCom 15004
+
+BEGIN-VENDOR RuggedCom
+
+ATTRIBUTE RuggedCom-Privilege-level 2 string
+
+END-VENDOR RuggedCom
diff --git a/share/dictionary.sangoma b/share/dictionary.sangoma
new file mode 100644
index 0000000..fffb338
--- /dev/null
+++ b/share/dictionary.sangoma
@@ -0,0 +1,114 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# dictionary.sangoma
+#
+# jma@sangoma.com
+#
+# Version: $Id: dictionary.sangoma
+#
+
+VENDOR NetBorder 35987
+
+#
+# Standard attribute
+#
+BEGIN-VENDOR NetBorder
+
+ATTRIBUTE NetBorder-AVPair 1 string
+ATTRIBUTE NetBorder-CLID 2 string
+ATTRIBUTE NetBorder-Dialplan 3 string
+ATTRIBUTE NetBorder-Src 4 string
+ATTRIBUTE NetBorder-Dst 5 string
+ATTRIBUTE NetBorder-Src-Channel 6 string
+ATTRIBUTE NetBorder-Dst-Channel 7 string
+ATTRIBUTE NetBorder-Ani 8 string
+ATTRIBUTE NetBorder-Aniii 9 string
+ATTRIBUTE NetBorder-Lastapp 10 string
+ATTRIBUTE NetBorder-Lastdata 11 string
+ATTRIBUTE NetBorder-Disposition 12 string
+ATTRIBUTE NetBorder-Hangupcause 13 integer
+ATTRIBUTE NetBorder-Billusec 15 integer
+ATTRIBUTE NetBorder-AMAFlags 16 integer
+ATTRIBUTE NetBorder-RDNIS 17 string
+ATTRIBUTE NetBorder-Context 18 string
+ATTRIBUTE NetBorder-Source 19 string
+ATTRIBUTE NetBorder-Callstartdate 20 string
+ATTRIBUTE NetBorder-Callanswerdate 21 string
+ATTRIBUTE NetBorder-Calltransferdate 22 string
+ATTRIBUTE NetBorder-Callenddate 23 string
+ATTRIBUTE NetBorder-Signalbond 24 string
+
+#
+# NetBorder-Hangupcause
+#
+VALUE NetBorder-Hangupcause None 0
+VALUE NetBorder-Hangupcause Unallocated-Number 1
+VALUE NetBorder-Hangupcause No-Route-Transit-Net 2
+VALUE NetBorder-Hangupcause No-Route-Destination 3
+VALUE NetBorder-Hangupcause Channel-Unacceptable 6
+VALUE NetBorder-Hangupcause Call-Awarded-Delivery 7
+VALUE NetBorder-Hangupcause Normal-Clearing 16
+VALUE NetBorder-Hangupcause User-Busy 17
+VALUE NetBorder-Hangupcause No-User-Response 18
+VALUE NetBorder-Hangupcause No-Answer 19
+VALUE NetBorder-Hangupcause Subscriber-Absent 20
+VALUE NetBorder-Hangupcause Call-Rejected 21
+VALUE NetBorder-Hangupcause Number-Changed 22
+VALUE NetBorder-Hangupcause Redirecto-To-New-Destination 23
+VALUE NetBorder-Hangupcause Exchange-Routing-Error 25
+VALUE NetBorder-Hangupcause Destination-Out-Of-Order 27
+VALUE NetBorder-Hangupcause Invalid-Number-Format 28
+VALUE NetBorder-Hangupcause Facility-Rejected 29
+VALUE NetBorder-Hangupcause Response-To-Status-Enquiry 30
+VALUE NetBorder-Hangupcause Normal-Unspecified 31
+VALUE NetBorder-Hangupcause Normal-Circuit-Congestion 34
+VALUE NetBorder-Hangupcause Network-Out-Of-Order 38
+VALUE NetBorder-Hangupcause Normal-Temporary-Failure 41
+VALUE NetBorder-Hangupcause Switch-Congestion 42
+VALUE NetBorder-Hangupcause Access-Info-Discarded 43
+VALUE NetBorder-Hangupcause Requested-Chan-Unavail 44
+VALUE NetBorder-Hangupcause Pre-Empted 45
+VALUE NetBorder-Hangupcause Facility-Not-Subscribed 50
+VALUE NetBorder-Hangupcause Outgoing-Call-Barred 52
+VALUE NetBorder-Hangupcause Incoming-Call-Barred 54
+VALUE NetBorder-Hangupcause Bearercapability-Notauth 57
+VALUE NetBorder-Hangupcause Bearercapability-Notavail 58
+VALUE NetBorder-Hangupcause Service-Unavailable 63
+VALUE NetBorder-Hangupcause Bearercapability-Notimpl 65
+VALUE NetBorder-Hangupcause Chan-Not-Implemented 66
+VALUE NetBorder-Hangupcause Facility-Not-Implemented 69
+VALUE NetBorder-Hangupcause Service-Not-Implemented 79
+VALUE NetBorder-Hangupcause Invalid-Call-Reference 81
+VALUE NetBorder-Hangupcause Incompatible-Destination 88
+VALUE NetBorder-Hangupcause Invalid-Msg-Unspecified 95
+VALUE NetBorder-Hangupcause Mandatory-IE-Missing 96
+VALUE NetBorder-Hangupcause Message-Type-Nonexist 97
+VALUE NetBorder-Hangupcause Wrong-Message 98
+VALUE NetBorder-Hangupcause IE-Nonexist 99
+VALUE NetBorder-Hangupcause Invalid-IE-Contents 100
+VALUE NetBorder-Hangupcause Wrong-Call-State 101
+VALUE NetBorder-Hangupcause Recovery-On-Timer-Expire 102
+VALUE NetBorder-Hangupcause Mandatory-IE-Length-Error 103
+VALUE NetBorder-Hangupcause Protocol-Error 111
+VALUE NetBorder-Hangupcause Interworking 127
+VALUE NetBorder-Hangupcause Success 142
+VALUE NetBorder-Hangupcause Originator-Cancel 487
+VALUE NetBorder-Hangupcause Crash 500
+VALUE NetBorder-Hangupcause System-Shutdown 501
+VALUE NetBorder-Hangupcause Lose-Race 502
+VALUE NetBorder-Hangupcause Manager-Request 503
+VALUE NetBorder-Hangupcause Blind-Transfer 600
+VALUE NetBorder-Hangupcause Attended-Transfer 601
+VALUE NetBorder-Hangupcause Allotted-Timeout 602
+VALUE NetBorder-Hangupcause User-Challenge 603
+VALUE NetBorder-Hangupcause Media-Timeout 604
+VALUE NetBorder-Hangupcause Picked-Off 605
+VALUE NetBorder-Hangupcause User-Not-Registered 606
+
+#
+#
+#
+
+END-VENDOR NetBorder
diff --git a/share/dictionary.sg b/share/dictionary.sg
new file mode 100644
index 0000000..2fde048
--- /dev/null
+++ b/share/dictionary.sg
@@ -0,0 +1,149 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# SG-1 System by Runcom Technologies Ltd.
+#
+# ftp://ftp.3gpp.org/specs/2002-06/R1999/29_series/29061-3a0.zip
+#
+# $Id$
+#
+VENDOR SG 2454
+
+BEGIN-VENDOR SG
+
+ATTRIBUTE SG-Filter-Redirect-Gw 1 ipaddr
+ATTRIBUTE SG-Accounting 10 integer
+ATTRIBUTE SG-Orig-Name 12 string
+ATTRIBUTE SG-Auth-Type 13 integer
+ATTRIBUTE SG-Action 14 integer
+ATTRIBUTE SG-SSC-Host 15 ipaddr
+ATTRIBUTE SG-Service-Name 16 string
+ATTRIBUTE SG-Personal-Site 17 string
+ATTRIBUTE SG-Mac-Address 18 string
+ATTRIBUTE SG-User-Group 19 integer
+ATTRIBUTE SG-Max-Allowed-Sessions 20 integer
+ATTRIBUTE SG-Class 21 string
+ATTRIBUTE SG-Eds-Enc-Key 22 string
+ATTRIBUTE SG-Eds-Cookie 23 string
+ATTRIBUTE SG-Original-Url-Prefix 24 string
+ATTRIBUTE SG-Max-Allowed-Nodes 25 integer
+ATTRIBUTE SG-Parent-User-Name 26 string
+ATTRIBUTE SG-Node-Group 27 integer
+ATTRIBUTE SG-Node-Default-Service 28 string
+ATTRIBUTE SG-Node-Dynamic-Service 29 string
+ATTRIBUTE SG-Dhcp-Server 30 ipaddr
+ATTRIBUTE SG-Opt82-Relay-Remote-Id 31 string
+ATTRIBUTE SG-Discover-Action 32 integer
+ATTRIBUTE SG-Release-Action 33 integer
+ATTRIBUTE SG-Fixed-Ip-Address 34 string
+ATTRIBUTE SG-Node-Fixed-Ip-Address 35 string
+ATTRIBUTE SG-Lease-Time 36 integer
+ATTRIBUTE SG-Protocol-Type 40 integer
+ATTRIBUTE SG-Service-Timeout 50 integer
+ATTRIBUTE SG-Next-Service-Name 51 string
+ATTRIBUTE SG-Auto-Service-Name 52 string
+ATTRIBUTE SG-Auth-Source 53 integer
+ATTRIBUTE SG-Data-Quota 54 string
+ATTRIBUTE SG-Acl-Data-Quota 55 string
+ATTRIBUTE SG-Service-Cache 56 integer
+ATTRIBUTE SG-Data-Quota-Used 57 string
+ATTRIBUTE SG-Acl-Data-Quota-Used 58 string
+ATTRIBUTE SG-Acl-Packet-Quota 59 string
+ATTRIBUTE SG-Acl-Packet-Quota-Used 60 string
+ATTRIBUTE SG-Roaming 61 integer
+ATTRIBUTE SG-Acl-Eds-Action 62 string
+ATTRIBUTE SG-Acl-Idle-Ignore 63 string
+ATTRIBUTE SG-Service-Quota-Ignore 65 string
+ATTRIBUTE SG-Service-Acl-Quota-Ignore 66 string
+ATTRIBUTE SG-Service-Acl-Quota-Indication 67 string
+ATTRIBUTE SG-Remote-Filter-Redirect-Gw 70 string
+ATTRIBUTE SG-Next-Hop 71 ipaddr
+ATTRIBUTE SG-Nip-Pipe-Next-Hop 72 ipaddr
+ATTRIBUTE SG-Advertise-Protocol 73 integer
+ATTRIBUTE SG-Forward-Addr 74 ipaddr
+ATTRIBUTE SG-Acl-Tcp-Nat-Redirect 75 string
+ATTRIBUTE SG-Acl-Next-Hop 76 string
+ATTRIBUTE SG-Tunnel-Id 80 string
+ATTRIBUTE SG-L2tp-Tunnel-Password 81 string
+ATTRIBUTE SG-Ip-Address 82 string
+ATTRIBUTE SG-Tunnel-Assignment-Id 83 integer
+ATTRIBUTE SG-Tunnel-Client-Ip-Address 84 ipaddr
+ATTRIBUTE SG-Nativeip 85 integer
+ATTRIBUTE SG-Ip-Tunnel 86 string
+ATTRIBUTE SG-Up-Mean-Rate 90 string
+ATTRIBUTE SG-Down-Mean-Rate 91 string
+ATTRIBUTE SG-Acl-Up-Mean-Rate 92 string
+ATTRIBUTE SG-Acl-Down-Mean-Rate 93 string
+ATTRIBUTE SG-Cos 94 string
+ATTRIBUTE SG-Acl-Priority 95 string
+ATTRIBUTE SG-Burst-Size 96 integer
+ATTRIBUTE SG-Ip-Primary 100 ipaddr
+ATTRIBUTE SG-Ip-Secondary 101 ipaddr
+ATTRIBUTE SG-Wimax-Reduced-Resources 110 integer
+ATTRIBUTE SG-Wimax-Acl-Schedule-Type 111 string
+ATTRIBUTE SG-Wimax-Acl-Min-Reserved-Traffic-Rate 112 string
+ATTRIBUTE SG-Wimax-Acl-Maximum-Traffic-Burst 113 string
+ATTRIBUTE SG-Wimax-Acl-Tolerated-Jitter 114 string
+ATTRIBUTE SG-Wimax-Acl-Maximum-Latency 115 string
+ATTRIBUTE SG-Wimax-Acl-Unsolicited-Grant-Int 116 string
+ATTRIBUTE SG-Wimax-Acl-Sdu-Size 117 string
+ATTRIBUTE SG-Wimax-Acl-Unsolicited-Polling-Int 118 string
+ATTRIBUTE SG-Wimax-MSK-Lifetime 119 integer
+ATTRIBUTE SG-Wimax-DM-Action-Code 120 integer
+ATTRIBUTE SG-Wimax-Acl-ARQ-Enable 121 string
+ATTRIBUTE SG-Wimax-Bsid-Next-Hop 122 ipaddr
+ATTRIBUTE SG-Wimax-Mobility-Features-Supported 123 integer
+ATTRIBUTE SG-Wimax-Node-Disconnect 124 integer
+ATTRIBUTE SG-Wimax-Service-Flow-Modification 125 integer
+ATTRIBUTE SG-Wimax-Service-Flow-Down 126 string
+ATTRIBUTE SG-Node-Acct-Username 130 string
+VALUE SG-Accounting Disable 1
+VALUE SG-Accounting Enable 2
+VALUE SG-Accounting Lastpacket 3
+VALUE SG-Accounting Enable-On-IP-Update 4
+VALUE SG-Accounting Reset-Acct-Session-ID 5
+VALUE SG-Auth-Type Pre-Auth 1
+VALUE SG-Auth-Type Service-Selection 2
+VALUE SG-Auth-Type Web-Auth 3
+VALUE SG-Action Reject 1
+VALUE SG-Action Echo 2
+VALUE SG-Action L2Echo 6
+VALUE SG-Action Macantispoof 3
+VALUE SG-Action User-Space-Overwrite 4
+VALUE SG-Action User-Space-Overwrite-On-Next-Service 5
+VALUE SG-Discover-Action Normal 1
+VALUE SG-Discover-Action Update 2
+VALUE SG-Discover-Action Pass-Through 3
+VALUE SG-Release-Action Disconnect 1
+VALUE SG-Release-Action Update 2
+VALUE SG-Protocol-Type MLP 1
+VALUE SG-Protocol-Type ROAM 2
+VALUE SG-Auth-Source Service 1
+VALUE SG-Auth-Source User 2
+VALUE SG-Auth-Source CLI 3
+VALUE SG-Service-Cache Off 1
+VALUE SG-Roaming Disable 1
+VALUE SG-Advertise-Protocol RIPv2 1
+VALUE SG-Advertise-Protocol OSPF 2
+VALUE SG-Nativeip PPP 1
+VALUE SG-Wimax-Reduced-Resources Enable 1
+VALUE SG-Wimax-Reduced-Resources Disable 2
+VALUE SG-Wimax-DM-Action-Code Reconnect-Disable 0x000010E0
+VALUE SG-Wimax-DM-Action-Code Reconnect-Disable-On-Idle 0x000410E0
+VALUE SG-Wimax-DM-Action-Code Idle 0x00000005
+VALUE SG-Wimax-DM-Action-Code Idle-On-Session-Idle 0x00040005
+VALUE SG-Wimax-Mobility-Features-Supported Mobility 1
+VALUE SG-Wimax-Mobility-Features-Supported Sleep 2
+VALUE SG-Wimax-Mobility-Features-Supported Idle 4
+VALUE SG-Wimax-Mobility-Features-Supported NoMobility 4294967294
+VALUE SG-Wimax-Mobility-Features-Supported NoSleep 4294967293
+VALUE SG-Wimax-Mobility-Features-Supported NoIdle 4294967291
+VALUE SG-Wimax-Node-Disconnect Enable 0
+VALUE SG-Wimax-Node-Disconnect Disable 1
+VALUE SG-Wimax-Service-Flow-Modification On 2
+VALUE SG-Wimax-Service-Flow-Modification Off 1
+VALUE Acct-Status-Type SG-Service-Start 0x09960001
+VALUE Acct-Status-Type SG-Service-Stop 0x09960002
+
+END-VENDOR SG
diff --git a/share/dictionary.shasta b/share/dictionary.shasta
new file mode 100644
index 0000000..87b3ff3
--- /dev/null
+++ b/share/dictionary.shasta
@@ -0,0 +1,26 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# dictionary.shasta
+#
+# Nortel Shasta VSAs
+# Andre Gustavo de C. Albuquerque <gustavoa@nortelnetworks.com>
+#
+
+VENDOR Shasta 3199
+
+#
+# Standard attribute
+#
+BEGIN-VENDOR Shasta
+
+ATTRIBUTE Shasta-User-Privilege 1 integer
+ATTRIBUTE Shasta-Service-Profile 2 string
+ATTRIBUTE Shasta-VPN-Name 3 string
+
+VALUE Shasta-User-Privilege User 1
+VALUE Shasta-User-Privilege Super-User 2
+VALUE Shasta-User-Privilege SSuper-User 3
+
+END-VENDOR Shasta
diff --git a/share/dictionary.shiva b/share/dictionary.shiva
new file mode 100644
index 0000000..08da819
--- /dev/null
+++ b/share/dictionary.shiva
@@ -0,0 +1,131 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Shiva dictionary.
+#
+# Shiva Inc.
+# http://www.shiva.com/
+#
+# For more information on magic values for Shiva-User-Attributes,
+# see their web page, at:
+#
+# http://www.shiva.com/prod/kbase/mapping.html
+#
+# Enable by putting the line "$INCLUDE dictionary.shiva" into
+# the main dictionary file.
+#
+# Version: 1.00 27-Apr-1999 contributed by Alan DeKok
+# $Id$
+#
+
+VENDOR Shiva 166
+
+# Shiva Extensions
+
+#
+# This next attribute is Shiva's attempt to create their own
+# VSA in the main dictionary. Don't use it. It's a bad idea.
+#
+#ATTRIBUTE Shiva-User-Attributes 51 string
+
+BEGIN-VENDOR Shiva
+
+ATTRIBUTE Shiva-User-Attributes 1 string
+ATTRIBUTE Shiva-Compression 30 integer
+ATTRIBUTE Shiva-Dialback-Delay 31 integer
+ATTRIBUTE Shiva-Call-Durn-Trap 32 integer
+ATTRIBUTE Shiva-Bandwidth-Trap 33 integer
+ATTRIBUTE Shiva-Minimum-Call 34 integer
+ATTRIBUTE Shiva-Default-Host 35 string
+ATTRIBUTE Shiva-Menu-Name 36 string
+ATTRIBUTE Shiva-User-Flags 37 string
+ATTRIBUTE Shiva-Termtype 38 string
+ATTRIBUTE Shiva-Break-Key 39 string
+ATTRIBUTE Shiva-Fwd-Key 40 string
+ATTRIBUTE Shiva-Bak-Key 41 string
+ATTRIBUTE Shiva-Dial-Timeout 42 integer
+ATTRIBUTE Shiva-LAT-Port 43 string
+ATTRIBUTE Shiva-Max-VCs 44 integer
+ATTRIBUTE Shiva-DHCP-Leasetime 45 integer
+ATTRIBUTE Shiva-LAT-Groups 46 string
+ATTRIBUTE Shiva-RTC-Timestamp 60 integer
+ATTRIBUTE Shiva-Circuit-Type 61 integer
+ATTRIBUTE Shiva-Called-Number 90 string
+ATTRIBUTE Shiva-Calling-Number 91 string
+ATTRIBUTE Shiva-Customer-Id 92 string
+ATTRIBUTE Shiva-Type-Of-Service 93 integer
+ATTRIBUTE Shiva-Link-Speed 94 integer
+ATTRIBUTE Shiva-Links-In-Bundle 95 integer
+ATTRIBUTE Shiva-Compression-Type 96 integer
+ATTRIBUTE Shiva-Link-Protocol 97 integer
+ATTRIBUTE Shiva-Network-Protocols 98 integer
+ATTRIBUTE Shiva-Session-Id 99 integer
+ATTRIBUTE Shiva-Disconnect-Reason 100 integer
+ATTRIBUTE Shiva-Acct-Serv-Switch 101 ipaddr
+ATTRIBUTE Shiva-Event-Flags 102 integer
+ATTRIBUTE Shiva-Function 103 integer
+ATTRIBUTE Shiva-Connect-Reason 104 integer
+
+VALUE Shiva-Compression None 0
+VALUE Shiva-Compression Negotiate 1
+VALUE Shiva-Compression Spider 2
+VALUE Shiva-Compression Predictor 3
+VALUE Shiva-Compression STAC 4
+
+VALUE Shiva-Circuit-Type Primary 1
+VALUE Shiva-Circuit-Type Secondary-Backup 2
+VALUE Shiva-Circuit-Type Secondary-Augment 3
+VALUE Shiva-Circuit-Type Secondary-Switch 4
+VALUE Shiva-Circuit-Type Listener 5
+VALUE Shiva-Circuit-Type RADIUS 6
+
+# Shiva Type Of Service Values
+
+VALUE Shiva-Type-Of-Service Analog 1
+VALUE Shiva-Type-Of-Service Digitized-Analog 2
+VALUE Shiva-Type-Of-Service Digital 3
+VALUE Shiva-Type-Of-Service Digital-V110 4
+VALUE Shiva-Type-Of-Service Digital-V120 5
+VALUE Shiva-Type-Of-Service Digital-Leased-Line 6
+
+# Shiva Link Protocol Values
+
+VALUE Shiva-Link-Protocol HDLC 1
+VALUE Shiva-Link-Protocol ARAV1 2
+VALUE Shiva-Link-Protocol ARAV2 3
+VALUE Shiva-Link-Protocol SHELL 4
+VALUE Shiva-Link-Protocol AALAP 5
+VALUE Shiva-Link-Protocol SLIP 6
+
+# Shiva Connect Reason Values
+
+VALUE Shiva-Connect-Reason Remote 1
+VALUE Shiva-Connect-Reason Dialback 2
+VALUE Shiva-Connect-Reason Virtual-Connection 3
+VALUE Shiva-Connect-Reason Bandwidth-On-Demand 4
+
+# Shiva Disconnect Reason Values
+
+VALUE Shiva-Disconnect-Reason Remote 1
+VALUE Shiva-Disconnect-Reason Error 2
+VALUE Shiva-Disconnect-Reason Idle-Timeout 3
+VALUE Shiva-Disconnect-Reason Session-Timeout 4
+VALUE Shiva-Disconnect-Reason Admin-Disconnect 5
+VALUE Shiva-Disconnect-Reason Dialback 6
+VALUE Shiva-Disconnect-Reason Virtual-Connection 7
+VALUE Shiva-Disconnect-Reason Bandwidth-On-Demand 8
+VALUE Shiva-Disconnect-Reason Failed-Authentication 9
+VALUE Shiva-Disconnect-Reason Preempted 10
+VALUE Shiva-Disconnect-Reason Blocked 11
+VALUE Shiva-Disconnect-Reason Tariff-Management 12
+VALUE Shiva-Disconnect-Reason Backup 13
+
+# Shiva Function Values
+
+VALUE Shiva-Function Unknown 0
+VALUE Shiva-Function Dialin 1
+VALUE Shiva-Function Dialout 2
+VALUE Shiva-Function Lan-To-Lan 3
+
+END-VENDOR Shiva
diff --git a/share/dictionary.siemens b/share/dictionary.siemens
new file mode 100644
index 0000000..5d04502
--- /dev/null
+++ b/share/dictionary.siemens
@@ -0,0 +1,28 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Siemens
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR Siemens 4329
+
+BEGIN-VENDOR Siemens
+
+ATTRIBUTE Siemens-URL-Redirection 1 string
+ATTRIBUTE Siemens-AP-Name 2 string
+ATTRIBUTE Siemens-AP-Serial 3 string
+ATTRIBUTE Siemens-VNS-Name 4 string
+ATTRIBUTE Siemens-SSID 5 string
+ATTRIBUTE Siemens-BSS-MAC 6 string
+ATTRIBUTE Siemens-Policy-Name 7 string
+ATTRIBUTE Siemens-Topology-Name 8 string
+ATTRIBUTE Siemens-Ingress-RC-Name 9 string
+ATTRIBUTE Siemens-Egress-RC-Name 10 string
+
+END-VENDOR Siemens
diff --git a/share/dictionary.slipstream b/share/dictionary.slipstream
new file mode 100644
index 0000000..6274662
--- /dev/null
+++ b/share/dictionary.slipstream
@@ -0,0 +1,21 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# For Slipstream dialup accelerator servers
+# Created based on
+# slipstream_sp_6.0_installation_and_configuration_guide.pdf
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR Slipstream 7000
+
+BEGIN-VENDOR Slipstream
+
+ATTRIBUTE Slipstream-Auth 1 string
+
+END-VENDOR Slipstream
diff --git a/share/dictionary.sofaware b/share/dictionary.sofaware
new file mode 100644
index 0000000..0eec6e9
--- /dev/null
+++ b/share/dictionary.sofaware
@@ -0,0 +1,39 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Sofaware VPN-1 Edge from Sofaware (Check Point appliance).
+#
+# Values are strings, rather than real VALUEs.
+#
+# SofaWare-Admin : "none" / "readonly" / "readwrite"
+# Users have no, read-only or read-write access to the
+# appliance's configuration interface (Web / SSH)
+#
+# SofaWare-VPN : `true" / "false"
+# User can / cannot connect the VPN
+#
+# SofaWare-Hotspot : "true" / "false"
+# The account can be used for authentication on the
+# Hotspot web page (may be required before accessing
+# the Internet)
+#
+# SofaWare-UFP : "true" / "false"
+# The user can /cannot overwrite the URL Filtering policy
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR SofaWare 6983
+
+BEGIN-VENDOR SofaWare
+
+ATTRIBUTE SofaWare-Admin 1 string
+ATTRIBUTE SofaWare-VPN 2 string
+ATTRIBUTE SofaWare-Hotspot 3 string
+ATTRIBUTE SofaWare-UFP 4 string
+
+END-VENDOR SofaWare
diff --git a/share/dictionary.softbank b/share/dictionary.softbank
new file mode 100644
index 0000000..9ee8c03
--- /dev/null
+++ b/share/dictionary.softbank
@@ -0,0 +1,32 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors#
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+#############################################################################
+#
+# Softbank VSAs
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR SoftBank 22197
+
+BEGIN-VENDOR SoftBank
+
+ATTRIBUTE SoftBank-BB-Unit-MAC 1 string
+ATTRIBUTE SoftBank-BB-Unit-Manufacturer 2 string
+ATTRIBUTE SoftBank-BB-Unit-Model 3 string
+ATTRIBUTE SoftBank-BB-Unit-HW-Revision 4 string
+
+ATTRIBUTE SoftBank-TFTP-Config-Server 185 ipaddr
+ATTRIBUTE SoftBank-TFTP-Config-File 186 string
+ATTRIBUTE SoftBank-DNS-IPv6-Primary 198 ipv6addr
+ATTRIBUTE SoftBank-DNS-IPv6-Secondary 199 ipv6addr
+ATTRIBUTE SoftBank-Syslog-Server 201 ipv6addr
+ATTRIBUTE SoftBank-SNTP-Server 203 ipv6addr
+ATTRIBUTE SoftBank-IPv4-Tunnel-Local-Address 204 ipaddr
+ATTRIBUTE SoftBank-IPv4-Tunnel-Endpoint 207 ipv6addr
+ATTRIBUTE SoftBank-RouteInfo-Server 215 string
+
+END-VENDOR SoftBank
diff --git a/share/dictionary.sonicwall b/share/dictionary.sonicwall
new file mode 100644
index 0000000..8f4cb0c
--- /dev/null
+++ b/share/dictionary.sonicwall
@@ -0,0 +1,64 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Sonicwall Firewall dictionary
+#
+# $Id$
+#
+
+VENDOR SonicWall 8741
+
+# Backwards compatibility.
+BEGIN-VENDOR SonicWall
+
+ATTRIBUTE SS3-Firewall-User-Privilege 1 integer
+
+# New names.
+ATTRIBUTE SonicWall-User-Privilege 1 integer
+VALUE SonicWall-User-Privilege Remote-Access 1 # deprecated
+VALUE SonicWall-User-Privilege Bypass-Filters 2
+VALUE SonicWall-User-Privilege VPN-Client-Access 3 # standard
+VALUE SonicWall-User-Privilege Access-To-VPN 4 # standard
+VALUE SonicWall-User-Privilege Limited-Management 5
+VALUE SonicWall-User-Privilege L2TP-Client-Access 6 # standard
+VALUE SonicWall-User-Privilege Wireless-Guest 7 # standard
+VALUE SonicWall-User-Privilege Wireless-Add-ACL 8
+VALUE SonicWall-User-Privilege Internet-Access 9 # standard
+
+# Those values indicated as "standard" are applicable only on a SonicWall
+# firewall running standard firmware and not on one running enhanced firmware.
+
+#
+# This attribute is to use in place of SonicWall-User-Privilege with RADIUS
+# servers that allow only one instance of a Vendor-Specific attribute to be
+# set (such as the ACE Server from RSA). Note that it is commented out in this
+# file because it is not needed in any servers that support multiple VSA's.
+#
+# The value of this attribute is a text string giving a comma-separated list
+# of one or more privileges, each corresponding to a value of the
+# SonicWall-User-Privilege attribute above (and note that some are applicable
+# only on a SonicWall firewall running standard firmware as indicated above):
+# "BF,VC,VA,LM,LA,WG,WA,IA"
+# "RA" for "Remote-Access" is now deprecated.
+# ATTRIBUTE SonicWall-User-Privileges 2 string SonicWall
+
+# Multiple of these can be set for a user, each specifying the name of a
+# user group to which that user has membership. Note that this can
+# alternatively be achieved by use of the Filter-Id attribute.
+# This is applicable only on a SonicWall firewall running enhanced firmware.
+#
+ATTRIBUTE SonicWall-User-Group 3 string
+
+# This attribute is to use in place of SonicWall-User-Group with RADIUS
+# servers that allow only one instance of a Vendor-Specific attribute to be
+# set (such as the ACE Server from RSA). Note that it is commented out in this
+# file because it is not needed in any servers that support multiple VSA's.
+#
+# The value of this attribute is a text string giving a comma-separated list
+# of the names of one or more user groups to which that user has membership.
+# This is applicable only on a SonicWall firewall running enhanced firmware.
+#
+# ATTRIBUTE SonicWall-User-Groups 4 string SonicWall.
+
+END-VENDOR SonicWall
diff --git a/share/dictionary.springtide b/share/dictionary.springtide
new file mode 100644
index 0000000..8a08bfa
--- /dev/null
+++ b/share/dictionary.springtide
@@ -0,0 +1,34 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# SpringTide VSAs
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR SpringTide 3551
+
+BEGIN-VENDOR SpringTide
+
+ATTRIBUTE ST-Acct-VC-Connection-Id 1 string
+ATTRIBUTE ST-Service-Name 2 string
+ATTRIBUTE ST-Service-Domain 3 integer
+ATTRIBUTE ST-Policy-Name 4 string
+ATTRIBUTE ST-Primary-DNS-Server 5 ipaddr
+ATTRIBUTE ST-Secondary-DNS-Server 6 ipaddr
+ATTRIBUTE ST-Primary-NBNS-Server 7 ipaddr
+ATTRIBUTE ST-Secondary-NBNS-Server 8 ipaddr
+ATTRIBUTE ST-Physical-Port 9 integer
+ATTRIBUTE ST-Physical-Slot 10 integer
+ATTRIBUTE ST-Virtual-Path-ID 11 integer
+ATTRIBUTE ST-Virtual-Circuit-ID 12 integer
+ATTRIBUTE ST-Realm-Name 13 string
+ATTRIBUTE ST-IPSec-Pfs-Group 14 integer
+ATTRIBUTE ST-IPSec-Client-Firewall 15 integer
+ATTRIBUTE ST-IPSec-Client-Subnet 16 string
+
+END-VENDOR SpringTide
diff --git a/share/dictionary.starent b/share/dictionary.starent
new file mode 100644
index 0000000..42ce62c
--- /dev/null
+++ b/share/dictionary.starent
@@ -0,0 +1,1383 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Starent dictionary
+# http://www.starentnetworks.com/
+#
+# Starent dictionary with 2 bytes tag and 2 byte length.
+#
+# The source of this document is a Cisco Manual:
+# "Cisco ASR 5000 Series AAA and GTP Interface Administration and
+# Reference Release 12.x (Last Updated May 31, 2011)"
+#
+# This document is available at:
+# http://www.cisco.com/en/US/products/ps11072/products_implementation_design_guides_list.html
+#
+##############################################################################
+
+VENDOR Starent 8164 format=2,2
+
+BEGIN-VENDOR Starent
+
+ATTRIBUTE SN-VPN-ID 1 integer
+ATTRIBUTE SN-VPN-Name 2 string
+ATTRIBUTE SN-Disconnect-Reason 3 integer
+ATTRIBUTE SN-PPP-Progress-Code 4 integer
+ATTRIBUTE SN-Primary-DNS-Server 5 ipaddr
+ATTRIBUTE SN-Secondary-DNS-Server 6 ipaddr
+ATTRIBUTE SN-Re-CHAP-Interval 7 integer
+ATTRIBUTE SN-IP-Pool-Name 8 string
+ATTRIBUTE SN-PPP-Data-Compression 9 integer
+ATTRIBUTE SN-IP-Filter-In 10 string
+ATTRIBUTE SN-IP-Filter-Out 11 string
+ATTRIBUTE SN-Local-IP-Address 13 ipaddr
+ATTRIBUTE SN-IP-Source-Validation 14 integer
+ATTRIBUTE SN-PPP-Outbound-Password 15 string
+ATTRIBUTE SN-PPP-Keepalive 16 integer
+ATTRIBUTE SN-IP-In-ACL 17 string
+ATTRIBUTE SN-IP-Out-ACL 18 string
+ATTRIBUTE SN-PPP-Data-Compression-Mode 19 integer
+ATTRIBUTE SN-Subscriber-Permission 20 integer
+ATTRIBUTE SN-Admin-Permission 21 integer
+ATTRIBUTE SN-Simultaneous-SIP-MIP 22 integer
+ATTRIBUTE SN-Min-Compress-Size 23 integer
+ATTRIBUTE SN-Service-Type 24 integer
+ATTRIBUTE SN-DNS-Proxy-Use-Subscr-Addr 25 integer
+ATTRIBUTE SN-Tunnel-Password 26 octets
+ATTRIBUTE SN-Tunnel-Load-Balancing 27 integer
+ATTRIBUTE SN-MN-HA-Timestamp-Tolerance 30 integer
+ATTRIBUTE SN-Prepaid-Compressed-Count 31 integer
+ATTRIBUTE SN-Prepaid-Inbound-Octets 32 integer
+ATTRIBUTE SN-Prepaid-Outbound-Octets 33 integer
+ATTRIBUTE SN-Prepaid-Total-Octets 34 integer
+ATTRIBUTE SN-Prepaid-Timeout 35 integer
+ATTRIBUTE SN-Prepaid-Watermark 36 integer
+ATTRIBUTE SN-NAI-Construction-Domain 37 string
+ATTRIBUTE SN-Tunnel-ISAKMP-Crypto-Map 38 string
+ATTRIBUTE SN-Tunnel-ISAKMP-Secret 39 string
+ATTRIBUTE SN-Ext-Inline-Srvr-Context 41 string
+ATTRIBUTE SN-L3-to-L2-Tun-Addr-Policy 43 integer
+ATTRIBUTE SN-Long-Duration-Timeout 44 integer
+ATTRIBUTE SN-Long-Duration-Action 45 integer
+ATTRIBUTE SN-PDSN-Handoff-Req-IP-Addr 46 integer
+ATTRIBUTE SN-HA-Send-DNS-ADDRESS 47 integer
+ATTRIBUTE SN-MIP-Send-Term-Verification 48 integer
+ATTRIBUTE SN-Data-Tunnel-Ignore-DF-Bit 49 integer
+ATTRIBUTE SN-MIP-AAA-Assign-Addr 50 integer
+ATTRIBUTE SN-Proxy-MIP 52 integer
+ATTRIBUTE SN-MIP-Match-AAA-Assign-Addr 51 integer
+ATTRIBUTE SN-IP-Alloc-Method 53 integer
+ATTRIBUTE SN-Gratuitous-ARP-Aggressive 54 integer
+ATTRIBUTE SN-Ext-Inline-Srvr-Up-Addr 55 ipaddr
+ATTRIBUTE SN-Ext-Inline-Srvr-Down-Addr 56 ipaddr
+ATTRIBUTE SN-Ext-Inline-Srvr-Preference 57 integer
+ATTRIBUTE SN-Ext-Inline-Srvr-Up-VLAN 58 octets
+ATTRIBUTE SN-Ext-Inline-Srvr-Down-VLAN 59 octets
+ATTRIBUTE SN-IP-Hide-Service-Address 60 integer
+ATTRIBUTE SN-PPP-Outbound-Username 61 string
+ATTRIBUTE SN-GTP-Version 62 integer
+ATTRIBUTE SN-Access-link-IP-Frag 63 integer
+ATTRIBUTE SN-Subscriber-Accounting 64 integer
+ATTRIBUTE SN-Nw-Reachability-Server-Name 65 string
+ATTRIBUTE SN-Subscriber-IP-Hdr-Neg-Mode 67 integer
+ATTRIBUTE SN-GGSN-MIP-Required 68 integer
+ATTRIBUTE SN-Subscriber-Acct-Start 69 integer
+ATTRIBUTE SN-Subscriber-Acct-Interim 70 integer
+ATTRIBUTE SN-Subscriber-Acct-Stop 71 integer
+ATTRIBUTE SN-QoS-Tp-Dnlk 73 integer
+ATTRIBUTE SN-Tp-Dnlk-Committed-Data-Rate 74 integer
+ATTRIBUTE SN-Tp-Dnlk-Peak-Data-Rate 75 integer
+ATTRIBUTE SN-Tp-Dnlk-Burst-Size 76 integer
+ATTRIBUTE SN-Tp-Dnlk-Exceed-Action 77 integer
+ATTRIBUTE SN-Tp-Dnlk-Violate-Action 78 integer
+ATTRIBUTE SN-QoS-Tp-Uplk 79 integer
+ATTRIBUTE SN-Tp-Uplk-Committed-Data-Rate 80 integer
+ATTRIBUTE SN-Tp-Uplk-Peak-Data-Rate 81 integer
+ATTRIBUTE SN-Tp-Uplk-Burst-Size 82 integer
+ATTRIBUTE SN-Tp-Uplk-Exceed-Action 83 integer
+ATTRIBUTE SN-Tp-Uplk-Violate-Action 84 integer
+ATTRIBUTE SN-Subscriber-IP-TOS-Copy 85 integer
+ATTRIBUTE SN-QoS-Conversation-Class 86 octets
+ATTRIBUTE SN-QoS-Streaming-Class 87 octets
+ATTRIBUTE SN-QoS-Interactive1-Class 88 octets
+ATTRIBUTE SN-QoS-Interactive2-Class 89 octets
+ATTRIBUTE SN-QoS-Interactive3-Class 90 octets
+ATTRIBUTE SN-QoS-Background-Class 91 octets
+ATTRIBUTE SN-PPP-NW-Layer-IPv4 92 integer
+ATTRIBUTE SN-PPP-NW-Layer-IPv6 93 integer
+ATTRIBUTE SN-Virtual-APN-Name 94 string
+ATTRIBUTE SN-PPP-Accept-Peer-v6Ifid 95 integer
+ATTRIBUTE SN-IPv6-rtr-advt-interval 96 integer
+ATTRIBUTE SN-IPv6-num-rtr-advt 97 integer
+ATTRIBUTE SN-NPU-Qos-Priority 98 integer
+ATTRIBUTE SN-MN-HA-Hash-Algorithm 99 integer
+ATTRIBUTE SN-Subscriber-Acct-Rsp-Action 100 integer
+ATTRIBUTE SN-IPv6-Primary-DNS 101 ipv6addr
+ATTRIBUTE SN-IPv6-Secondary-DNS 102 octets
+ATTRIBUTE SN-IPv6-Egress-Filtering 103 integer
+ATTRIBUTE SN-Mediation-VPN-Name 104 string
+ATTRIBUTE SN-Mediation-Acct-Rsp-Action 105 integer
+ATTRIBUTE SN-Home-Sub-Use-GGSN 106 integer
+ATTRIBUTE SN-Visiting-Sub-Use-GGSN 107 integer
+ATTRIBUTE SN-Roaming-Sub-Use-GGSN 108 integer
+ATTRIBUTE SN-Home-Profile 109 integer
+ATTRIBUTE SN-IP-Src-Validation-Drop-Limit 110 integer
+ATTRIBUTE SN-QoS-Class-Conversational-PHB 111 integer
+ATTRIBUTE SN-QoS-Class-Streaming-PHB 112 integer
+ATTRIBUTE SN-QoS-Class-Background-PHB 113 integer
+ATTRIBUTE SN-QoS-Class-Interactive-1-PHB 114 integer
+ATTRIBUTE SN-QoS-Class-Interactive-2-PHB 115 integer
+ATTRIBUTE SN-QoS-Class-Interactive-3-PHB 116 integer
+ATTRIBUTE SN-Visiting-Profile 117 integer
+ATTRIBUTE SN-Roaming-Profile 118 integer
+ATTRIBUTE SN-Home-Behavior 119 integer
+ATTRIBUTE SN-Visiting-Behavior 120 integer
+ATTRIBUTE SN-Roaming-Behavior 121 integer
+ATTRIBUTE SN-Internal-SM-Index 122 integer
+ATTRIBUTE SN-Mediation-Enabled 123 integer
+ATTRIBUTE SN-IPv6-Sec-Pool 124 string
+ATTRIBUTE SN-IPv6-Sec-Prefix 125 octets
+ATTRIBUTE SN-IPv6-DNS-Proxy 126 integer
+ATTRIBUTE SN-Subscriber-Nexthop-Address 127 integer
+ATTRIBUTE SN-Prepaid 128 integer
+ATTRIBUTE SN-Prepaid-Preference 129 integer
+ATTRIBUTE SN-PPP-Always-On-Vse 130 integer
+ATTRIBUTE SN-Voice-Push-List-Name 131 string
+ATTRIBUTE SN-Unclassify-List-Name 132 string
+ATTRIBUTE SN-Subscriber-No-Interims 133 integer
+ATTRIBUTE SN-Permit-User-Mcast-PDUs 134 integer
+ATTRIBUTE SN-Prepaid-Final-Duration-Alg 135 integer
+ATTRIBUTE SN-IPv6-Min-Link-MTU 136 integer
+ATTRIBUTE SN-Charging-VPN-Name 137 string
+ATTRIBUTE SN-Chrg-Char-Selection-Mode 138 integer
+ATTRIBUTE SN-Cause-For-Rec-Closing 139 integer
+ATTRIBUTE SN-Change-Condition 140 integer
+ATTRIBUTE SN-Dynamic-Addr-Alloc-Ind-Flag 141 octets
+ATTRIBUTE SN-Ntk-Initiated-Ctx-Ind-Flag 142 octets
+ATTRIBUTE SN-Ntk-Session-Disconnect-Flag 143 integer
+ATTRIBUTE SN-Enable-QoS-Renegotiation 144 integer
+ATTRIBUTE SN-QoS-Renegotiation-Timeout 145 integer
+ATTRIBUTE SN-QoS-Negotiated 147 string
+ATTRIBUTE SN-Mediation-No-Interims 146 integer
+ATTRIBUTE SN-Primary-NBNS-Server 148 ipaddr
+ATTRIBUTE SN-Secondary-NBNS-Server 149 ipaddr
+ATTRIBUTE SN-IP-Header-Compression 150 integer
+ATTRIBUTE SN-Mode 151 integer
+#ATTRIBUTE SN-ROHC-Mode 151 integer
+ATTRIBUTE SN-Assigned-VLAN-ID 152 short
+ATTRIBUTE SN-Direction 153 integer
+ATTRIBUTE SN-MIP-HA-Assignment-Table 154 string
+ATTRIBUTE SN-Tun-Addr-Policy 156 integer
+ATTRIBUTE SN-DHCP-Lease-Expiry-Policy 157 integer
+ATTRIBUTE SN-Subscriber-Template-Name 158 string
+ATTRIBUTE SN-Subs-IMSA-Service-Name 159 string
+ATTRIBUTE SN-Traffic-Group 161 integer
+ATTRIBUTE SN-Rad-APN-Name 162 octets
+ATTRIBUTE SN-MIP-Send-Ancid 163 integer
+ATTRIBUTE SN-MIP-Send-Imsi 164 integer
+ATTRIBUTE SN-MIP-Dual-Anchor 165 integer
+ATTRIBUTE SN-MIP-ANCID 166 octets
+ATTRIBUTE SN-IMS-AM-Address 167 ipaddr
+ATTRIBUTE SN-IMS-AM-Domain-Name 168 octets
+ATTRIBUTE SN-Service-Address 169 ipaddr
+ATTRIBUTE SN-PDIF-MIP-Required 170 integer
+ATTRIBUTE SN-FMC-Location 171 octets
+ATTRIBUTE SN-PDIF-MIP-Release-TIA 172 integer
+ATTRIBUTE SN-PDIF-MIP-Simple-IP-Fallback 173 integer
+ATTRIBUTE SN-Tunnel-Gn 174 integer
+ATTRIBUTE SN-MIP-Reg-Lifetime-Realm 175 integer
+ATTRIBUTE SN-Ecs-Data-Volume 176 octets
+ATTRIBUTE SN-QoS-Traffic-Policy 177 octets
+ATTRIBUTE SN-ANID 178 octets
+ATTRIBUTE SN-PPP-Reneg-Disc 187 integer
+ATTRIBUTE SN-MIP-Send-Correlation-Info 188 integer
+ATTRIBUTE SN-PDSN-Correlation-Id 189 octets
+ATTRIBUTE SN-PDSN-NAS-Id 190 string
+ATTRIBUTE SN-PDSN-NAS-IP-Address 191 ipaddr
+ATTRIBUTE SN-Subscriber-Acct-Mode 192 integer
+ATTRIBUTE SN-IP-In-Plcy-Grp 193 string
+ATTRIBUTE SN-IP-Out-Plcy-Grp 194 string
+ATTRIBUTE SN-IP-Source-Violate-No-Acct 196 integer
+ATTRIBUTE SN-Firewall-Enabled 198 integer
+ATTRIBUTE SNA-PPP-Unfr-data-In-Oct 200 integer
+ATTRIBUTE SNA-PPP-Unfr-data-Out-Oct 201 integer
+ATTRIBUTE SNA-PPP-Unfr-Data-In-Gig 202 integer
+ATTRIBUTE SNA-PPP-Unfr-Data-Out-Gig 203 integer
+ATTRIBUTE SN-Admin-Expiry 204 integer
+ATTRIBUTE SNA-Input-Gigawords 206 integer
+ATTRIBUTE SNA-Output-Gigawords 207 integer
+ATTRIBUTE SN-DNS-Proxy-Intercept-List 214 string
+ATTRIBUTE SN-Subscriber-Class 219 integer
+ATTRIBUTE SN-CFPolicy-ID 220 integer
+ATTRIBUTE SN-Subs-VJ-Slotid-Cmp-Neg-Mode 221 integer
+ATTRIBUTE SN-Primary-DCCA-Peer 223 string
+ATTRIBUTE SN-Secondary-DCCA-Peer 224 string
+ATTRIBUTE SN-Subs-Acc-Flow-Traffic-Valid 225 integer
+ATTRIBUTE SN-Acct-Input-Packets-Dropped 226 integer
+ATTRIBUTE SN-Acct-Output-Packets-Dropped 227 integer
+ATTRIBUTE SN-Acct-Input-Octets-Dropped 228 integer64
+ATTRIBUTE SN-Acct-Output-Octets-Dropped 229 integer64
+ATTRIBUTE SN-Acct-Input-Giga-Dropped 230 integer
+ATTRIBUTE SN-Acct-Output-Giga-Dropped 231 integer
+ATTRIBUTE SN-Overload-Disc-Connect-Time 233 integer
+ATTRIBUTE SN-Overload-Disconnect 235 integer
+ATTRIBUTE SN-Radius-Returned-Username 236 integer
+ATTRIBUTE SN-ROHC-Profile-Name 238 string
+ATTRIBUTE SN-Firewall-Policy 239 octets
+ATTRIBUTE SN-Transparent-Data 247 octets
+ATTRIBUTE SN-MS-ISDN 248 octets
+ATTRIBUTE SN-Routing-Area-Id 249 string
+ATTRIBUTE SN-Rulebase 250 string
+ATTRIBUTE SN-Call-Id 251 integer
+ATTRIBUTE SN-IMSI 252 octets
+ATTRIBUTE SN-Long-Duration-Notification 253 integer
+ATTRIBUTE SN-SIP-Method 254 integer
+ATTRIBUTE SN-Event 255 string
+ATTRIBUTE SN-Role-Of-Node 256 integer
+ATTRIBUTE SN-Session-Id 257 string
+ATTRIBUTE SN-SIP-Request-Time-Stamp 258 string
+ATTRIBUTE SN-SIP-Response-Time-Stamp 259 string
+ATTRIBUTE SN-IMS-Charging-Identifier 260 string
+ATTRIBUTE SN-Originating-IOI 261 string
+ATTRIBUTE SN-Terminating-IOI 262 string
+ATTRIBUTE SN-SDP-Session-Description 263 string
+ATTRIBUTE SN-GGSN-Address 264 ipaddr
+ATTRIBUTE SN-Sec-IP-Pool-Name 265 string
+ATTRIBUTE SN-Authorised-Qos 266 string
+ATTRIBUTE SN-Cause-Code 267 integer
+ATTRIBUTE SN-Node-Functionality 268 integer
+ATTRIBUTE SN-Is-Unregistered-Subscriber 269 string
+ATTRIBUTE SN-Content-Type 270 string
+ATTRIBUTE SN-Content-Length 271 string
+ATTRIBUTE SN-Content-Disposition 272 string
+ATTRIBUTE SN-CSCF-Rf-SDP-Media-Components 273 octets
+ATTRIBUTE SN-ROHC-Flow-Marking-Mode 274 integer
+# Attribute 275 has three clashing values.
+# ATTRIBUTE SN-Inactivity-Time 275 integer
+ATTRIBUTE SN-CSCF-App-Server-Info 275 octets
+ATTRIBUTE SN-ISC-Template-Name 276 string
+ATTRIBUTE SN-CF-Forward-Unconditional 277 string
+ATTRIBUTE SN-CF-Forward-No-Answer 278 string
+ATTRIBUTE SN-CF-Forward-Busy-Line 279 string
+ATTRIBUTE SN-CF-Forward-Not-Regd 280 string
+ATTRIBUTE SN-CF-Follow-Me 281 string
+ATTRIBUTE SN-CF-CId-Display 282 integer
+ATTRIBUTE SN-CF-CId-Display-Blocked 283 integer
+ATTRIBUTE SN-CF-Call-Waiting 284 integer
+ATTRIBUTE SN-CF-Call-Transfer 285 integer
+ATTRIBUTE SN-Cscf-Subscriber-Ip-Address 287 ipaddr
+ATTRIBUTE SN-Software-Version 288 string
+ATTRIBUTE SN-Max-Sec-Contexts-Per-Subs 290 integer
+ATTRIBUTE SN-CF-Call-Local 291 integer
+ATTRIBUTE SN-CF-Call-LongDistance 292 integer
+ATTRIBUTE SN-CF-Call-International 293 integer
+ATTRIBUTE SN-CF-Call-Premium 294 integer
+ATTRIBUTE SN-CR-International-Cid 295 integer
+ATTRIBUTE SN-CR-LongDistance-Cid 296 integer
+ATTRIBUTE SN-NAT-IP-Address 297 ipaddr
+ATTRIBUTE SN-CF-Call-RoamingInternatnl 298 integer
+ATTRIBUTE SN-PDG-TTG-Required 299 integer
+ATTRIBUTE SN-Bandwidth-Policy 300 string
+ATTRIBUTE SN-Acs-Credit-Control-Group 301 string
+ATTRIBUTE SN-CBB-Policy 302 string
+ATTRIBUTE SN-QOS-HLR-Profile 303 octets
+ATTRIBUTE SN-Fast-Reauth-Username 304 octets
+ATTRIBUTE SN-Pseudonym-Username 305 octets
+ATTRIBUTE SN-WiMAX-Auth-Only 306 integer
+ATTRIBUTE SN-TrafficSelector-Class 307 integer
+ATTRIBUTE SN-DHCP-Options 309 octets
+ATTRIBUTE SN-Handoff-Indicator 310 integer
+ATTRIBUTE SN-User-Privilege 313 integer
+ATTRIBUTE SN-IPv6-Alloc-Method 314 integer
+ATTRIBUTE SN-Congestion-Mgmt-Policy 315 string
+ATTRIBUTE SN-WSG-MIP-Required 316 integer
+ATTRIBUTE SN-WSG-MIP-Release-TIA 317 integer
+ATTRIBUTE SN-WSG-MIP-Simple-IP-Fallback 318 integer
+ATTRIBUTE SN-WLAN-AP-Identifier 319 octets
+ATTRIBUTE SN-WLAN-UE-Identifier 320 octets
+
+ATTRIBUTE SNA-PPP-Ctrl-Input-Octets 1001 integer
+ATTRIBUTE SNA-PPP-Ctrl-Output-Octets 1002 integer
+ATTRIBUTE SNA-PPP-Ctrl-Input-Packets 1003 integer
+ATTRIBUTE SNA-PPP-Ctrl-Output-Packets 1004 integer
+ATTRIBUTE SNA-PPP-Framed-Input-Octets 1005 integer
+ATTRIBUTE SNA-PPP-Framed-Output-Octets 1006 integer
+ATTRIBUTE SNA-PPP-Discards-Input 1007 integer
+ATTRIBUTE SNA-PPP-Discards-Output 1008 integer
+ATTRIBUTE SNA-PPP-Errors-Input 1009 integer
+ATTRIBUTE SNA-PPP-Errors-Output 1010 integer
+ATTRIBUTE SNA-PPP-Bad-Addr 1011 integer
+ATTRIBUTE SNA-PPP-Bad-Ctrl 1012 integer
+ATTRIBUTE SNA-PPP-Packet-Too-Long 1013 integer
+ATTRIBUTE SNA-PPP-Bad-FCS 1014 integer
+ATTRIBUTE SNA-PPP-Echo-Req-Input 1015 integer
+ATTRIBUTE SNA-PPP-Echo-Req-Output 1016 integer
+ATTRIBUTE SNA-PPP-Echo-Rsp-Input 1017 integer
+ATTRIBUTE SNA-PPP-Echo-Rsp-Output 1018 integer
+ATTRIBUTE SNA-RPRRQ-Rcvd-Total 1019 integer
+ATTRIBUTE SNA-RPRRQ-Rcvd-Acc-Reg 1020 integer
+ATTRIBUTE SNA-RPRRQ-Rcvd-Acc-Dereg 1021 integer
+ATTRIBUTE SNA-RPRRQ-Rcvd-Msg-Auth-Fail 1022 integer
+ATTRIBUTE SNA-RPRRQ-Rcvd-Mis-ID 1023 integer
+ATTRIBUTE SNA-RPRRQ-Rcvd-Badly-Formed 1024 integer
+ATTRIBUTE SNA-RPRRQ-Rcvd-VID-Unsupported 1025 integer
+ATTRIBUTE SNA-RPRRQ-Rcvd-T-Bit-Not-Set 1026 integer
+ATTRIBUTE SNA-RPRAK-Rcvd-Total 1027 integer
+ATTRIBUTE SNA-RPRAK-Rcvd-Acc-Ack 1028 integer
+ATTRIBUTE SNA-RPRAK-Rcvd-Msg-Auth-Fail 1029 integer
+ATTRIBUTE SNA-RPRAK-Rcvd-Mis-ID 1030 integer
+ATTRIBUTE SNA-RP-Reg-Reply-Sent-Total 1031 integer
+ATTRIBUTE SNA-RP-Reg-Reply-Sent-Acc-Reg 1032 integer
+ATTRIBUTE SNA-RP-Reg-Reply-Sent-Acc-Dereg 1033 integer
+ATTRIBUTE SNA-RP-Reg-Reply-Sent-Bad-Req 1034 integer
+ATTRIBUTE SNA-RP-Reg-Reply-Sent-Denied 1035 integer
+ATTRIBUTE SNA-RP-Reg-Reply-Sent-Mis-ID 1036 integer
+ATTRIBUTE SNA-RP-Reg-Reply-Sent-Send-Err 1037 integer
+ATTRIBUTE SNA-RP-Reg-Upd-Sent 1038 integer
+ATTRIBUTE SNA-RP-Reg-Upd-Re-Sent 1039 integer
+ATTRIBUTE SNA-RP-Reg-Upd-Send-Err 1040 integer
+
+ATTRIBUTE SN-Proxy-MIPV6 65530 integer
+
+VALUE SN-Disconnect-Reason Not-Defined 0
+VALUE SN-Disconnect-Reason Admin-Disconnect 1
+VALUE SN-Disconnect-Reason Remote-Disconnect 2
+VALUE SN-Disconnect-Reason Local-Disconnect 3
+VALUE SN-Disconnect-Reason Disc-No-Resource 4
+VALUE SN-Disconnect-Reason Disc-Excd-Service-Limit 5
+VALUE SN-Disconnect-Reason PPP-LCP-Neg-Failed 6
+VALUE SN-Disconnect-Reason PPP-LCP-No-Response 7
+VALUE SN-Disconnect-Reason PPP-LCP-Loopback 8
+VALUE SN-Disconnect-Reason PPP-LCP-Max-Retry 9
+VALUE SN-Disconnect-Reason PPP-Echo-Failed 10
+VALUE SN-Disconnect-Reason PPP-Auth-Failed 11
+VALUE SN-Disconnect-Reason PPP-Auth-Failed-No-AAA-Resp 12
+VALUE SN-Disconnect-Reason PPP-Auth-No-Response 13
+VALUE SN-Disconnect-Reason PPP-Auth-Max-Retry 14
+VALUE SN-Disconnect-Reason Invalid-AAA-Attr 15
+VALUE SN-Disconnect-Reason Failed-User-Filter 16
+VALUE SN-Disconnect-Reason Failed-Provide-Service 17
+VALUE SN-Disconnect-Reason Invalid-IP-Address-AAA 18
+VALUE SN-Disconnect-Reason Invalid-IP-Pool-AAA 19
+VALUE SN-Disconnect-Reason PPP-IPCP-Neg-Failed 20
+VALUE SN-Disconnect-Reason PPP-IPCP-No-Response 21
+VALUE SN-Disconnect-Reason PPP-IPCP-Max-Retry 22
+VALUE SN-Disconnect-Reason PPP-No-Rem-IP-Address 23
+VALUE SN-Disconnect-Reason Inactivity-Timeout 24
+VALUE SN-Disconnect-Reason Session-Timeout 25
+VALUE SN-Disconnect-Reason Max-Data-Excd 26
+VALUE SN-Disconnect-Reason Invalid-IP-Source-Address 27
+VALUE SN-Disconnect-Reason MSID-Auth-Failed 28
+VALUE SN-Disconnect-Reason MSID-Auth-Fauiled-No-AAA-Resp 29
+VALUE SN-Disconnect-Reason A11-Max-Retry 30
+VALUE SN-Disconnect-Reason A11-Lifetime-Expired 31
+VALUE SN-Disconnect-Reason A11-Message-Integrity-Failure 32
+VALUE SN-Disconnect-Reason PPP-lcp-remote-disc 33
+VALUE SN-Disconnect-Reason Session-setup-timeout 34
+VALUE SN-Disconnect-Reason PPP-keepalive-failure 35
+VALUE SN-Disconnect-Reason Flow-add-failed 36
+VALUE SN-Disconnect-Reason Call-type-detection-failed 37
+VALUE SN-Disconnect-Reason Wrong-ipcp-params 38
+VALUE SN-Disconnect-Reason MIP-remote-dereg 39
+VALUE SN-Disconnect-Reason MIP-lifetime-expiry 40
+VALUE SN-Disconnect-Reason MIP-proto-error 41
+VALUE SN-Disconnect-Reason MIP-auth-failure 42
+VALUE SN-Disconnect-Reason MIP-reg-timeout 43
+VALUE SN-Disconnect-Reason Invalid-dest-context 44
+VALUE SN-Disconnect-Reason Source-context-removed 45
+VALUE SN-Disconnect-Reason Destination-context-removed 46
+VALUE SN-Disconnect-Reason Req-service-addr-unavailable 47
+VALUE SN-Disconnect-Reason Demux-mgr-failed 48
+VALUE SN-Disconnect-Reason Internal-error 49
+VALUE SN-Disconnect-Reason AAA-context-removed 50
+VALUE SN-Disconnect-Reason invalid-service-type 51
+VALUE SN-Disconnect-Reason mip-relay-req-failed 52
+VALUE SN-Disconnect-Reason mip-rcvd-relay-failure 53
+VALUE SN-Disconnect-Reason ppp-restart-inter-pdsn-handoff 54
+VALUE SN-Disconnect-Reason gre-key-mismatch 55
+VALUE SN-Disconnect-Reason invalid_tunnel_context 56
+VALUE SN-Disconnect-Reason no_peer_lns_address 57
+VALUE SN-Disconnect-Reason failed_tunnel_connect 58
+VALUE SN-Disconnect-Reason l2tp-tunnel-disconnect-remote 59
+VALUE SN-Disconnect-Reason l2tp-tunnel-timeout 60
+VALUE SN-Disconnect-Reason l2tp-protocol-error-remote 61
+VALUE SN-Disconnect-Reason l2tp-protocol-error-local 62
+VALUE SN-Disconnect-Reason l2tp-auth-failed-remote 63
+VALUE SN-Disconnect-Reason l2tp-auth-failed-local 64
+VALUE SN-Disconnect-Reason l2tp-try-another-lns-from-remote 65
+VALUE SN-Disconnect-Reason l2tp-no-resource-local 66
+VALUE SN-Disconnect-Reason l2tp-no-resource-remote 67
+VALUE SN-Disconnect-Reason l2tp-tunnel-disconnect-local 68
+VALUE SN-Disconnect-Reason l2tp-admin-disconnect_remote 69
+VALUE SN-Disconnect-Reason l2tpmgr-reached-max-capacity 70
+VALUE SN-Disconnect-Reason MIP-reg-revocation 71
+VALUE SN-Disconnect-Reason path-failure 72
+VALUE SN-Disconnect-Reason dhcp-relay-ip-validation-failed 73
+VALUE SN-Disconnect-Reason gtp-unknown-pdp-addr-or-pdp-type 74
+VALUE SN-Disconnect-Reason gtp-all-dynamic-pdp-addr-occupied 75
+VALUE SN-Disconnect-Reason gtp-no-memory-is-available 76
+VALUE SN-Disconnect-Reason dhcp-relay-static-ip-addr-not-allowed 77
+VALUE SN-Disconnect-Reason dhcp-no-ip-addr-allocated 78
+VALUE SN-Disconnect-Reason dhcp-ip-addr-allocation-tmr-exp 79
+VALUE SN-Disconnect-Reason dhcp-ip-validation-failed 80
+VALUE SN-Disconnect-Reason dhcp-static-addr-not-allowed 81
+VALUE SN-Disconnect-Reason dhcp-ip-addr-not-available-at-present 82
+VALUE SN-Disconnect-Reason dhcp-lease-expired 83
+VALUE SN-Disconnect-Reason lpool-ip-validation-failed 84
+VALUE SN-Disconnect-Reason lpool-static-ip-addr-not-allowed 85
+VALUE SN-Disconnect-Reason static-ip-validation-failed 86
+VALUE SN-Disconnect-Reason static-ip-addr-not-present 87
+VALUE SN-Disconnect-Reason static-ip-addr-not-allowed 88
+VALUE SN-Disconnect-Reason radius-ip-validation-failed 89
+VALUE SN-Disconnect-Reason radius-ip-addr-not-provided 90
+VALUE SN-Disconnect-Reason invalid-ip-addr-from-sgsn 91
+VALUE SN-Disconnect-Reason no-more-sessions-in-aaa 92
+VALUE SN-Disconnect-Reason ggsn-aaa-auth-req-failed 93
+VALUE SN-Disconnect-Reason conflict-in-ip-addr-assignment 94
+VALUE SN-Disconnect-Reason apn-removed 95
+VALUE SN-Disconnect-Reason credits-used-bytes-in 96
+VALUE SN-Disconnect-Reason credits-used-bytes-out 97
+VALUE SN-Disconnect-Reason credits-used-bytes-total 98
+VALUE SN-Disconnect-Reason prepaid-failed 99
+VALUE SN-Disconnect-Reason l2tp-ipsec-tunnel-failure 100
+VALUE SN-Disconnect-Reason l2tp-ipsec-tunnel-disconnected 101
+VALUE SN-Disconnect-Reason mip-ipsec-sa-inactive 102
+VALUE SN-Disconnect-Reason Long-Duration-Timeout 103
+VALUE SN-Disconnect-Reason proxy-mip-registration-failure 104
+VALUE SN-Disconnect-Reason proxy-mip-binding-update 105
+VALUE SN-Disconnect-Reason proxy-mip-inter-pdsn-handoff-require-ip-address 106
+VALUE SN-Disconnect-Reason proxy-mip-inter-pdsn-handoff-mismatched-address 107
+VALUE SN-Disconnect-Reason Local-purge 108
+VALUE SN-Disconnect-Reason failed-update-handoff 109
+VALUE SN-Disconnect-Reason closed_rp-handoff-complete 110
+VALUE SN-Disconnect-Reason closed_rp-duplicate-session 111
+VALUE SN-Disconnect-Reason closed_rp-handoff-session-not-found 112
+VALUE SN-Disconnect-Reason closed_rp-handoff-failed 113
+VALUE SN-Disconnect-Reason pcf-monitor-keep-alive-failed 114
+VALUE SN-Disconnect-Reason call-internal-reject 115
+VALUE SN-Disconnect-Reason call-restarted 116
+VALUE SN-Disconnect-Reason a11-mn-ha-auth-failure 117
+VALUE SN-Disconnect-Reason a11-badly-formed 118
+VALUE SN-Disconnect-Reason a11-t-bit-not-set 119
+VALUE SN-Disconnect-Reason a11-unsupported-vendor-id 120
+VALUE SN-Disconnect-Reason a11-mismatched-id 121
+VALUE SN-Disconnect-Reason mipha-dup-home-addr-req 122
+VALUE SN-Disconnect-Reason mipha-dup-imsi-session 123
+VALUE SN-Disconnect-Reason ha-unreachable 124
+VALUE SN-Disconnect-Reason IPSP-addr-in-use 125
+VALUE SN-Disconnect-Reason mipfa-dup-home-addr-req 126
+VALUE SN-Disconnect-Reason mipha-ip-pool-busyout 127
+VALUE SN-Disconnect-Reason inter-pdsn-handoff 128
+VALUE SN-Disconnect-Reason active-to-dormant 129
+VALUE SN-Disconnect-Reason ppp-renegotiation 130
+VALUE SN-Disconnect-Reason active-start-param-change 131
+VALUE SN-Disconnect-Reason tarrif-boundary 132
+VALUE SN-Disconnect-Reason a11-disconnect-no-active-stop 133
+VALUE SN-Disconnect-Reason nw-reachability-failed-reject 134
+VALUE SN-Disconnect-Reason nw-reachability-failed-redirect 135
+VALUE SN-Disconnect-Reason container-max-exceeded 136
+VALUE SN-Disconnect-Reason static-addr-not-allowed-in-apn 137
+VALUE SN-Disconnect-Reason static-addr-required-by-radius 138
+VALUE SN-Disconnect-Reason static-addr-not-allowed-by-radius 139
+VALUE SN-Disconnect-Reason mip-registration-dropped 140
+VALUE SN-Disconnect-Reason counter-rollover 141
+VALUE SN-Disconnect-Reason constructed-nai-auth-fail 142
+VALUE SN-Disconnect-Reason inter-pdsn-service-optimize-handoff-disabled 143
+VALUE SN-Disconnect-Reason gre-key-collision 144
+VALUE SN-Disconnect-Reason inter-pdsn-service-optimize-handoff-triggered 145
+VALUE SN-Disconnect-Reason intra-pdsn-handoff-triggered 146
+VALUE SN-Disconnect-Reason delayed-abort-timer-expired 147
+VALUE SN-Disconnect-Reason Admin-AAA-disconnect 148
+VALUE SN-Disconnect-Reason Admin-AAA-disconnect-handoff 149
+VALUE SN-Disconnect-Reason PPP-IPV6CP-Neg-Failed 150
+VALUE SN-Disconnect-Reason PPP-IPV6CP-No-Response 151
+VALUE SN-Disconnect-Reason PPP-IPV6CP-Max-Retry 152
+VALUE SN-Disconnect-Reason PPP-Restart-Invalid-source-IPV4-address 153
+VALUE SN-Disconnect-Reason a11-disconnect-handoff-no-active-stop 154
+VALUE SN-Disconnect-Reason call-restarted-inter-pdsn-handoff 155
+VALUE SN-Disconnect-Reason call-restarted-ppp-termination 156
+VALUE SN-Disconnect-Reason mipfa-resource-conflict 157
+VALUE SN-Disconnect-Reason failed-auth-with-charging-svc 158
+VALUE SN-Disconnect-Reason mipha-dup-imsi-session-purge 159
+VALUE SN-Disconnect-Reason mipha-rev-pending-newcall 160
+VALUE SN-Disconnect-Reason volume-quota-reached 161
+VALUE SN-Disconnect-Reason duration-quota-reached 162
+VALUE SN-Disconnect-Reason gtp-user-authentication-failed 163
+VALUE SN-Disconnect-Reason MIP-reg-revocation-no-lcp-term 164
+VALUE SN-Disconnect-Reason MIP-private-ip-no-rev-tunnel 165
+VALUE SN-Disconnect-Reason Invalid-Prepaid-AAA-attr-in-auth-response 166
+VALUE SN-Disconnect-Reason mipha-prepaid-reset-dynamic-newcall 167
+VALUE SN-Disconnect-Reason gre-flow-control-timeout 168
+VALUE SN-Disconnect-Reason mip-paaa-bc-query-not-found 169
+VALUE SN-Disconnect-Reason mipha-dynamic-ip-addr-not-available 170
+VALUE SN-Disconnect-Reason a11-mismatched-id-on-handoff 171
+VALUE SN-Disconnect-Reason a11-badly-formed-on-handoff 172
+VALUE SN-Disconnect-Reason a11-unsupported-vendor-id-on-handoff 173
+VALUE SN-Disconnect-Reason a11-t-bit-not-set-on-handoff 174
+VALUE SN-Disconnect-Reason MIP-reg-revocation-i-bit-on 175
+VALUE SN-Disconnect-Reason A11-RRQ-Deny-Max-Count 176
+VALUE SN-Disconnect-Reason Dormant-Transition-During-Session-Setup 177
+VALUE SN-Disconnect-Reason PPP-Rem-Reneg-Disc-Always-Cfg 178
+VALUE SN-Disconnect-Reason PPP-Rem-Reneg-Disc-NAI-MSID-Mismatch 179
+VALUE SN-Disconnect-Reason mipha-subscriber-ipsec-tunnel-down 180
+VALUE SN-Disconnect-Reason mipha-subscriber-ipsec-tunnel-failed 181
+VALUE SN-Disconnect-Reason mipha-subscriber-ipsecmgr-death 182
+VALUE SN-Disconnect-Reason flow-is-deactivated 183
+VALUE SN-Disconnect-Reason ecsv2-license-exceeded 184
+VALUE SN-Disconnect-Reason IPSG-Auth-Failed 185
+VALUE SN-Disconnect-Reason driver-initiated 186
+VALUE SN-Disconnect-Reason ims-authorization-failed 187
+VALUE SN-Disconnect-Reason service-instance-released 188
+VALUE SN-Disconnect-Reason flow-released 189
+VALUE SN-Disconnect-Reason ppp-renego-no-ha-addr 190
+VALUE SN-Disconnect-Reason intra-pdsn-handoff 191
+VALUE SN-Disconnect-Reason overload-disconnect 192
+VALUE SN-Disconnect-Reason css-service-not-found 193
+VALUE SN-Disconnect-Reason Auth-Failed 194
+VALUE SN-Disconnect-Reason dhcp-client-sent-release 195
+VALUE SN-Disconnect-Reason dhcp-client-sent-nak 196
+VALUE SN-Disconnect-Reason msid-dhcp-chaddr-mismatch 197
+VALUE SN-Disconnect-Reason link-broken 198
+VALUE SN-Disconnect-Reason prog-end-timeout 199
+VALUE SN-Disconnect-Reason qos-update-wait-timeout 200
+VALUE SN-Disconnect-Reason css-synch-cause 201
+VALUE SN-Disconnect-Reason Gtp-context-replacement 202
+VALUE SN-Disconnect-Reason PDIF-Auth-failed 203
+VALUE SN-Disconnect-Reason l2tp-unknown-apn 204
+VALUE SN-Disconnect-Reason ms-unexpected-network-reentry 205
+VALUE SN-Disconnect-Reason r6-invalid-nai 206
+VALUE SN-Disconnect-Reason eap-max-retry-reached 207
+VALUE SN-Disconnect-Reason vbm-hoa-session-disconnected 208
+VALUE SN-Disconnect-Reason vbm-voa-session-disconnected 209
+VALUE SN-Disconnect-Reason in-acl-disconnect-on-violation 210
+VALUE SN-Disconnect-Reason eap-msk-lifetime-expiry 211
+VALUE SN-Disconnect-Reason eap-msk-lifetime-too-low 212
+VALUE SN-Disconnect-Reason mipfa-inter-tech-handoff 213
+VALUE SN-Disconnect-Reason r6-max-retry-reached 214
+VALUE SN-Disconnect-Reason r6-nwexit-recd 215
+VALUE SN-Disconnect-Reason r6-dereg-req-recd 216
+VALUE SN-Disconnect-Reason r6-remote-failure 217
+VALUE SN-Disconnect-Reason r6r4-protocol-errors 218
+VALUE SN-Disconnect-Reason wimax-qos-invalid-aaa-attr 219
+VALUE SN-Disconnect-Reason npu-gre-flows-not-available 220
+VALUE SN-Disconnect-Reason r4-max-retry-reached 221
+VALUE SN-Disconnect-Reason r4-nwexit-recd 222
+VALUE SN-Disconnect-Reason r4-dereg-req-recd 223
+VALUE SN-Disconnect-Reason r4-remote-failure 224
+VALUE SN-Disconnect-Reason ims-authorization-revoked 225
+VALUE SN-Disconnect-Reason ims-authorization-released 226
+VALUE SN-Disconnect-Reason ims-auth-decision-invalid 227
+VALUE SN-Disconnect-Reason mac-addr-validation-failed 228
+VALUE SN-Disconnect-Reason excessive-wimax-pd-flows-cfgd 229
+VALUE SN-Disconnect-Reason sgsn-canc-loc-sub 230
+VALUE SN-Disconnect-Reason sgsn-canc-loc-upd 231
+VALUE SN-Disconnect-Reason sgsn-mnr-exp 232
+VALUE SN-Disconnect-Reason sgsn-ident-fail 233
+VALUE SN-Disconnect-Reason sgsn-sec-fail 234
+VALUE SN-Disconnect-Reason sgsn-auth-fail 235
+VALUE SN-Disconnect-Reason sgsn-glu-fail 236
+VALUE SN-Disconnect-Reason sgsn-imp-det 237
+VALUE SN-Disconnect-Reason sgsn-smgr-purge 238
+VALUE SN-Disconnect-Reason sgsn-subs-handed-to-peer 239
+VALUE SN-Disconnect-Reason sgsn-dns-fail-inter-rau 240
+VALUE SN-Disconnect-Reason sgsn-cont-rsp-fail 241
+VALUE SN-Disconnect-Reason sgsn-hlr-not-found-for-imsi 242
+VALUE SN-Disconnect-Reason sgsn-ms-init-det 243
+VALUE SN-Disconnect-Reason sgsn-opr-policy-fail 244
+VALUE SN-Disconnect-Reason sgsn-duplicate-context 245
+VALUE SN-Disconnect-Reason hss-profile-update-failed 246
+VALUE SN-Disconnect-Reason sgsn-no-pdp-activated 247
+VALUE SN-Disconnect-Reason asnpc-idle-mode-timeout 248
+VALUE SN-Disconnect-Reason asnpc-idle-mode-exit 249
+VALUE SN-Disconnect-Reason asnpc-idle-mode-auth-failed 250
+VALUE SN-Disconnect-Reason asngw-invalid-qos-configuration 251
+VALUE SN-Disconnect-Reason sgsn-dsd-allgprswithdrawn 252
+VALUE SN-Disconnect-Reason r6-pmk-key-change-failure 253
+VALUE SN-Disconnect-Reason sgsn-illegal-me 254
+VALUE SN-Disconnect-Reason sess-termination-timeout 255
+VALUE SN-Disconnect-Reason sgsn-sai-fail 256
+VALUE SN-Disconnect-Reason sgsn-rnc-removal 257
+VALUE SN-Disconnect-Reason sgsn-rai-removal 258
+VALUE SN-Disconnect-Reason sgsn-init-deact 259
+VALUE SN-Disconnect-Reason ggsn-init-deact 260
+VALUE SN-Disconnect-Reason hlr-init-deact 261
+VALUE SN-Disconnect-Reason ms-init-deact 262
+VALUE SN-Disconnect-Reason sgsn-detach-init-deact 263
+VALUE SN-Disconnect-Reason sgsn-rab-rel-init-deact 264
+VALUE SN-Disconnect-Reason sgsn-iu-rel-init-deact 265
+VALUE SN-Disconnect-Reason sgsn-gtpu-path-failure 266
+VALUE SN-Disconnect-Reason sgsn-gtpc-path-failure 267
+VALUE SN-Disconnect-Reason sgsn-local-handoff-init-deact 268
+VALUE SN-Disconnect-Reason sgsn-remote-handoff-init-deact 269
+VALUE SN-Disconnect-Reason sgsn-gtp-no-resource 270
+VALUE SN-Disconnect-Reason sgsn-rnc-no-resource 271
+VALUE SN-Disconnect-Reason sgsn-odb-init-deact 272
+VALUE SN-Disconnect-Reason sgsn-invalid-ti 273
+VALUE SN-Disconnect-Reason sgsn-ggsn-ctxt-non-existent 274
+VALUE SN-Disconnect-Reason sgsn-apn-restrict-vio 275
+VALUE SN-Disconnect-Reason sgsn-regular-deact 276
+VALUE SN-Disconnect-Reason sgsn-abnormal-deact 277
+VALUE SN-Disconnect-Reason sgsn-actv-rejected-by-peer 278
+VALUE SN-Disconnect-Reason sgsn-err-ind 279
+VALUE SN-Disconnect-Reason asngw-non-anchor-prohibited 280
+VALUE SN-Disconnect-Reason asngw-im-entry-prohibited 281
+VALUE SN-Disconnect-Reason session-idle-mode-entry-timeout 282
+VALUE SN-Disconnect-Reason session-idle-mode-exit-timeout 283
+VALUE SN-Disconnect-Reason asnpc-ms-power-down-nwexit 284
+VALUE SN-Disconnect-Reason asnpc-r4-nwexit-recd 285
+VALUE SN-Disconnect-Reason sgsn-iu-rel-before-call-est 286
+VALUE SN-Disconnect-Reason ikev2-subscriber-ipsecmgr-death 287
+VALUE SN-Disconnect-Reason All-dynamic-pool-addr-occupied 288
+VALUE SN-Disconnect-Reason mip6ha-ip-addr-not-available 289
+VALUE SN-Disconnect-Reason bs-monitor-keep-alive-failed 290
+VALUE SN-Disconnect-Reason sgsn-att-in-reg-state 291
+VALUE SN-Disconnect-Reason sgsn-inbound-srns-in-reg-state 292
+VALUE SN-Disconnect-Reason dt-ggsn-tun-reestablish-failed 293
+VALUE SN-Disconnect-Reason sgsn-unknown-pdp 294
+VALUE SN-Disconnect-Reason sgsn-pdp-auth-failure 295
+VALUE SN-Disconnect-Reason sgsn-duplicate-pdp-context 296
+VALUE SN-Disconnect-Reason sgsn-no-rsp-from-ggsn 297
+VALUE SN-Disconnect-Reason sgsn-failure-rsp-from-ggsn 298
+VALUE SN-Disconnect-Reason sgsn-apn-unknown 299
+VALUE SN-Disconnect-Reason sgsn-serv-req-init-deact 300
+VALUE SN-Disconnect-Reason sgsn-attach-on-attch-init-abort 301
+VALUE SN-Disconnect-Reason sgsn-iu-rel-in-israu-init-abort 302
+VALUE SN-Disconnect-Reason sgsn-smgr-init-abort 303
+VALUE SN-Disconnect-Reason sgsn-mm-ctx-cleanup-init-abort 304
+VALUE SN-Disconnect-Reason sgsn-unknown-abort 305
+VALUE SN-Disconnect-Reason sgsn-guard-timeout-abort 306
+VALUE SN-Disconnect-Reason vpn-bounce-dhcpip-validate-req 307
+VALUE SN-Disconnect-Reason mipv6-id-mismatch 308
+VALUE SN-Disconnect-Reason aaa-session-id-not-found 309
+VALUE SN-Disconnect-Reason x1-max-retry-reached 310
+VALUE SN-Disconnect-Reason x1-nwexit-recd 311
+VALUE SN-Disconnect-Reason x1-dereg-req-recd 312
+VALUE SN-Disconnect-Reason x1-remote-failure 313
+VALUE SN-Disconnect-Reason x1x2-protocol-errors 314
+VALUE SN-Disconnect-Reason x2-max-retry-reached 315
+VALUE SN-Disconnect-Reason x2-nwexit-recd 316
+VALUE SN-Disconnect-Reason x2-dereg-req-recd 317
+VALUE SN-Disconnect-Reason x2-remote-failure 318
+VALUE SN-Disconnect-Reason x1-pmk-key-change-failure 319
+VALUE SN-Disconnect-Reason sa-rekeying-failure 320
+VALUE SN-Disconnect-Reason sess-sleep-mode-entry-timeout 321
+VALUE SN-Disconnect-Reason phsgw-non-anchor-prohibited 322
+VALUE SN-Disconnect-Reason asnpc-pc-relocation-failed 323
+VALUE SN-Disconnect-Reason asnpc-pc-relocation 324
+VALUE SN-Disconnect-Reason auth_policy_mismatch 325
+VALUE SN-Disconnect-Reason sa-lifetime-expiry 326
+VALUE SN-Disconnect-Reason asnpc-del-ms-entry-recd 327
+VALUE SN-Disconnect-Reason phspc-sleep-mode-timeout 328
+VALUE SN-Disconnect-Reason phspc-sleep-mode-exit 329
+VALUE SN-Disconnect-Reason phspc-sleep-mode-auth-failed 330
+VALUE SN-Disconnect-Reason phspc-ms-power-down-nwexit 331
+VALUE SN-Disconnect-Reason phspc-x2-nwexit-recd 332
+VALUE SN-Disconnect-Reason invalid-nat-config 333
+VALUE SN-Disconnect-Reason asngw-tid-entry-not-found 334
+VALUE SN-Disconnect-Reason No-NAT-IP-Address 335
+VALUE SN-Disconnect-Reason excessive-phs-pd-flows-cfgd 336
+VALUE SN-Disconnect-Reason phsgw-invalid-qos-configuration 337
+VALUE SN-Disconnect-Reason Interim-Update 338
+VALUE SN-Disconnect-Reason sgsn-attach-abrt-rad-lost 339
+VALUE SN-Disconnect-Reason sgsn-inbnd-irau-abrt-rad-lost 340
+VALUE SN-Disconnect-Reason ike-keepalive-failed 341
+VALUE SN-Disconnect-Reason sgsn-attach-abrt-ms-suspend 342
+VALUE SN-Disconnect-Reason sgsn-inbnd-irau-abrt-ms-suspend 343
+VALUE SN-Disconnect-Reason duplicate-session-detected 344
+VALUE SN-Disconnect-Reason sgsn-xid-response-failure 345
+VALUE SN-Disconnect-Reason sgsn-nse-cleanup 346
+VALUE SN-Disconnect-Reason sgsn-gtp-req-failure 347
+VALUE SN-Disconnect-Reason sgsn-imsi-mismatch 348
+VALUE SN-Disconnect-Reason sgsn-bvc-blocked 349
+VALUE SN-Disconnect-Reason sgsn-attach-on-inbound-irau 350
+VALUE SN-Disconnect-Reason sgsn-attach-on-outbound-irau 351
+VALUE SN-Disconnect-Reason sgsn-incorrect-state 352
+VALUE SN-Disconnect-Reason sgsn-t3350-expiry 353
+VALUE SN-Disconnect-Reason sgsn-page-timer-expiry 354
+VALUE SN-Disconnect-Reason phsgw-tid-entry-not-found 355
+VALUE SN-Disconnect-Reason phspc-del-ms-entry-recd 356
+VALUE SN-Disconnect-Reason sgsn-pdp-local-purge 357
+VALUE SN-Disconnect-Reason phs-invalid-nai 358
+VALUE SN-Disconnect-Reason session-sleep-mode-exit-timeout 359
+VALUE SN-Disconnect-Reason sgsn-offload-phase2 360
+VALUE SN-Disconnect-Reason phs-thirdparty-auth-fail 361
+VALUE SN-Disconnect-Reason remote-error-notify 362
+VALUE SN-Disconnect-Reason no-response 363
+VALUE SN-Disconnect-Reason PDG-Auth-failed 364
+VALUE SN-Disconnect-Reason mme-s1AP-send-failed 365
+VALUE SN-Disconnect-Reason mme-egtpc-connection-failed 366
+VALUE SN-Disconnect-Reason mme-egtpc-create-session-failed 367
+VALUE SN-Disconnect-Reason mme-authentication-failure 368
+VALUE SN-Disconnect-Reason mme-ue-detach 369
+VALUE SN-Disconnect-Reason mme-mme-detach 370
+VALUE SN-Disconnect-Reason mme-hss-detach 371
+VALUE SN-Disconnect-Reason mme-pgw-detach 372
+VALUE SN-Disconnect-Reason mme-sub-validation-failure 373
+VALUE SN-Disconnect-Reason mme-hss-connection-failure 374
+VALUE SN-Disconnect-Reason mme-hss-user-unknown 375
+VALUE SN-Disconnect-Reason dhcp-lease-mismatch-detected 376
+VALUE SN-Disconnect-Reason nemo-link-layer-down 377
+VALUE SN-Disconnect-Reason eapol-max-retry-reached 378
+VALUE SN-Disconnect-Reason sgsn-offload-phase3 379
+VALUE SN-Disconnect-Reason mbms-bearer-service-disconnect 380
+VALUE SN-Disconnect-Reason disconnect-on-violation-odb 381
+VALUE SN-Disconnect-Reason disconn-on-violation-focs-odb 382
+VALUE SN-Disconnect-Reason CSCF-REG-Admin-disconnect 383
+VALUE SN-Disconnect-Reason CSCF-REG-User-disconnect 384
+VALUE SN-Disconnect-Reason CSCF-REG-Inactivity-timeout 385
+VALUE SN-Disconnect-Reason CSCF-REG-Network-disconnect 386
+VALUE SN-Disconnect-Reason CSCF-Call-Admin-disconnect 387
+VALUE SN-Disconnect-Reason CSCF-CAll-User-disconnect 388
+VALUE SN-Disconnect-Reason CSCF-CALL-Local-disconnect 389
+VALUE SN-Disconnect-Reason CSCF-CALL-No-Resource 390
+VALUE SN-Disconnect-Reason CSCF-CALL-No-Respone 391
+VALUE SN-Disconnect-Reason CSCF-CALL-Inactivity-timeout 392
+VALUE SN-Disconnect-Reason CSCF-CALL-Media-Auth-Failure 393
+VALUE SN-Disconnect-Reason CSCF-REG-No-Resource 394
+VALUE SN-Disconnect-Reason ms-unexpected-idle-mode-entry 395
+VALUE SN-Disconnect-Reason re-auth-failed 396
+VALUE SN-Disconnect-Reason sgsn-pdp-nse-cleanup 397
+VALUE SN-Disconnect-Reason sgsn-mm-ctxt-gtp-no-resource 398
+VALUE SN-Disconnect-Reason unknown-apn 399
+VALUE SN-Disconnect-Reason gtpc-path-failure 400
+VALUE SN-Disconnect-Reason gtpu-path-failure 401
+VALUE SN-Disconnect-Reason actv-rejected-by-sgsn 402
+VALUE SN-Disconnect-Reason sgsn-pdp-gprs-camel-release 403
+VALUE SN-Disconnect-Reason sgsn-check-imei-failure 404
+VALUE SN-Disconnect-Reason sgsn-sndcp-init-deact 405
+VALUE SN-Disconnect-Reason sgsn-pdp-inactivity-timeout 406
+VALUE SN-Disconnect-Reason fw-and-nat-policy-removed 407
+VALUE SN-Disconnect-Reason FNG-Auth-failed 408
+VALUE SN-Disconnect-Reason ha-stale-key-disconnect 409
+VALUE SN-Disconnect-Reason No-IPV6-address-for-subscriber 410
+VALUE SN-Disconnect-Reason prefix-registration-failure 411
+VALUE SN-Disconnect-Reason disconnect-from-policy-server 412
+VALUE SN-Disconnect-Reason s6b-auth-failed 413
+VALUE SN-Disconnect-Reason gtpc-err-ind 414
+VALUE SN-Disconnect-Reason gtpu-err-ind 415
+VALUE SN-Disconnect-Reason invalid-pdn-type 416
+VALUE SN-Disconnect-Reason aaa-auth-req-failed 417
+VALUE SN-Disconnect-Reason apn-denied-no-subscription 418
+VALUE SN-Disconnect-Reason Sgw-context-replacement 419
+VALUE SN-Disconnect-Reason dup-static-ip-addr-req 420
+VALUE SN-Disconnect-Reason apn-restrict-violation 421
+VALUE SN-Disconnect-Reason invalid-wapn 422
+VALUE SN-Disconnect-Reason ttg-nsapi-allocation-failed 423
+VALUE SN-Disconnect-Reason mandatory-gtp-ie-missing 424
+VALUE SN-Disconnect-Reason aaa-unreachable 425
+VALUE SN-Disconnect-Reason asngw-service-flow-deletion 426
+VALUE SN-Disconnect-Reason CT-PMIP-RRQ-NVSE-Value-Change 427
+VALUE SN-Disconnect-Reason tcp-read-failed 428
+VALUE SN-Disconnect-Reason tcp-write-failed 429
+VALUE SN-Disconnect-Reason ssl-handshake-failed 430
+VALUE SN-Disconnect-Reason ssl-renegotiate-failed 431
+VALUE SN-Disconnect-Reason ssl-bad-message 432
+VALUE SN-Disconnect-Reason ssl-alert-received 433
+VALUE SN-Disconnect-Reason ssl-disconnect 434
+VALUE SN-Disconnect-Reason ssl-migration 435
+VALUE SN-Disconnect-Reason sgsn-ard-failure 436
+VALUE SN-Disconnect-Reason sgsn-camel-release 437
+VALUE SN-Disconnect-Reason Hotlining-Status-Change 447
+VALUE SN-Disconnect-Reason ggsn-no-rsp-from-sgsn 448
+VALUE SN-Disconnect-Reason diameter-protocol-error 449
+VALUE SN-Disconnect-Reason diameter-request-timeout 450
+VALUE SN-Disconnect-Reason operator-policy 451
+VALUE SN-Disconnect-Reason spr-connection-timeout 452
+VALUE SN-Disconnect-Reason mipha-dup-wimax-session 453
+VALUE SN-Disconnect-Reason invalid-version-attr 454
+VALUE SN-Disconnect-Reason sgsn-zone-code-failure 455
+
+VALUE SN-PPP-Progress-Code Not-Defined 0
+VALUE SN-PPP-Progress-Code Call-Lcp-Down 1
+VALUE SN-PPP-Progress-Code Call-Disconnecting 2
+VALUE SN-PPP-Progress-Code Call-PPP-Renegotiating 3
+VALUE SN-PPP-Progress-Code Call-Lcp-Down_1 10
+VALUE SN-PPP-Progress-Code Call-Arrived 11
+VALUE SN-PPP-Progress-Code Call-Lcp-Up 12
+VALUE SN-PPP-Progress-Code Call-Authenticating 13
+VALUE SN-PPP-Progress-Code Call-Authenticated 14
+VALUE SN-PPP-Progress-Code Call-Ipcp-Up 15
+VALUE SN-PPP-Progress-Code Call-Simple-IP-Connected 16
+VALUE SN-PPP-Progress-Code Call-Mobile-IP-Connected 17
+#VALUE SN-PPP-Progress-Code Call-Disconnecting 20
+#VALUE SN-PPP-Progress-Code Call-PPP-Renegotiating 30
+#VALUE SN-PPP-Progress-Code Call-Arrived 40
+VALUE SN-PPP-Progress-Code Call-Pdg-Tcp-Connecting 45
+VALUE SN-PPP-Progress-Code Call-Pdg-Ssl-Connecting 46
+#VALUE SN-PPP-Progress-Code Call-Lcp-Up 50
+#VALUE SN-PPP-Progress-Code Call-Authenticating 60
+VALUE SN-PPP-Progress-Code Call-Bcmcs-Authenticating 70
+#VALUE SN-PPP-Progress-Code Call-Authenticated 80
+VALUE SN-PPP-Progress-Code Call-Tunnel-Connecting 85
+#VALUE SN-PPP-Progress-Code Call-Ipcp-Up 90
+VALUE SN-PPP-Progress-Code Call-Imsa-Authorizing 95
+VALUE SN-PPP-Progress-Code Call-Imsa-Authorized 97
+VALUE SN-PPP-Progress-Code Call-MBMS-UE-Authorizing 98
+VALUE SN-PPP-Progress-Code Call-MBMS-Bearer-Authorizing 99
+#VALUE SN-PPP-Progress-Code Call-Simple-IP-Connected 100
+#VALUE SN-PPP-Progress-Code Call-Mobile-IP-Connected 110
+VALUE SN-PPP-Progress-Code Call-Tunnel-Connected 115
+VALUE SN-PPP-Progress-Code Call-Pdp-Type-IP-Connected 120
+VALUE SN-PPP-Progress-Code Call-Pdp-Type-IPv6-Connected 125
+VALUE SN-PPP-Progress-Code Call-Pdp-Type-PPP-Connected 130
+VALUE SN-PPP-Progress-Code Call-Proxy-Mobile-IP-Connected 140
+VALUE SN-PPP-Progress-Code Call-Pdg-Connected 142
+VALUE SN-PPP-Progress-Code Call-Pdg-Ssl-Connected 141
+VALUE SN-PPP-Progress-Code Call-Pdg-Connected 142
+VALUE SN-PPP-Progress-Code Call-Pdg-Connected 142
+VALUE SN-PPP-Progress-Code Call-Ipsg-Connected 145
+VALUE SN-PPP-Progress-Code Call-Bcmcs-Connected 150
+VALUE SN-PPP-Progress-Code Call-MBMS-UE-Connected 155
+VALUE SN-PPP-Progress-Code Call-MBMS-Bearer-Connected 156
+VALUE SN-PPP-Progress-Code Call-Pending-Addr-From-DHCP 160
+VALUE SN-PPP-Progress-Code Call-Got-Addr-From-DHCP 170
+VALUE SN-PPP-Progress-Code Call-HA-IPSEC-Tunnel-Connecting 180
+VALUE SN-PPP-Progress-Code Call-HA-IPSEC-Connected 190
+VALUE SN-PPP-Progress-Code Call-ASN-Non-Anchor-Connected 200
+VALUE SN-PPP-Progress-Code Call-ASNPC-Connected 210
+VALUE SN-PPP-Progress-Code Call-Mobile-IPv6-Connected 220
+VALUE SN-PPP-Progress-Code Call-PMIPv6-Connected 221
+VALUE SN-PPP-Progress-Code Call-PHSPC-Connected 230
+VALUE SN-PPP-Progress-Code Call-GTP-IPv4-Connected 235
+VALUE SN-PPP-Progress-Code Call-GTP-IPv6-Connected 236
+VALUE SN-PPP-Progress-Code Call-GTP-IPv4-IPv6-Connected 237
+VALUE SN-PPP-Progress-Code Call-SGW-Connected 245
+VALUE SN-PPP-Progress-Code Call-MME-Attached 246
+VALUE SN-PPP-Progress-Code Call-Auth-Only-Connected 247
+
+VALUE SN-PPP-Data-Compression None 0
+VALUE SN-PPP-Data-Compression Stac-LZS 1
+VALUE SN-PPP-Data-Compression MPPC 2
+VALUE SN-PPP-Data-Compression MPCC-Stac-LZS 3
+VALUE SN-PPP-Data-Compression Deflate 4
+VALUE SN-PPP-Data-Compression Deflate-Stac-LZS 5
+VALUE SN-PPP-Data-Compression Deflate-MPCC 6
+VALUE SN-PPP-Data-Compression Deflate-MPCC-Stac-LZS 7
+
+VALUE SN-IP-Source-Validation No 0
+VALUE SN-IP-Source-Validation Yes 1
+
+VALUE SN-Subscriber-Permission None 0
+VALUE SN-Subscriber-Permission Simple-IP 1
+VALUE SN-Subscriber-Permission Mobile-IP 2
+VALUE SN-Subscriber-Permission Simple-IP-Mobile-IP 3
+VALUE SN-Subscriber-Permission HA-Mobile-IP 4
+VALUE SN-Subscriber-Permission Simple-IP-HA-Mobile-IP 5
+VALUE SN-Subscriber-Permission Mobile-IP-HA-Mobile-IP 6
+VALUE SN-Subscriber-Permission All 7
+VALUE SN-Subscriber-Permission GGSN-PDP-TYPE-IP 8
+VALUE SN-Subscriber-Permission GGSN-PDP-TYPE-PPP 16
+VALUE SN-Subscriber-Permission Network-Mobility 32
+VALUE SN-Subscriber-Permission FA-HA-NEMO 38
+VALUE SN-Subscriber-Permission All_New 63
+
+VALUE SN-Admin-Permission None 0
+VALUE SN-Admin-Permission CLI 1
+VALUE SN-Admin-Permission FTP 2
+VALUE SN-Admin-Permission CLI-FTP 3
+VALUE SN-Admin-Permission Intercept 4
+VALUE SN-Admin-Permission CLI-Intercept 5
+VALUE SN-Admin-Permission CLI-Intercept-FTP 7
+VALUE SN-Admin-Permission ECS 8
+VALUE SN-Admin-Permission CLI-ECS 9
+VALUE SN-Admin-Permission CLI-FTP-ECS 11
+VALUE SN-Admin-Permission CLI-Intercept-ECS 13
+VALUE SN-Admin-Permission CLI-Intercept-FTP-ECS 15
+
+VALUE SN-Simultaneous-SIP-MIP Disabled 0
+VALUE SN-Simultaneous-SIP-MIP Enabled 1
+
+VALUE SN-PPP-Data-Compression-Mode Normal 0
+VALUE SN-PPP-Data-Compression-Mode Stateless 1
+
+VALUE SN-Access-link-IP-Frag Normal 0
+VALUE SN-Access-link-IP-Frag DF-Ignore 1
+VALUE SN-Access-link-IP-Frag DF-Fragment-ICMP-Notify 2
+
+VALUE SN-Cause-Code Normal_End_Of_Session 0
+VALUE SN-Cause-Code Successful_Transaction 1
+VALUE SN-Cause-Code End_Of_Subscriber_Dialog 2
+VALUE SN-Cause-Code 3XX_Redirection 3
+VALUE SN-Cause-Code 4XX_Request_Failure 4
+VALUE SN-Cause-Code 5XX_Server_Failure 5
+VALUE SN-Cause-Code 6XX_Global_Failure 6
+VALUE SN-Cause-Code Unspecified_Error 7
+VALUE SN-Cause-Code Unsuccessful_Session_Setup 8
+VALUE SN-Cause-Code Internal_Error 9
+
+VALUE SN-CF-Call-International Disable 0
+VALUE SN-CF-Call-International Enable 1
+
+VALUE SN-CF-Call-Local Disable 0
+VALUE SN-CF-Call-Local Enable 1
+
+VALUE SN-CF-Call-LongDistance Disable 0
+VALUE SN-CF-Call-LongDistance Enable 1
+
+VALUE SN-CF-Call-Premium Disable 0
+VALUE SN-CF-Call-Premium Enable 1
+
+VALUE SN-CF-Call-RoamingInternatnl Disable 0
+VALUE SN-CF-Call-RoamingInternatnl Enable 1
+
+VALUE SN-CF-Call-Transfer Disable 0
+VALUE SN-CF-Call-Transfer Enable 1
+
+VALUE SN-CF-Call-Waiting Disable 0
+VALUE SN-CF-Call-Waiting Enable 1
+
+VALUE SN-CF-CId-Display Disable 0
+VALUE SN-CF-CId-Display Enable 1
+
+VALUE SN-CF-CId-Display-Blocked Disable 0
+VALUE SN-CF-CId-Display-Blocked Enable 1
+
+VALUE SN-Change-Condition QOSCHANGE 0
+VALUE SN-Change-Condition TARIFFTIMECHANGE 1
+VALUE SN-Change-Condition SGSNCHANGE 500
+
+VALUE SN-Data-Tunnel-Ignore-DF-Bit Disabled 0
+VALUE SN-Data-Tunnel-Ignore-DF-Bit Enabled 1
+
+VALUE SN-DHCP-Lease-Expiry-Policy auto-renew 0
+VALUE SN-DHCP-Lease-Expiry-Policy disconnect 1
+
+VALUE SN-Direction Any 0
+VALUE SN-Direction Uplink 1
+VALUE SN-Direction Downlink 2
+
+VALUE SN-DNS-Proxy-Use-Subscr-Addr Disable 0
+VALUE SN-DNS-Proxy-Use-Subscr-Addr Enable 1
+
+VALUE SN-Enable-QoS-Renegotiation No 0
+VALUE SN-Enable-QoS-Renegotiation Yes 1
+
+VALUE SN-Firewall-Enabled False 0
+VALUE SN-Firewall-Enabled True 1
+
+VALUE SN-GGSN-MIP-Required Disabled 0
+VALUE SN-GGSN-MIP-Required Enabled 1
+
+VALUE SN-Gratuitous-ARP-Aggressive Disabled 0
+VALUE SN-Gratuitous-ARP-Aggressive Enabled 1
+
+VALUE SN-GTP-Version GTP_VERSION_0 0
+VALUE SN-GTP-Version GTP_VERSION_1 1
+VALUE SN-GTP-Version GTP_VERSION_2 2
+
+VALUE SN-HA-Send-DNS-ADDRESS Disabled 0
+VALUE SN-HA-Send-DNS-ADDRESS Enabled 1
+
+VALUE SN-Handoff-Indicator Active-Handoff 0
+VALUE SN-Handoff-Indicator Location-Update 1
+
+VALUE SN-Home-Sub-Use-GGSN Deny 0
+VALUE SN-Home-Sub-Use-GGSN Accept 1
+
+VALUE SN-IP-Alloc-Method Alloc_Local_Pool 0
+VALUE SN-IP-Alloc-Method Alloc_Dhcp_Client 1
+VALUE SN-IP-Alloc-Method Alloc_Radius 2
+VALUE SN-IP-Alloc-Method Alloc_No_Alloc 3
+VALUE SN-IP-Alloc-Method Alloc_Static_Alloc 4
+VALUE SN-IP-Alloc-Method Alloc_Dhcp_Relay 5
+
+VALUE SN-IP-Header-Compression None 0
+VALUE SN-IP-Header-Compression VJ 1
+VALUE SN-IP-Header-Compression ROHC 2
+VALUE SN-IP-Header-Compression VJ_ROHC 3
+
+VALUE SN-IP-Hide-Service-Address Disabled 0
+VALUE SN-IP-Hide-Service-Address Enabled 1
+
+VALUE SN-IP-Source-Violate-No-Acct Disabled 0
+VALUE SN-IP-Source-Violate-No-Acct Enabled 1
+
+VALUE SN-IPv6-DNS-Proxy Disabled 0
+VALUE SN-IPv6-DNS-Proxy Enabled 1
+
+VALUE SN-IPv6-Egress-Filtering Disabled 0
+VALUE SN-IPv6-Egress-Filtering Enabled 1
+
+VALUE SN-L3-to-L2-Tun-Addr-Policy no-local-alloc-validate 0
+VALUE SN-L3-to-L2-Tun-Addr-Policy local-alloc 1
+VALUE SN-L3-to-L2-Tun-Addr-Policy local-alloc-validate 2
+
+VALUE SN-Long-Duration-Action Detection 1
+VALUE SN-Long-Duration-Action Disconnection 2
+VALUE SN-Long-Duration-Action Dormant-Only-Disconnection 3
+VALUE SN-Long-Duration-Action Dormant-Only-Detection 4
+
+VALUE SN-Long-Duration-Notification Suppress 0
+VALUE SN-Long-Duration-Notification Send 1
+
+VALUE SN-Mediation-Acct-Rsp-Action None 0
+VALUE SN-Mediation-Acct-Rsp-Action No_Early_PDUs 1
+VALUE SN-Mediation-Acct-Rsp-Action Delay_GTP_Response 2
+
+VALUE SN-Mediation-Enabled Disabled 0
+VALUE SN-Mediation-Enabled Enabled 1
+
+VALUE SN-Mediation-No-Interims Disabled 0
+VALUE SN-Mediation-No-Interims Enabled 1
+
+VALUE SN-MIP-AAA-Assign-Addr Disabled 0
+VALUE SN-MIP-AAA-Assign-Addr Enabled 1
+
+VALUE SN-MIP-Dual-Anchor Disabled 0
+VALUE SN-MIP-Dual-Anchor Enabled 1
+
+VALUE SN-MIP-Match-AAA-Assign-Addr Disabled 0
+VALUE SN-MIP-Match-AAA-Assign-Addr Enabled 1
+
+VALUE SN-MIP-Send-Ancid Disabled 0
+VALUE SN-MIP-Send-Ancid Enabled 1
+
+VALUE SN-MIP-Send-Correlation-Info Disabled 0
+# In StarOS 8.3 and later, supported value 1 is NVSE_Starent, before 8.3 it is Enabled.
+VALUE SN-MIP-Send-Correlation-Info EnabledOrNVSE_Starent 1
+VALUE SN-MIP-Send-Correlation-Info NVSE_CUstom1 2
+VALUE SN-MIP-Send-Correlation-Info NVSE_Custom2 3
+
+VALUE SN-MIP-Send-Imsi NoneOrDisabled 0
+VALUE SN-MIP-Send-Imsi Starent_NVSE 1
+VALUE SN-MIP-Send-Imsi NVSE_Custom1 2
+VALUE SN-MIP-Send-Imsi NVSE_Custom2 3
+
+VALUE SN-MIP-Send-Term-Verification Disabled 0
+VALUE SN-MIP-Send-Term-Verification EnabledOrNVSE_Custom1 1
+VALUE SN-MIP-Send-Term-Verification NVSE_Custom2 2
+VALUE SN-MIP-Send-Term-Verification NVSE_Starent 3
+
+VALUE SN-MN-HA-Hash-Algorithm MD5 1
+VALUE SN-MN-HA-Hash-Algorithm MD5_RFC2002 2
+VALUE SN-MN-HA-Hash-Algorithm HMAC_MD5 3
+
+VALUE SN-Mode Reliable 0
+VALUE SN-Mode Optimistic 1
+VALUE SN-Mode Unidirectional 2
+
+VALUE SN-Node-Functionality S-CSCF 0
+VALUE SN-Node-Functionality P-CSCF 1
+VALUE SN-Node-Functionality I-CSCF 2
+
+VALUE SN-NPU-Qos-Priority Best_Effort 0
+VALUE SN-NPU-Qos-Priority Bronze 1
+VALUE SN-NPU-Qos-Priority Silver 2
+VALUE SN-NPU-Qos-Priority Gold 3
+VALUE SN-NPU-Qos-Priority From_DSCP 4
+
+VALUE SN-Ntk-Session-Disconnect-Flag Session-Disconnect 1
+
+VALUE SN-PDG-TTG-Required No 0
+VALUE SN-PDG-TTG-Required Yes 1
+
+VALUE SN-PDIF-MIP-Release-TIA No 0
+VALUE SN-PDIF-MIP-Release-TIA Yes 1
+
+VALUE SN-PDIF-MIP-Required No 0
+VALUE SN-PDIF-MIP-Required Yes 1
+
+VALUE SN-PDIF-MIP-Simple-IP-Fallback No 0
+VALUE SN-PDIF-MIP-Simple-IP-Fallback Yes 1
+
+VALUE SN-PDSN-Handoff-Req-IP-Addr Disabled 0
+VALUE SN-PDSN-Handoff-Req-IP-Addr Enabled 1
+
+VALUE SN-Permit-User-Mcast-PDUs Disabled 0
+VALUE SN-Permit-User-Mcast-PDUs Enabled 1
+
+VALUE SN-PPP-Accept-Peer-v6Ifid Disabled 0
+VALUE SN-PPP-Accept-Peer-v6Ifid Enabled 1
+
+VALUE SN-PPP-Always-On-Vse Disabled 0
+VALUE SN-PPP-Always-On-Vse Enabled 1
+
+VALUE SN-PPP-NW-Layer-IPv4 Disabled 0
+VALUE SN-PPP-NW-Layer-IPv4 Enabled 1
+VALUE SN-PPP-NW-Layer-IPv4 Passive 2
+
+VALUE SN-PPP-NW-Layer-IPv6 Disabled 0
+VALUE SN-PPP-NW-Layer-IPv6 Enabled 1
+VALUE SN-PPP-NW-Layer-IPv6 Passive 2
+
+VALUE SN-PPP-Reneg-Disc Never 0
+VALUE SN-PPP-Reneg-Disc Always 1
+VALUE SN-PPP-Reneg-Disc NAI_Prefix_MSID_Mismatch 2
+
+VALUE SN-Prepaid no_prepaid 0
+VALUE SN-Prepaid custom_prepaid 1
+VALUE SN-Prepaid standard_prepaid 2
+VALUE SN-Prepaid wimax_prepaid 4
+
+VALUE SN-Prepaid-Compressed-Count Uncompressed 0
+VALUE SN-Prepaid-Compressed-Count Compressed 1
+
+VALUE SN-Prepaid-Final-Duration-Alg current_time 0
+VALUE SN-Prepaid-Final-Duration-Alg last-user-layer3-activity-time 1
+VALUE SN-Prepaid-Final-Duration-Alg last-airlink-activity-time 2
+VALUE SN-Prepaid-Final-Duration-Alg last-airlink-activity-time-last-reported 3
+
+VALUE SN-Prepaid-Preference prepaid_duration 0
+VALUE SN-Prepaid-Preference prepaid_volume 1
+
+VALUE SN-Proxy-MIP Disabled 0
+VALUE SN-Proxy-MIP Enabled 1
+
+VALUE SN-Proxy-MIPV6 Disabled 0
+VALUE SN-Proxy-MIPV6 Enabled 1
+
+VALUE SN-QoS-Class-Background-PHB Best-Effort 0
+VALUE SN-QoS-Class-Background-PHB Pass-Through 1
+VALUE SN-QoS-Class-Background-PHB AF11 10
+VALUE SN-QoS-Class-Background-PHB AF12 12
+VALUE SN-QoS-Class-Background-PHB AF13 14
+VALUE SN-QoS-Class-Background-PHB AF21 18
+VALUE SN-QoS-Class-Background-PHB AF22 20
+VALUE SN-QoS-Class-Background-PHB AF23 22
+VALUE SN-QoS-Class-Background-PHB AF31 26
+VALUE SN-QoS-Class-Background-PHB AF32 28
+VALUE SN-QoS-Class-Background-PHB AF33 30
+VALUE SN-QoS-Class-Background-PHB AF41 34
+VALUE SN-QoS-Class-Background-PHB AF42 36
+VALUE SN-QoS-Class-Background-PHB AF43 38
+VALUE SN-QoS-Class-Background-PHB EF 46
+
+VALUE SN-QoS-Class-Conversational-PHB Best-Effort 0
+VALUE SN-QoS-Class-Conversational-PHB Pass-Through 1
+VALUE SN-QoS-Class-Conversational-PHB AF11 10
+VALUE SN-QoS-Class-Conversational-PHB AF12 12
+VALUE SN-QoS-Class-Conversational-PHB AF13 14
+VALUE SN-QoS-Class-Conversational-PHB AF21 18
+VALUE SN-QoS-Class-Conversational-PHB AF22 20
+VALUE SN-QoS-Class-Conversational-PHB AF23 22
+VALUE SN-QoS-Class-Conversational-PHB AF31 26
+VALUE SN-QoS-Class-Conversational-PHB AF32 28
+VALUE SN-QoS-Class-Conversational-PHB AF33 30
+VALUE SN-QoS-Class-Conversational-PHB AF41 34
+VALUE SN-QoS-Class-Conversational-PHB AF42 36
+VALUE SN-QoS-Class-Conversational-PHB AF43 38
+VALUE SN-QoS-Class-Conversational-PHB EF 46
+
+VALUE SN-QoS-Class-Interactive-1-PHB Best-Effort 0
+VALUE SN-QoS-Class-Interactive-1-PHB Pass-Through 1
+VALUE SN-QoS-Class-Interactive-1-PHB AF11 10
+VALUE SN-QoS-Class-Interactive-1-PHB AF12 12
+VALUE SN-QoS-Class-Interactive-1-PHB AF13 14
+VALUE SN-QoS-Class-Interactive-1-PHB AF21 18
+VALUE SN-QoS-Class-Interactive-1-PHB AF22 20
+VALUE SN-QoS-Class-Interactive-1-PHB AF23 22
+VALUE SN-QoS-Class-Interactive-1-PHB AF31 26
+VALUE SN-QoS-Class-Interactive-1-PHB AF32 28
+VALUE SN-QoS-Class-Interactive-1-PHB AF33 30
+VALUE SN-QoS-Class-Interactive-1-PHB AF41 34
+VALUE SN-QoS-Class-Interactive-1-PHB AF42 36
+VALUE SN-QoS-Class-Interactive-1-PHB AF43 38
+VALUE SN-QoS-Class-Interactive-1-PHB EF 46
+
+VALUE SN-QoS-Class-Interactive-2-PHB Best-Effort 0
+VALUE SN-QoS-Class-Interactive-2-PHB Pass-Through 1
+VALUE SN-QoS-Class-Interactive-2-PHB AF11 10
+VALUE SN-QoS-Class-Interactive-2-PHB AF12 12
+VALUE SN-QoS-Class-Interactive-2-PHB AF13 14
+VALUE SN-QoS-Class-Interactive-2-PHB AF21 18
+VALUE SN-QoS-Class-Interactive-2-PHB AF22 20
+VALUE SN-QoS-Class-Interactive-2-PHB AF23 22
+VALUE SN-QoS-Class-Interactive-2-PHB AF31 26
+VALUE SN-QoS-Class-Interactive-2-PHB AF32 28
+VALUE SN-QoS-Class-Interactive-2-PHB AF33 30
+VALUE SN-QoS-Class-Interactive-2-PHB AF41 34
+VALUE SN-QoS-Class-Interactive-2-PHB AF42 36
+VALUE SN-QoS-Class-Interactive-2-PHB AF43 38
+VALUE SN-QoS-Class-Interactive-2-PHB EF 46
+
+VALUE SN-QoS-Class-Interactive-3-PHB Best-Effort 0
+VALUE SN-QoS-Class-Interactive-3-PHB Pass-Through 1
+VALUE SN-QoS-Class-Interactive-3-PHB AF11 10
+VALUE SN-QoS-Class-Interactive-3-PHB AF12 12
+VALUE SN-QoS-Class-Interactive-3-PHB AF13 14
+VALUE SN-QoS-Class-Interactive-3-PHB AF21 18
+VALUE SN-QoS-Class-Interactive-3-PHB AF22 20
+VALUE SN-QoS-Class-Interactive-3-PHB AF23 22
+VALUE SN-QoS-Class-Interactive-3-PHB AF31 26
+VALUE SN-QoS-Class-Interactive-3-PHB AF32 28
+VALUE SN-QoS-Class-Interactive-3-PHB AF33 30
+VALUE SN-QoS-Class-Interactive-3-PHB AF41 34
+VALUE SN-QoS-Class-Interactive-3-PHB AF42 36
+VALUE SN-QoS-Class-Interactive-3-PHB AF43 38
+VALUE SN-QoS-Class-Interactive-3-PHB EF 46
+
+VALUE SN-QoS-Class-Streaming-PHB Best-Effort 0
+VALUE SN-QoS-Class-Streaming-PHB Pass-Through 1
+VALUE SN-QoS-Class-Streaming-PHB AF11 10
+VALUE SN-QoS-Class-Streaming-PHB AF12 12
+VALUE SN-QoS-Class-Streaming-PHB AF13 14
+VALUE SN-QoS-Class-Streaming-PHB AF21 18
+VALUE SN-QoS-Class-Streaming-PHB AF22 20
+VALUE SN-QoS-Class-Streaming-PHB AF23 22
+VALUE SN-QoS-Class-Streaming-PHB AF31 26
+VALUE SN-QoS-Class-Streaming-PHB AF32 28
+VALUE SN-QoS-Class-Streaming-PHB AF33 30
+VALUE SN-QoS-Class-Streaming-PHB AF41 34
+VALUE SN-QoS-Class-Streaming-PHB AF42 36
+VALUE SN-QoS-Class-Streaming-PHB AF43 38
+VALUE SN-QoS-Class-Streaming-PHB EF 46
+
+VALUE SN-QoS-Tp-Dnlk Disabled 0
+VALUE SN-QoS-Tp-Dnlk Policing 1
+VALUE SN-QoS-Tp-Dnlk Shaping 2
+
+VALUE SN-QoS-Tp-Uplk Disabled 0
+VALUE SN-QoS-Tp-Uplk Policing 1
+VALUE SN-QoS-Tp-Uplk Shaping 2
+
+VALUE SN-Radius-Returned-Username No 0
+VALUE SN-Radius-Returned-Username Yes 1
+
+VALUE SN-Roaming-Sub-Use-GGSN Deny 0
+VALUE SN-Roaming-Sub-Use-GGSN Accept 1
+
+VALUE SN-ROHC-Flow-Marking-Mode False 0
+VALUE SN-ROHC-Flow-Marking-Mode True 1
+
+VALUE SN-Role-Of-Node ORIGINATING_ROLE 0
+VALUE SN-Role-Of-Node TERMINATING_ROLE 1
+
+VALUE SN-Service-Type None 0
+VALUE SN-Service-Type PDSN 1
+VALUE SN-Service-Type Management 2
+VALUE SN-Service-Type HA 3
+VALUE SN-Service-Type GGSN 4
+VALUE SN-Service-Type LNS 5
+VALUE SN-Service-Type IPSG 6
+VALUE SN-Service-Type CSCF 7
+VALUE SN-Service-Type ASNGW 8
+VALUE SN-Service-Type PDIF 9
+VALUE SN-Service-Type STANDALONE_FA 10
+VALUE SN-Service-Type SGSN 11
+VALUE SN-Service-Type PHSGW 12
+VALUE SN-Service-Type PDG 13
+VALUE SN-Service-Type MIPV6HA 14
+VALUE SN-Service-Type PGW 15
+VALUE SN-Service-Type SGW 16
+VALUE SN-Service-Type FNG 17
+VALUE SN-Service-Type OGW 18
+VALUE SN-Service-Type HNBGW 19
+VALUE SN-Service-Type BNG 20
+
+VALUE SN-Subs-Acc-Flow-Traffic-Valid Disabled 0
+VALUE SN-Subs-Acc-Flow-Traffic-Valid Enabled 1
+
+VALUE SN-Subscriber-Accounting None 0
+VALUE SN-Subscriber-Accounting Radius 1
+VALUE SN-Subscriber-Accounting GTPP 2
+
+VALUE SN-Subscriber-Acct-Interim Normal 0
+VALUE SN-Subscriber-Acct-Interim Suppress 1
+
+VALUE SN-Subscriber-Acct-Mode flow-based-auxilliary 0
+VALUE SN-Subscriber-Acct-Mode flow-based-all 1
+VALUE SN-Subscriber-Acct-Mode flow-based-none 2
+VALUE SN-Subscriber-Acct-Mode session-based 3
+VALUE SN-Subscriber-Acct-Mode main-a10-only 4
+
+VALUE SN-Subscriber-Acct-Rsp-Action None 0
+VALUE SN-Subscriber-Acct-Rsp-Action No_Early_PDUs 1
+VALUE SN-Subscriber-Acct-Rsp-Action Delay_GTP_Response 2
+
+VALUE SN-Subscriber-Acct-Start Normal 0
+VALUE SN-Subscriber-Acct-Start Suppress 1
+
+VALUE SN-Subscriber-Acct-Stop Normal 0
+VALUE SN-Subscriber-Acct-Stop Suppress 1
+
+VALUE SN-Subscriber-Class Normal_Subscriber 0
+VALUE SN-Subscriber-Class Ting_100 1
+VALUE SN-Subscriber-Class Ting_500 2
+VALUE SN-Subscriber-Class Ting_Buddy 3
+VALUE SN-Subscriber-Class Ting_Star 4
+VALUE SN-Subscriber-Class Ting_Nolimit_SMS 5
+VALUE SN-Subscriber-Class Kids_Locator 6
+VALUE SN-Subscriber-Class Ting_2000 7
+VALUE SN-Subscriber-Class Handicapped_Welfare 8
+VALUE SN-Subscriber-Class Reserved 9
+
+VALUE SN-Subscriber-IP-Hdr-Neg-Mode Force 0
+VALUE SN-Subscriber-IP-Hdr-Neg-Mode Detect 1
+
+VALUE SN-Subscriber-IP-TOS-Copy None 0
+VALUE SN-Subscriber-IP-TOS-Copy Access-Tunnel 1
+VALUE SN-Subscriber-IP-TOS-Copy Data-Tunnel 2
+VALUE SN-Subscriber-IP-TOS-Copy Both 3
+
+VALUE SN-Subscriber-No-Interims Disabled 0
+VALUE SN-Subscriber-No-Interims Enabled 1
+
+VALUE SN-Subs-VJ-Slotid-Cmp-Neg-Mode None 0
+VALUE SN-Subs-VJ-Slotid-Cmp-Neg-Mode Receive 1
+VALUE SN-Subs-VJ-Slotid-Cmp-Neg-Mode Transmit 2
+VALUE SN-Subs-VJ-Slotid-Cmp-Neg-Mode Both 3
+
+VALUE SN-Tp-Dnlk-Exceed-Action Transmit 0
+VALUE SN-Tp-Dnlk-Exceed-Action Drop 1
+VALUE SN-Tp-Dnlk-Exceed-Action Lower-IP-Precedence 2
+VALUE SN-Tp-Dnlk-Exceed-Action Buffer 3
+VALUE SN-Tp-Dnlk-Exceed-Action Transmit-On-Buffer-Full 4
+
+VALUE SN-Tp-Dnlk-Violate-Action Transmit 0
+VALUE SN-Tp-Dnlk-Violate-Action Drop 1
+VALUE SN-Tp-Dnlk-Violate-Action Lower-IP-Precedence 2
+VALUE SN-Tp-Dnlk-Violate-Action Buffer 3
+VALUE SN-Tp-Dnlk-Violate-Action Transmit-On-Buffer-Full 4
+
+VALUE SN-Tp-Uplk-Exceed-Action Transmit 0
+VALUE SN-Tp-Uplk-Exceed-Action Drop 1
+VALUE SN-Tp-Uplk-Exceed-Action Lower-IP-Precedence 2
+VALUE SN-Tp-Uplk-Exceed-Action Buffer 3
+VALUE SN-Tp-Uplk-Exceed-Action Transmit-On-Buffer-Full 4
+
+VALUE SN-Tp-Uplk-Violate-Action Transmit 0
+VALUE SN-Tp-Uplk-Violate-Action Drop 1
+VALUE SN-Tp-Uplk-Violate-Action Lower-IP-Precedence 2
+VALUE SN-Tp-Uplk-Violate-Action Buffer 3
+VALUE SN-Tp-Uplk-Violate-Action Transmit-On-Buffer-Full 4
+
+VALUE SN-Tun-Addr-Policy no-local-alloc-validate 0
+VALUE SN-Tun-Addr-Policy local-alloc 1
+VALUE SN-Tun-Addr-Policy local-alloc-validate 2
+
+VALUE SN-Tunnel-Gn Disabled 0
+VALUE SN-Tunnel-Gn Enabled 1
+
+VALUE SN-Tunnel-Load-Balancing random 1
+VALUE SN-Tunnel-Load-Balancing balanced 2
+VALUE SN-Tunnel-Load-Balancing prioritized 3
+
+VALUE SN-Visiting-Sub-Use-GGSN Deny 0
+VALUE SN-Visiting-Sub-Use-GGSN Accept 1
+
+VALUE SN-WiMAX-Auth-Only Disabled 0
+VALUE SN-WiMAX-Auth-Only Enabled 1
+
+VALUE SN-User-Privilege Administrative 6
+VALUE SN-User-Privilege NAS_Prompt 7
+VALUE SN-User-Privilege Inspector 19650516
+VALUE SN-User-Privilege Security_Admin 19660618
+
+VALUE SN-IPv6-Alloc-Method Alloc_Local_Pool 0
+VALUE SN-IPv6-Alloc-Method Alloc_Dhcp_Client 1
+VALUE SN-IPv6-Alloc-Method Alloc_No_Alloc 2
+VALUE SN-IPv6-Alloc-Method Alloc_Static_Alloc 3
+
+VALUE SN-WSG-MIP-Required No 0
+VALUE SN-WSG-MIP-Required Yes 1
+
+VALUE SN-WSG-MIP-Release-TIA No 0
+VALUE SN-WSG-MIP-Release-TIA Yes 1
+
+VALUE SN-WSG-MIP-Simple-IP-Fallback No 0
+VALUE SN-WSG-MIP-Simple-IP-Fallback Yes 1
+
+END-VENDOR Starent
diff --git a/share/dictionary.starent.vsa1 b/share/dictionary.starent.vsa1
new file mode 100644
index 0000000..282a7b7
--- /dev/null
+++ b/share/dictionary.starent.vsa1
@@ -0,0 +1,1202 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Starent dictionary
+# http://www.starentnetworks.com/
+#
+# Starent dictionary with 1 byte tag and 1 byte length.
+#
+# It conflicts with the standard Starent dictionary, so it is not
+# included by default.
+#
+# The source of this document is a Cisco Manual:
+# "Cisco ASR 5000 Series AAA and GTP Interface Administration and
+# Reference Release 12.x (Last Updated May 31, 2011)"
+#
+# This document is available at:
+# http://www.cisco.com/en/US/products/ps11072/products_implementation_design_guides_list.html
+#
+##############################################################################
+
+VENDOR Starent 8164 format=1,1
+
+BEGIN-VENDOR Starent
+
+ATTRIBUTE SN1-VPN-ID 1 integer
+ATTRIBUTE SN1-VPN-Name 2 string
+ATTRIBUTE SN1-Disconnect-Reason 3 integer
+ATTRIBUTE SN1-PPP-Progress-Code 4 integer
+ATTRIBUTE SN1-Primary-DNS-Server 5 ipaddr
+ATTRIBUTE SN1-Secondary-DNS-Server 6 ipaddr
+ATTRIBUTE SN1-Re-CHAP-Interval 7 integer
+ATTRIBUTE SN1-IP-Pool-Name 8 string
+ATTRIBUTE SN1-PPP-Data-Compression 9 integer
+ATTRIBUTE SN1-IP-Filter-In 10 string
+ATTRIBUTE SN1-IP-Filter-Out 11 string
+ATTRIBUTE SN1-Local-IP-Address 13 ipaddr
+ATTRIBUTE SN1-IP-Source-Validation 14 integer
+ATTRIBUTE SN1-PPP-Outbound-Password 15 string
+ATTRIBUTE SN1-PPP-Keepalive 16 integer
+ATTRIBUTE SN1-IP-In-ACL 17 string
+ATTRIBUTE SN1-IP-Out-ACL 18 string
+ATTRIBUTE SN1-PPP-Data-Compression-Mode 19 integer
+ATTRIBUTE SN1-Subscriber-Permission 20 integer
+ATTRIBUTE SN1-Admin-Permission 21 integer
+ATTRIBUTE SN1-Simultaneous-SIP-MIP 22 integer
+ATTRIBUTE SN1-Min-Compress-Size 23 integer
+ATTRIBUTE SN1-Service-Type 24 integer
+ATTRIBUTE SN1-DNS-Proxy-Use-Subscr-Addr 25 integer
+ATTRIBUTE SN1-Tunnel-Password 26 octets
+ATTRIBUTE SN1-Tunnel-Load-Balancing 27 integer
+ATTRIBUTE SN1-MN-HA-Timestamp-Tolerance 30 integer
+ATTRIBUTE SN1-Prepaid-Compressed-Count 31 integer
+ATTRIBUTE SN1-Prepaid-Inbound-Octets 32 integer
+ATTRIBUTE SN1-Prepaid-Outbound-Octets 33 integer
+ATTRIBUTE SN1-Prepaid-Total-Octets 34 integer
+ATTRIBUTE SN1-Prepaid-Timeout 35 integer
+ATTRIBUTE SN1-Prepaid-Watermark 36 integer
+ATTRIBUTE SN1-NAI-Construction-Domain 37 string
+ATTRIBUTE SN1-Tunnel-ISAKMP-Crypto-Map 38 string
+ATTRIBUTE SN1-Tunnel-ISAKMP-Secret 39 string
+ATTRIBUTE SN1-Ext-Inline-Srvr-Context 41 string
+ATTRIBUTE SN1-L3-to-L2-Tun-Addr-Policy 43 integer
+ATTRIBUTE SN1-Long-Duration-Timeout 44 integer
+ATTRIBUTE SN1-Long-Duration-Action 45 integer
+ATTRIBUTE SN1-PDSN1-Handoff-Req-IP-Addr 46 integer
+ATTRIBUTE SN1-HA-Send-DNS-ADDRESS 47 integer
+ATTRIBUTE SN1-MIP-Send-Term-Verification 48 integer
+ATTRIBUTE SN1-Data-Tunnel-Ignore-DF-Bit 49 integer
+ATTRIBUTE SN1-MIP-AAA-Assign-Addr 50 integer
+ATTRIBUTE SN1-Proxy-MIP 52 integer
+ATTRIBUTE SN1-MIP-Match-AAA-Assign-Addr 51 integer
+ATTRIBUTE SN1-IP-Alloc-Method 53 integer
+ATTRIBUTE SN1-Gratuitous-ARP-Aggressive 54 integer
+ATTRIBUTE SN1-Ext-Inline-Srvr-Up-Addr 55 ipaddr
+ATTRIBUTE SN1-Ext-Inline-Srvr-Down-Addr 56 ipaddr
+ATTRIBUTE SN1-Ext-Inline-Srvr-Preference 57 integer
+ATTRIBUTE SN1-Ext-Inline-Srvr-Up-VLAN 58 octets
+ATTRIBUTE SN1-Ext-Inline-Srvr-Down-VLAN 59 octets
+ATTRIBUTE SN1-IP-Hide-Service-Address 60 integer
+ATTRIBUTE SN1-PPP-Outbound-Username 61 string
+ATTRIBUTE SN1-GTP-Version 62 integer
+ATTRIBUTE SN1-Access-link-IP-Frag 63 integer
+ATTRIBUTE SN1-Subscriber-Accounting 64 integer
+ATTRIBUTE SN1-Nw-Reachability-Server-Name 65 string
+ATTRIBUTE SN1-Subscriber-IP-Hdr-Neg-Mode 67 integer
+ATTRIBUTE SN1-GGSN1-MIP-Required 68 integer
+ATTRIBUTE SN1-Subscriber-Acct-Start 69 integer
+ATTRIBUTE SN1-Subscriber-Acct-Interim 70 integer
+ATTRIBUTE SN1-Subscriber-Acct-Stop 71 integer
+ATTRIBUTE SN1-QoS-Tp-Dnlk 73 integer
+ATTRIBUTE SN1-Tp-Dnlk-Committed-Data-Rate 74 integer
+ATTRIBUTE SN1-Tp-Dnlk-Peak-Data-Rate 75 integer
+ATTRIBUTE SN1-Tp-Dnlk-Burst-Size 76 integer
+ATTRIBUTE SN1-Tp-Dnlk-Exceed-Action 77 integer
+ATTRIBUTE SN1-Tp-Dnlk-Violate-Action 78 integer
+ATTRIBUTE SN1-QoS-Tp-Uplk 79 integer
+ATTRIBUTE SN1-Tp-Uplk-Committed-Data-Rate 80 integer
+ATTRIBUTE SN1-Tp-Uplk-Peak-Data-Rate 81 integer
+ATTRIBUTE SN1-Tp-Uplk-Burst-Size 82 integer
+ATTRIBUTE SN1-Tp-Uplk-Exceed-Action 83 integer
+ATTRIBUTE SN1-Tp-Uplk-Violate-Action 84 integer
+ATTRIBUTE SN1-Subscriber-IP-TOS-Copy 85 integer
+ATTRIBUTE SN1-QoS-Conversation-Class 86 octets
+ATTRIBUTE SN1-QoS-Streaming-Class 87 octets
+ATTRIBUTE SN1-QoS-Interactive1-Class 88 octets
+ATTRIBUTE SN1-QoS-Interactive2-Class 89 octets
+ATTRIBUTE SN1-QoS-Interactive3-Class 90 octets
+ATTRIBUTE SN1-QoS-Background-Class 91 octets
+ATTRIBUTE SN1-PPP-NW-Layer-IPv4 92 integer
+ATTRIBUTE SN1-PPP-NW-Layer-IPv6 93 integer
+ATTRIBUTE SN1-Virtual-APN-Name 94 string
+ATTRIBUTE SN1-PPP-Accept-Peer-v6Ifid 95 integer
+ATTRIBUTE SN1-IPv6-rtr-advt-interval 96 integer
+ATTRIBUTE SN1-IPv6-num-rtr-advt 97 integer
+ATTRIBUTE SN1-NPU-Qos-Priority 98 integer
+ATTRIBUTE SN1-MN-HA-Hash-Algorithm 99 integer
+ATTRIBUTE SN1-Subscriber-Acct-Rsp-Action 100 integer
+ATTRIBUTE SN1-IPv6-Primary-DNS 101 ipv6addr
+ATTRIBUTE SN1-IPv6-Secondary-DNS 102 octets
+ATTRIBUTE SN1-IPv6-Egress-Filtering 103 integer
+ATTRIBUTE SN1-Mediation-VPN-Name 104 string
+ATTRIBUTE SN1-Mediation-Acct-Rsp-Action 105 integer
+ATTRIBUTE SN1-Home-Sub-Use-GGSN 106 integer
+ATTRIBUTE SN1-Visiting-Sub-Use-GGSN 107 integer
+ATTRIBUTE SN1-Roaming-Sub-Use-GGSN 108 integer
+ATTRIBUTE SN1-Home-Profile 109 integer
+ATTRIBUTE SN1-IP-Src-Validation-Drop-Limit 110 integer
+ATTRIBUTE SN1-QoS-Class-Conversational-PHB 111 integer
+ATTRIBUTE SN1-QoS-Class-Streaming-PHB 112 integer
+ATTRIBUTE SN1-QoS-Class-Background-PHB 113 integer
+ATTRIBUTE SN1-QoS-Class-Interactive-1-PHB 114 integer
+ATTRIBUTE SN1-QoS-Class-Interactive-2-PHB 115 integer
+ATTRIBUTE SN1-QoS-Class-Interactive-3-PHB 116 integer
+ATTRIBUTE SN1-Visiting-Profile 117 integer
+ATTRIBUTE SN1-Roaming-Profile 118 integer
+ATTRIBUTE SN1-Home-Behavior 119 integer
+ATTRIBUTE SN1-Visiting-Behavior 120 integer
+ATTRIBUTE SN1-Roaming-Behavior 121 integer
+ATTRIBUTE SN1-Internal-SM-Index 122 integer
+ATTRIBUTE SN1-Mediation-Enabled 123 integer
+ATTRIBUTE SN1-IPv6-Sec-Pool 124 string
+ATTRIBUTE SN1-IPv6-Sec-Prefix 125 octets
+ATTRIBUTE SN1-IPv6-DNS-Proxy 126 integer
+ATTRIBUTE SN1-Subscriber-Nexthop-Address 127 integer
+ATTRIBUTE SN1-Prepaid 128 integer
+ATTRIBUTE SN1-Prepaid-Preference 129 integer
+ATTRIBUTE SN1-PPP-Always-On-Vse 130 integer
+ATTRIBUTE SN1-Voice-Push-List-Name 131 string
+ATTRIBUTE SN1-Unclassify-List-Name 132 string
+ATTRIBUTE SN1-Subscriber-No-Interims 133 integer
+ATTRIBUTE SN1-Permit-User-Mcast-PDUs 134 integer
+ATTRIBUTE SN1-Prepaid-Final-Duration-Alg 135 integer
+ATTRIBUTE SN1-IPv6-Min-Link-MTU 136 integer
+ATTRIBUTE SN1-Charging-VPN-Name 137 string
+ATTRIBUTE SN1-Chrg-Char-Selection-Mode 138 integer
+ATTRIBUTE SN1-Cause-For-Rec-Closing 139 integer
+ATTRIBUTE SN1-Change-Condition 140 integer
+ATTRIBUTE SN1-Dynamic-Addr-Alloc-Ind-Flag 141 octets
+ATTRIBUTE SN1-Ntk-Initiated-Ctx-Ind-Flag 142 octets
+ATTRIBUTE SN1-Ntk-Session-Disconnect-Flag 143 integer
+ATTRIBUTE SN1-Enable-QoS-Renegotiation 144 integer
+ATTRIBUTE SN1-QoS-Renegotiation-Timeout 145 integer
+ATTRIBUTE SN1-QoS-Negotiated 147 string
+ATTRIBUTE SN1-Mediation-No-Interims 146 integer
+ATTRIBUTE SN1-Primary-NBNS-Server 148 ipaddr
+ATTRIBUTE SN1-Secondary-NBNS-Server 149 ipaddr
+ATTRIBUTE SN1-IP-Header-Compression 150 integer
+ATTRIBUTE SN1-Mode 151 integer
+#ATTRIBUTE SN1-ROHC-Mode 151 integer
+ATTRIBUTE SN1-Assigned-VLAN-ID 152 short
+ATTRIBUTE SN1-Direction 153 integer
+ATTRIBUTE SN1-MIP-HA-Assignment-Table 154 string
+ATTRIBUTE SN1-Tun-Addr-Policy 156 integer
+ATTRIBUTE SN1-DHCP-Lease-Expiry-Policy 157 integer
+ATTRIBUTE SN1-Subscriber-Template-Name 158 string
+ATTRIBUTE SN1-Subs-IMSA-Service-Name 159 string
+ATTRIBUTE SN1-Traffic-Group 161 integer
+ATTRIBUTE SN1-Rad-APN-Name 162 octets
+ATTRIBUTE SN1-MIP-Send-Ancid 163 integer
+ATTRIBUTE SN1-MIP-Send-Imsi 164 integer
+ATTRIBUTE SN1-MIP-Dual-Anchor 165 integer
+ATTRIBUTE SN1-MIP-ANCID 166 octets
+ATTRIBUTE SN1-IMS-AM-Address 167 ipaddr
+ATTRIBUTE SN1-IMS-AM-Domain-Name 168 octets
+ATTRIBUTE SN1-Service-Address 169 ipaddr
+ATTRIBUTE SN1-PDIF-MIP-Required 170 integer
+ATTRIBUTE SN1-FMC-Location 171 octets
+ATTRIBUTE SN1-PDIF-MIP-Release-TIA 172 integer
+ATTRIBUTE SN1-PDIF-MIP-Simple-IP-Fallback 173 integer
+ATTRIBUTE SN1-Tunnel-Gn 174 integer
+ATTRIBUTE SN1-MIP-Reg-Lifetime-Realm 175 integer
+ATTRIBUTE SN1-Ecs-Data-Volume 176 octets
+ATTRIBUTE SN1-QoS-Traffic-Policy 177 octets
+ATTRIBUTE SN1-ANID 178 octets
+ATTRIBUTE SN1-PPP-Reneg-Disc 187 integer
+ATTRIBUTE SN1-MIP-Send-Correlation-Info 188 integer
+ATTRIBUTE SN1-PDSN1-Correlation-Id 189 octets
+ATTRIBUTE SN1-PDSN1-NAS-Id 190 string
+ATTRIBUTE SN1-PDSN1-NAS-IP-Address 191 ipaddr
+ATTRIBUTE SN1-Subscriber-Acct-Mode 192 integer
+ATTRIBUTE SN1-IP-In-Plcy-Grp 193 string
+ATTRIBUTE SN1-IP-Out-Plcy-Grp 194 string
+ATTRIBUTE SN1-IP-Source-Violate-No-Acct 196 integer
+ATTRIBUTE SN1-Firewall-Enabled 198 integer
+ATTRIBUTE SNA-PPP-Unfr-data-In-Oct 200 integer
+ATTRIBUTE SNA-PPP-Unfr-data-Out-Oct 201 integer
+ATTRIBUTE SNA-PPP-Unfr-Data-In-Gig 202 integer
+ATTRIBUTE SNA-PPP-Unfr-Data-Out-Gig 203 integer
+ATTRIBUTE SN1-Admin-Expiry 204 integer
+ATTRIBUTE SNA-Input-Gigawords 206 integer
+ATTRIBUTE SNA-Output-Gigawords 207 integer
+ATTRIBUTE SN1-DNS-Proxy-Intercept-List 214 string
+ATTRIBUTE SN1-Subscriber-Class 219 integer
+ATTRIBUTE SN1-CFPolicy-ID 220 integer
+ATTRIBUTE SN1-Subs-VJ-Slotid-Cmp-Neg-Mode 221 integer
+ATTRIBUTE SN1-Primary-DCCA-Peer 223 string
+ATTRIBUTE SN1-Secondary-DCCA-Peer 224 string
+ATTRIBUTE SN1-Subs-Acc-Flow-Traffic-Valid 225 integer
+ATTRIBUTE SN1-Acct-Input-Packets-Dropped 226 integer
+ATTRIBUTE SN1-Acct-Output-Packets-Dropped 227 integer
+ATTRIBUTE SN1-Acct-Input-Octets-Dropped 228 integer64
+ATTRIBUTE SN1-Acct-Output-Octets-Dropped 229 integer64
+ATTRIBUTE SN1-Acct-Input-Giga-Dropped 230 integer
+ATTRIBUTE SN1-Acct-Output-Giga-Dropped 231 integer
+ATTRIBUTE SN1-Overload-Disc-Connect-Time 233 integer
+ATTRIBUTE SN1-Overload-Disconnect 235 integer
+ATTRIBUTE SN1-Radius-Returned-Username 236 integer
+ATTRIBUTE SN1-ROHC-Profile-Name 238 string
+ATTRIBUTE SN1-Firewall-Policy 239 octets
+ATTRIBUTE SN1-Transparent-Data 247 octets
+ATTRIBUTE SN1-MS-ISDN 248 octets
+ATTRIBUTE SN1-Routing-Area-Id 249 string
+#ATTRIBUTE SN1-Rulebase 249 string
+ATTRIBUTE SN1-Call-Id 251 integer
+ATTRIBUTE SN1-IMSI 252 octets
+ATTRIBUTE SN1-Long-Duration-Notification 253 integer
+ATTRIBUTE SN1-SIP-Method 254 integer
+ATTRIBUTE SN1-Event 255 string
+
+VALUE SN1-Disconnect-Reason Not-Defined 0
+VALUE SN1-Disconnect-Reason Admin-Disconnect 1
+VALUE SN1-Disconnect-Reason Remote-Disconnect 2
+VALUE SN1-Disconnect-Reason Local-Disconnect 3
+VALUE SN1-Disconnect-Reason Disc-No-Resource 4
+VALUE SN1-Disconnect-Reason Disc-Excd-Service-Limit 5
+VALUE SN1-Disconnect-Reason PPP-LCP-Neg-Failed 6
+VALUE SN1-Disconnect-Reason PPP-LCP-No-Response 7
+VALUE SN1-Disconnect-Reason PPP-LCP-Loopback 8
+VALUE SN1-Disconnect-Reason PPP-LCP-Max-Retry 9
+VALUE SN1-Disconnect-Reason PPP-Echo-Failed 10
+VALUE SN1-Disconnect-Reason PPP-Auth-Failed 11
+VALUE SN1-Disconnect-Reason PPP-Auth-Failed-No-AAA-Resp 12
+VALUE SN1-Disconnect-Reason PPP-Auth-No-Response 13
+VALUE SN1-Disconnect-Reason PPP-Auth-Max-Retry 14
+VALUE SN1-Disconnect-Reason Invalid-AAA-Attr 15
+VALUE SN1-Disconnect-Reason Failed-User-Filter 16
+VALUE SN1-Disconnect-Reason Failed-Provide-Service 17
+VALUE SN1-Disconnect-Reason Invalid-IP-Address-AAA 18
+VALUE SN1-Disconnect-Reason Invalid-IP-Pool-AAA 19
+VALUE SN1-Disconnect-Reason PPP-IPCP-Neg-Failed 20
+VALUE SN1-Disconnect-Reason PPP-IPCP-No-Response 21
+VALUE SN1-Disconnect-Reason PPP-IPCP-Max-Retry 22
+VALUE SN1-Disconnect-Reason PPP-No-Rem-IP-Address 23
+VALUE SN1-Disconnect-Reason Inactivity-Timeout 24
+VALUE SN1-Disconnect-Reason Session-Timeout 25
+VALUE SN1-Disconnect-Reason Max-Data-Excd 26
+VALUE SN1-Disconnect-Reason Invalid-IP-Source-Address 27
+VALUE SN1-Disconnect-Reason MSID-Auth-Failed 28
+VALUE SN1-Disconnect-Reason MSID-Auth-Fauiled-No-AAA-Resp 29
+VALUE SN1-Disconnect-Reason A11-Max-Retry 30
+VALUE SN1-Disconnect-Reason A11-Lifetime-Expired 31
+VALUE SN1-Disconnect-Reason A11-Message-Integrity-Failure 32
+VALUE SN1-Disconnect-Reason PPP-lcp-remote-disc 33
+VALUE SN1-Disconnect-Reason Session-setup-timeout 34
+VALUE SN1-Disconnect-Reason PPP-keepalive-failure 35
+VALUE SN1-Disconnect-Reason Flow-add-failed 36
+VALUE SN1-Disconnect-Reason Call-type-detection-failed 37
+VALUE SN1-Disconnect-Reason Wrong-ipcp-params 38
+VALUE SN1-Disconnect-Reason MIP-remote-dereg 39
+VALUE SN1-Disconnect-Reason MIP-lifetime-expiry 40
+VALUE SN1-Disconnect-Reason MIP-proto-error 41
+VALUE SN1-Disconnect-Reason MIP-auth-failure 42
+VALUE SN1-Disconnect-Reason MIP-reg-timeout 43
+VALUE SN1-Disconnect-Reason Invalid-dest-context 44
+VALUE SN1-Disconnect-Reason Source-context-removed 45
+VALUE SN1-Disconnect-Reason Destination-context-removed 46
+VALUE SN1-Disconnect-Reason Req-service-addr-unavailable 47
+VALUE SN1-Disconnect-Reason Demux-mgr-failed 48
+VALUE SN1-Disconnect-Reason Internal-error 49
+VALUE SN1-Disconnect-Reason AAA-context-removed 50
+VALUE SN1-Disconnect-Reason invalid-service-type 51
+VALUE SN1-Disconnect-Reason mip-relay-req-failed 52
+VALUE SN1-Disconnect-Reason mip-rcvd-relay-failure 53
+VALUE SN1-Disconnect-Reason ppp-restart-inter-pdsn-handoff 54
+VALUE SN1-Disconnect-Reason gre-key-mismatch 55
+VALUE SN1-Disconnect-Reason invalid_tunnel_context 56
+VALUE SN1-Disconnect-Reason no_peer_lns_address 57
+VALUE SN1-Disconnect-Reason failed_tunnel_connect 58
+VALUE SN1-Disconnect-Reason l2tp-tunnel-disconnect-remote 59
+VALUE SN1-Disconnect-Reason l2tp-tunnel-timeout 60
+VALUE SN1-Disconnect-Reason l2tp-protocol-error-remote 61
+VALUE SN1-Disconnect-Reason l2tp-protocol-error-local 62
+VALUE SN1-Disconnect-Reason l2tp-auth-failed-remote 63
+VALUE SN1-Disconnect-Reason l2tp-auth-failed-local 64
+VALUE SN1-Disconnect-Reason l2tp-try-another-lns-from-remote 65
+VALUE SN1-Disconnect-Reason l2tp-no-resource-local 66
+VALUE SN1-Disconnect-Reason l2tp-no-resource-remote 67
+VALUE SN1-Disconnect-Reason l2tp-tunnel-disconnect-local 68
+VALUE SN1-Disconnect-Reason l2tp-admin-disconnect_remote 69
+VALUE SN1-Disconnect-Reason l2tpmgr-reached-max-capacity 70
+VALUE SN1-Disconnect-Reason MIP-reg-revocation 71
+VALUE SN1-Disconnect-Reason path-failure 72
+VALUE SN1-Disconnect-Reason dhcp-relay-ip-validation-failed 73
+VALUE SN1-Disconnect-Reason gtp-unknown-pdp-addr-or-pdp-type 74
+VALUE SN1-Disconnect-Reason gtp-all-dynamic-pdp-addr-occupied 75
+VALUE SN1-Disconnect-Reason gtp-no-memory-is-available 76
+VALUE SN1-Disconnect-Reason dhcp-relay-static-ip-addr-not-allowed 77
+VALUE SN1-Disconnect-Reason dhcp-no-ip-addr-allocated 78
+VALUE SN1-Disconnect-Reason dhcp-ip-addr-allocation-tmr-exp 79
+VALUE SN1-Disconnect-Reason dhcp-ip-validation-failed 80
+VALUE SN1-Disconnect-Reason dhcp-static-addr-not-allowed 81
+VALUE SN1-Disconnect-Reason dhcp-ip-addr-not-available-at-present 82
+VALUE SN1-Disconnect-Reason dhcp-lease-expired 83
+VALUE SN1-Disconnect-Reason lpool-ip-validation-failed 84
+VALUE SN1-Disconnect-Reason lpool-static-ip-addr-not-allowed 85
+VALUE SN1-Disconnect-Reason static-ip-validation-failed 86
+VALUE SN1-Disconnect-Reason static-ip-addr-not-present 87
+VALUE SN1-Disconnect-Reason static-ip-addr-not-allowed 88
+VALUE SN1-Disconnect-Reason radius-ip-validation-failed 89
+VALUE SN1-Disconnect-Reason radius-ip-addr-not-provided 90
+VALUE SN1-Disconnect-Reason invalid-ip-addr-from-sgsn 91
+VALUE SN1-Disconnect-Reason no-more-sessions-in-aaa 92
+VALUE SN1-Disconnect-Reason ggsn-aaa-auth-req-failed 93
+VALUE SN1-Disconnect-Reason conflict-in-ip-addr-assignment 94
+VALUE SN1-Disconnect-Reason apn-removed 95
+VALUE SN1-Disconnect-Reason credits-used-bytes-in 96
+VALUE SN1-Disconnect-Reason credits-used-bytes-out 97
+VALUE SN1-Disconnect-Reason credits-used-bytes-total 98
+VALUE SN1-Disconnect-Reason prepaid-failed 99
+VALUE SN1-Disconnect-Reason l2tp-ipsec-tunnel-failure 100
+VALUE SN1-Disconnect-Reason l2tp-ipsec-tunnel-disconnected 101
+VALUE SN1-Disconnect-Reason mip-ipsec-sa-inactive 102
+VALUE SN1-Disconnect-Reason Long-Duration-Timeout 103
+VALUE SN1-Disconnect-Reason proxy-mip-registration-failure 104
+VALUE SN1-Disconnect-Reason proxy-mip-binding-update 105
+VALUE SN1-Disconnect-Reason proxy-mip-inter-pdsn-handoff-require-ip-address 106
+VALUE SN1-Disconnect-Reason proxy-mip-inter-pdsn-handoff-mismatched-address 107
+VALUE SN1-Disconnect-Reason Local-purge 108
+VALUE SN1-Disconnect-Reason failed-update-handoff 109
+VALUE SN1-Disconnect-Reason closed_rp-handoff-complete 110
+VALUE SN1-Disconnect-Reason closed_rp-duplicate-session 111
+VALUE SN1-Disconnect-Reason closed_rp-handoff-session-not-found 112
+VALUE SN1-Disconnect-Reason closed_rp-handoff-failed 113
+VALUE SN1-Disconnect-Reason pcf-monitor-keep-alive-failed 114
+VALUE SN1-Disconnect-Reason call-internal-reject 115
+VALUE SN1-Disconnect-Reason call-restarted 116
+VALUE SN1-Disconnect-Reason a11-mn-ha-auth-failure 117
+VALUE SN1-Disconnect-Reason a11-badly-formed 118
+VALUE SN1-Disconnect-Reason a11-t-bit-not-set 119
+VALUE SN1-Disconnect-Reason a11-unsupported-vendor-id 120
+VALUE SN1-Disconnect-Reason a11-mismatched-id 121
+VALUE SN1-Disconnect-Reason mipha-dup-home-addr-req 122
+VALUE SN1-Disconnect-Reason mipha-dup-imsi-session 123
+VALUE SN1-Disconnect-Reason ha-unreachable 124
+VALUE SN1-Disconnect-Reason IPSP-addr-in-use 125
+VALUE SN1-Disconnect-Reason mipfa-dup-home-addr-req 126
+VALUE SN1-Disconnect-Reason mipha-ip-pool-busyout 127
+VALUE SN1-Disconnect-Reason inter-pdsn-handoff 128
+VALUE SN1-Disconnect-Reason active-to-dormant 129
+VALUE SN1-Disconnect-Reason ppp-renegotiation 130
+VALUE SN1-Disconnect-Reason active-start-param-change 131
+VALUE SN1-Disconnect-Reason tarrif-boundary 132
+VALUE SN1-Disconnect-Reason a11-disconnect-no-active-stop 133
+VALUE SN1-Disconnect-Reason nw-reachability-failed-reject 134
+VALUE SN1-Disconnect-Reason nw-reachability-failed-redirect 135
+VALUE SN1-Disconnect-Reason container-max-exceeded 136
+VALUE SN1-Disconnect-Reason static-addr-not-allowed-in-apn 137
+VALUE SN1-Disconnect-Reason static-addr-required-by-radius 138
+VALUE SN1-Disconnect-Reason static-addr-not-allowed-by-radius 139
+VALUE SN1-Disconnect-Reason mip-registration-dropped 140
+VALUE SN1-Disconnect-Reason counter-rollover 141
+VALUE SN1-Disconnect-Reason constructed-nai-auth-fail 142
+VALUE SN1-Disconnect-Reason inter-pdsn-service-optimize-handoff-disabled 143
+VALUE SN1-Disconnect-Reason gre-key-collision 144
+VALUE SN1-Disconnect-Reason inter-pdsn-service-optimize-handoff-triggered 145
+VALUE SN1-Disconnect-Reason intra-pdsn-handoff-triggered 146
+VALUE SN1-Disconnect-Reason delayed-abort-timer-expired 147
+VALUE SN1-Disconnect-Reason Admin-AAA-disconnect 148
+VALUE SN1-Disconnect-Reason Admin-AAA-disconnect-handoff 149
+VALUE SN1-Disconnect-Reason PPP-IPV6CP-Neg-Failed 150
+VALUE SN1-Disconnect-Reason PPP-IPV6CP-No-Response 151
+VALUE SN1-Disconnect-Reason PPP-IPV6CP-Max-Retry 152
+VALUE SN1-Disconnect-Reason PPP-Restart-Invalid-source-IPV4-address 153
+VALUE SN1-Disconnect-Reason a11-disconnect-handoff-no-active-stop 154
+VALUE SN1-Disconnect-Reason call-restarted-inter-pdsn-handoff 155
+VALUE SN1-Disconnect-Reason call-restarted-ppp-termination 156
+VALUE SN1-Disconnect-Reason mipfa-resource-conflict 157
+VALUE SN1-Disconnect-Reason failed-auth-with-charging-svc 158
+VALUE SN1-Disconnect-Reason mipha-dup-imsi-session-purge 159
+VALUE SN1-Disconnect-Reason mipha-rev-pending-newcall 160
+VALUE SN1-Disconnect-Reason volume-quota-reached 161
+VALUE SN1-Disconnect-Reason duration-quota-reached 162
+VALUE SN1-Disconnect-Reason gtp-user-authentication-failed 163
+VALUE SN1-Disconnect-Reason MIP-reg-revocation-no-lcp-term 164
+VALUE SN1-Disconnect-Reason MIP-private-ip-no-rev-tunnel 165
+VALUE SN1-Disconnect-Reason Invalid-Prepaid-AAA-attr-in-auth-response 166
+VALUE SN1-Disconnect-Reason mipha-prepaid-reset-dynamic-newcall 167
+VALUE SN1-Disconnect-Reason gre-flow-control-timeout 168
+VALUE SN1-Disconnect-Reason mip-paaa-bc-query-not-found 169
+VALUE SN1-Disconnect-Reason mipha-dynamic-ip-addr-not-available 170
+VALUE SN1-Disconnect-Reason a11-mismatched-id-on-handoff 171
+VALUE SN1-Disconnect-Reason a11-badly-formed-on-handoff 172
+VALUE SN1-Disconnect-Reason a11-unsupported-vendor-id-on-handoff 173
+VALUE SN1-Disconnect-Reason a11-t-bit-not-set-on-handoff 174
+VALUE SN1-Disconnect-Reason MIP-reg-revocation-i-bit-on 175
+VALUE SN1-Disconnect-Reason A11-RRQ-Deny-Max-Count 176
+VALUE SN1-Disconnect-Reason Dormant-Transition-During-Session-Setup 177
+VALUE SN1-Disconnect-Reason PPP-Rem-Reneg-Disc-Always-Cfg 178
+VALUE SN1-Disconnect-Reason PPP-Rem-Reneg-Disc-NAI-MSID-Mismatch 179
+VALUE SN1-Disconnect-Reason mipha-subscriber-ipsec-tunnel-down 180
+VALUE SN1-Disconnect-Reason mipha-subscriber-ipsec-tunnel-failed 181
+VALUE SN1-Disconnect-Reason mipha-subscriber-ipsecmgr-death 182
+VALUE SN1-Disconnect-Reason flow-is-deactivated 183
+VALUE SN1-Disconnect-Reason ecsv2-license-exceeded 184
+VALUE SN1-Disconnect-Reason IPSG-Auth-Failed 185
+VALUE SN1-Disconnect-Reason driver-initiated 186
+VALUE SN1-Disconnect-Reason ims-authorization-failed 187
+VALUE SN1-Disconnect-Reason service-instance-released 188
+VALUE SN1-Disconnect-Reason flow-released 189
+VALUE SN1-Disconnect-Reason ppp-renego-no-ha-addr 190
+VALUE SN1-Disconnect-Reason intra-pdsn-handoff 191
+VALUE SN1-Disconnect-Reason overload-disconnect 192
+VALUE SN1-Disconnect-Reason css-service-not-found 193
+VALUE SN1-Disconnect-Reason Auth-Failed 194
+VALUE SN1-Disconnect-Reason dhcp-client-sent-release 195
+VALUE SN1-Disconnect-Reason dhcp-client-sent-nak 196
+VALUE SN1-Disconnect-Reason msid-dhcp-chaddr-mismatch 197
+VALUE SN1-Disconnect-Reason link-broken 198
+VALUE SN1-Disconnect-Reason prog-end-timeout 199
+VALUE SN1-Disconnect-Reason qos-update-wait-timeout 200
+VALUE SN1-Disconnect-Reason css-synch-cause 201
+VALUE SN1-Disconnect-Reason Gtp-context-replacement 202
+VALUE SN1-Disconnect-Reason PDIF-Auth-failed 203
+VALUE SN1-Disconnect-Reason l2tp-unknown-apn 204
+VALUE SN1-Disconnect-Reason ms-unexpected-network-reentry 205
+VALUE SN1-Disconnect-Reason r6-invalid-nai 206
+VALUE SN1-Disconnect-Reason eap-max-retry-reached 207
+VALUE SN1-Disconnect-Reason vbm-hoa-session-disconnected 208
+VALUE SN1-Disconnect-Reason vbm-voa-session-disconnected 209
+VALUE SN1-Disconnect-Reason in-acl-disconnect-on-violation 210
+VALUE SN1-Disconnect-Reason eap-msk-lifetime-expiry 211
+VALUE SN1-Disconnect-Reason eap-msk-lifetime-too-low 212
+VALUE SN1-Disconnect-Reason mipfa-inter-tech-handoff 213
+VALUE SN1-Disconnect-Reason r6-max-retry-reached 214
+VALUE SN1-Disconnect-Reason r6-nwexit-recd 215
+VALUE SN1-Disconnect-Reason r6-dereg-req-recd 216
+VALUE SN1-Disconnect-Reason r6-remote-failure 217
+VALUE SN1-Disconnect-Reason r6r4-protocol-errors 218
+VALUE SN1-Disconnect-Reason wimax-qos-invalid-aaa-attr 219
+VALUE SN1-Disconnect-Reason npu-gre-flows-not-available 220
+VALUE SN1-Disconnect-Reason r4-max-retry-reached 221
+VALUE SN1-Disconnect-Reason r4-nwexit-recd 222
+VALUE SN1-Disconnect-Reason r4-dereg-req-recd 223
+VALUE SN1-Disconnect-Reason r4-remote-failure 224
+VALUE SN1-Disconnect-Reason ims-authorization-revoked 225
+VALUE SN1-Disconnect-Reason ims-authorization-released 226
+VALUE SN1-Disconnect-Reason ims-auth-decision-invalid 227
+VALUE SN1-Disconnect-Reason mac-addr-validation-failed 228
+VALUE SN1-Disconnect-Reason excessive-wimax-pd-flows-cfgd 229
+VALUE SN1-Disconnect-Reason sgsn-canc-loc-sub 230
+VALUE SN1-Disconnect-Reason sgsn-canc-loc-upd 231
+VALUE SN1-Disconnect-Reason sgsn-mnr-exp 232
+VALUE SN1-Disconnect-Reason sgsn-ident-fail 233
+VALUE SN1-Disconnect-Reason sgsn-sec-fail 234
+VALUE SN1-Disconnect-Reason sgsn-auth-fail 235
+VALUE SN1-Disconnect-Reason sgsn-glu-fail 236
+VALUE SN1-Disconnect-Reason sgsn-imp-det 237
+VALUE SN1-Disconnect-Reason sgsn-smgr-purge 238
+VALUE SN1-Disconnect-Reason sgsn-subs-handed-to-peer 239
+VALUE SN1-Disconnect-Reason sgsn-dns-fail-inter-rau 240
+VALUE SN1-Disconnect-Reason sgsn-cont-rsp-fail 241
+VALUE SN1-Disconnect-Reason sgsn-hlr-not-found-for-imsi 242
+VALUE SN1-Disconnect-Reason sgsn-ms-init-det 243
+VALUE SN1-Disconnect-Reason sgsn-opr-policy-fail 244
+VALUE SN1-Disconnect-Reason sgsn-duplicate-context 245
+VALUE SN1-Disconnect-Reason hss-profile-update-failed 246
+VALUE SN1-Disconnect-Reason sgsn-no-pdp-activated 247
+VALUE SN1-Disconnect-Reason asnpc-idle-mode-timeout 248
+VALUE SN1-Disconnect-Reason asnpc-idle-mode-exit 249
+VALUE SN1-Disconnect-Reason asnpc-idle-mode-auth-failed 250
+VALUE SN1-Disconnect-Reason asngw-invalid-qos-configuration 251
+VALUE SN1-Disconnect-Reason sgsn-dsd-allgprswithdrawn 252
+VALUE SN1-Disconnect-Reason r6-pmk-key-change-failure 253
+VALUE SN1-Disconnect-Reason sgsn-illegal-me 254
+VALUE SN1-Disconnect-Reason sess-termination-timeout 255
+VALUE SN1-Disconnect-Reason sgsn-sai-fail 256
+VALUE SN1-Disconnect-Reason sgsn-rnc-removal 257
+VALUE SN1-Disconnect-Reason sgsn-rai-removal 258
+VALUE SN1-Disconnect-Reason sgsn-init-deact 259
+VALUE SN1-Disconnect-Reason ggsn-init-deact 260
+VALUE SN1-Disconnect-Reason hlr-init-deact 261
+VALUE SN1-Disconnect-Reason ms-init-deact 262
+VALUE SN1-Disconnect-Reason sgsn-detach-init-deact 263
+VALUE SN1-Disconnect-Reason sgsn-rab-rel-init-deact 264
+VALUE SN1-Disconnect-Reason sgsn-iu-rel-init-deact 265
+VALUE SN1-Disconnect-Reason sgsn-gtpu-path-failure 266
+VALUE SN1-Disconnect-Reason sgsn-gtpc-path-failure 267
+VALUE SN1-Disconnect-Reason sgsn-local-handoff-init-deact 268
+VALUE SN1-Disconnect-Reason sgsn-remote-handoff-init-deact 269
+VALUE SN1-Disconnect-Reason sgsn-gtp-no-resource 270
+VALUE SN1-Disconnect-Reason sgsn-rnc-no-resource 271
+VALUE SN1-Disconnect-Reason sgsn-odb-init-deact 272
+VALUE SN1-Disconnect-Reason sgsn-invalid-ti 273
+VALUE SN1-Disconnect-Reason sgsn-ggsn-ctxt-non-existent 274
+VALUE SN1-Disconnect-Reason sgsn-apn-restrict-vio 275
+VALUE SN1-Disconnect-Reason sgsn-regular-deact 276
+VALUE SN1-Disconnect-Reason sgsn-abnormal-deact 277
+VALUE SN1-Disconnect-Reason sgsn-actv-rejected-by-peer 278
+VALUE SN1-Disconnect-Reason sgsn-err-ind 279
+VALUE SN1-Disconnect-Reason asngw-non-anchor-prohibited 280
+VALUE SN1-Disconnect-Reason asngw-im-entry-prohibited 281
+VALUE SN1-Disconnect-Reason session-idle-mode-entry-timeout 282
+VALUE SN1-Disconnect-Reason session-idle-mode-exit-timeout 283
+VALUE SN1-Disconnect-Reason asnpc-ms-power-down-nwexit 284
+VALUE SN1-Disconnect-Reason asnpc-r4-nwexit-recd 285
+VALUE SN1-Disconnect-Reason sgsn-iu-rel-before-call-est 286
+VALUE SN1-Disconnect-Reason ikev2-subscriber-ipsecmgr-death 287
+VALUE SN1-Disconnect-Reason All-dynamic-pool-addr-occupied 288
+VALUE SN1-Disconnect-Reason mip6ha-ip-addr-not-available 289
+VALUE SN1-Disconnect-Reason bs-monitor-keep-alive-failed 290
+VALUE SN1-Disconnect-Reason sgsn-att-in-reg-state 291
+VALUE SN1-Disconnect-Reason sgsn-inbound-srns-in-reg-state 292
+VALUE SN1-Disconnect-Reason dt-ggsn-tun-reestablish-failed 293
+VALUE SN1-Disconnect-Reason sgsn-unknown-pdp 294
+VALUE SN1-Disconnect-Reason sgsn-pdp-auth-failure 295
+VALUE SN1-Disconnect-Reason sgsn-duplicate-pdp-context 296
+VALUE SN1-Disconnect-Reason sgsn-no-rsp-from-ggsn 297
+VALUE SN1-Disconnect-Reason sgsn-failure-rsp-from-ggsn 298
+VALUE SN1-Disconnect-Reason sgsn-apn-unknown 299
+VALUE SN1-Disconnect-Reason sgsn-serv-req-init-deact 300
+VALUE SN1-Disconnect-Reason sgsn-attach-on-attch-init-abort 301
+VALUE SN1-Disconnect-Reason sgsn-iu-rel-in-israu-init-abort 302
+VALUE SN1-Disconnect-Reason sgsn-smgr-init-abort 303
+VALUE SN1-Disconnect-Reason sgsn-mm-ctx-cleanup-init-abort 304
+VALUE SN1-Disconnect-Reason sgsn-unknown-abort 305
+VALUE SN1-Disconnect-Reason sgsn-guard-timeout-abort 306
+VALUE SN1-Disconnect-Reason vpn-bounce-dhcpip-validate-req 307
+VALUE SN1-Disconnect-Reason mipv6-id-mismatch 308
+VALUE SN1-Disconnect-Reason aaa-session-id-not-found 309
+VALUE SN1-Disconnect-Reason x1-max-retry-reached 310
+VALUE SN1-Disconnect-Reason x1-nwexit-recd 311
+VALUE SN1-Disconnect-Reason x1-dereg-req-recd 312
+VALUE SN1-Disconnect-Reason x1-remote-failure 313
+VALUE SN1-Disconnect-Reason x1x2-protocol-errors 314
+VALUE SN1-Disconnect-Reason x2-max-retry-reached 315
+VALUE SN1-Disconnect-Reason x2-nwexit-recd 316
+VALUE SN1-Disconnect-Reason x2-dereg-req-recd 317
+VALUE SN1-Disconnect-Reason x2-remote-failure 318
+VALUE SN1-Disconnect-Reason x1-pmk-key-change-failure 319
+VALUE SN1-Disconnect-Reason sa-rekeying-failure 320
+VALUE SN1-Disconnect-Reason sess-sleep-mode-entry-timeout 321
+VALUE SN1-Disconnect-Reason phsgw-non-anchor-prohibited 322
+VALUE SN1-Disconnect-Reason asnpc-pc-relocation-failed 323
+VALUE SN1-Disconnect-Reason asnpc-pc-relocation 324
+VALUE SN1-Disconnect-Reason auth_policy_mismatch 325
+VALUE SN1-Disconnect-Reason sa-lifetime-expiry 326
+VALUE SN1-Disconnect-Reason asnpc-del-ms-entry-recd 327
+VALUE SN1-Disconnect-Reason phspc-sleep-mode-timeout 328
+VALUE SN1-Disconnect-Reason phspc-sleep-mode-exit 329
+VALUE SN1-Disconnect-Reason phspc-sleep-mode-auth-failed 330
+VALUE SN1-Disconnect-Reason phspc-ms-power-down-nwexit 331
+VALUE SN1-Disconnect-Reason phspc-x2-nwexit-recd 332
+VALUE SN1-Disconnect-Reason invalid-nat-config 333
+VALUE SN1-Disconnect-Reason asngw-tid-entry-not-found 334
+VALUE SN1-Disconnect-Reason No-NAT-IP-Address 335
+VALUE SN1-Disconnect-Reason excessive-phs-pd-flows-cfgd 336
+VALUE SN1-Disconnect-Reason phsgw-invalid-qos-configuration 337
+VALUE SN1-Disconnect-Reason Interim-Update 338
+VALUE SN1-Disconnect-Reason sgsn-attach-abrt-rad-lost 339
+VALUE SN1-Disconnect-Reason sgsn-inbnd-irau-abrt-rad-lost 340
+VALUE SN1-Disconnect-Reason ike-keepalive-failed 341
+VALUE SN1-Disconnect-Reason sgsn-attach-abrt-ms-suspend 342
+VALUE SN1-Disconnect-Reason sgsn-inbnd-irau-abrt-ms-suspend 343
+VALUE SN1-Disconnect-Reason duplicate-session-detected 344
+VALUE SN1-Disconnect-Reason sgsn-xid-response-failure 345
+VALUE SN1-Disconnect-Reason sgsn-nse-cleanup 346
+VALUE SN1-Disconnect-Reason sgsn-gtp-req-failure 347
+VALUE SN1-Disconnect-Reason sgsn-imsi-mismatch 348
+VALUE SN1-Disconnect-Reason sgsn-bvc-blocked 349
+VALUE SN1-Disconnect-Reason sgsn-attach-on-inbound-irau 350
+VALUE SN1-Disconnect-Reason sgsn-attach-on-outbound-irau 351
+VALUE SN1-Disconnect-Reason sgsn-incorrect-state 352
+VALUE SN1-Disconnect-Reason sgsn-t3350-expiry 353
+VALUE SN1-Disconnect-Reason sgsn-page-timer-expiry 354
+VALUE SN1-Disconnect-Reason phsgw-tid-entry-not-found 355
+VALUE SN1-Disconnect-Reason phspc-del-ms-entry-recd 356
+VALUE SN1-Disconnect-Reason sgsn-pdp-local-purge 357
+VALUE SN1-Disconnect-Reason phs-invalid-nai 358
+VALUE SN1-Disconnect-Reason session-sleep-mode-exit-timeout 359
+VALUE SN1-Disconnect-Reason sgsn-offload-phase2 360
+VALUE SN1-Disconnect-Reason phs-thirdparty-auth-fail 361
+VALUE SN1-Disconnect-Reason remote-error-notify 362
+VALUE SN1-Disconnect-Reason no-response 363
+VALUE SN1-Disconnect-Reason PDG-Auth-failed 364
+VALUE SN1-Disconnect-Reason mme-s1AP-send-failed 365
+VALUE SN1-Disconnect-Reason mme-egtpc-connection-failed 366
+VALUE SN1-Disconnect-Reason mme-egtpc-create-session-failed 367
+VALUE SN1-Disconnect-Reason mme-authentication-failure 368
+VALUE SN1-Disconnect-Reason mme-ue-detach 369
+VALUE SN1-Disconnect-Reason mme-mme-detach 370
+VALUE SN1-Disconnect-Reason mme-hss-detach 371
+VALUE SN1-Disconnect-Reason mme-pgw-detach 372
+VALUE SN1-Disconnect-Reason mme-sub-validation-failure 373
+VALUE SN1-Disconnect-Reason mme-hss-connection-failure 374
+VALUE SN1-Disconnect-Reason mme-hss-user-unknown 375
+VALUE SN1-Disconnect-Reason dhcp-lease-mismatch-detected 376
+VALUE SN1-Disconnect-Reason nemo-link-layer-down 377
+VALUE SN1-Disconnect-Reason eapol-max-retry-reached 378
+VALUE SN1-Disconnect-Reason sgsn-offload-phase3 379
+VALUE SN1-Disconnect-Reason mbms-bearer-service-disconnect 380
+VALUE SN1-Disconnect-Reason disconnect-on-violation-odb 381
+VALUE SN1-Disconnect-Reason disconn-on-violation-focs-odb 382
+VALUE SN1-Disconnect-Reason CSCF-REG-Admin-disconnect 383
+VALUE SN1-Disconnect-Reason CSCF-REG-User-disconnect 384
+VALUE SN1-Disconnect-Reason CSCF-REG-Inactivity-timeout 385
+VALUE SN1-Disconnect-Reason CSCF-REG-Network-disconnect 386
+VALUE SN1-Disconnect-Reason CSCF-Call-Admin-disconnect 387
+VALUE SN1-Disconnect-Reason CSCF-CAll-User-disconnect 388
+VALUE SN1-Disconnect-Reason CSCF-CALL-Local-disconnect 389
+VALUE SN1-Disconnect-Reason CSCF-CALL-No-Resource 390
+VALUE SN1-Disconnect-Reason CSCF-CALL-No-Respone 391
+VALUE SN1-Disconnect-Reason CSCF-CALL-Inactivity-timeout 392
+VALUE SN1-Disconnect-Reason CSCF-CALL-Media-Auth-Failure 393
+VALUE SN1-Disconnect-Reason CSCF-REG-No-Resource 394
+VALUE SN1-Disconnect-Reason ms-unexpected-idle-mode-entry 395
+VALUE SN1-Disconnect-Reason re-auth-failed 396
+VALUE SN1-Disconnect-Reason sgsn-pdp-nse-cleanup 397
+VALUE SN1-Disconnect-Reason sgsn-mm-ctxt-gtp-no-resource 398
+VALUE SN1-Disconnect-Reason unknown-apn 399
+VALUE SN1-Disconnect-Reason gtpc-path-failure 400
+VALUE SN1-Disconnect-Reason gtpu-path-failure 401
+VALUE SN1-Disconnect-Reason actv-rejected-by-sgsn 402
+VALUE SN1-Disconnect-Reason sgsn-pdp-gprs-camel-release 403
+VALUE SN1-Disconnect-Reason sgsn-check-imei-failure 404
+VALUE SN1-Disconnect-Reason sgsn-sndcp-init-deact 405
+VALUE SN1-Disconnect-Reason sgsn-pdp-inactivity-timeout 406
+VALUE SN1-Disconnect-Reason fw-and-nat-policy-removed 407
+VALUE SN1-Disconnect-Reason FNG-Auth-failed 408
+VALUE SN1-Disconnect-Reason ha-stale-key-disconnect 409
+VALUE SN1-Disconnect-Reason No-IPV6-address-for-subscriber 410
+VALUE SN1-Disconnect-Reason prefix-registration-failure 411
+VALUE SN1-Disconnect-Reason disconnect-from-policy-server 412
+VALUE SN1-Disconnect-Reason s6b-auth-failed 413
+VALUE SN1-Disconnect-Reason gtpc-err-ind 414
+VALUE SN1-Disconnect-Reason gtpu-err-ind 415
+VALUE SN1-Disconnect-Reason invalid-pdn-type 416
+VALUE SN1-Disconnect-Reason aaa-auth-req-failed 417
+VALUE SN1-Disconnect-Reason apn-denied-no-subscription 418
+VALUE SN1-Disconnect-Reason Sgw-context-replacement 419
+VALUE SN1-Disconnect-Reason dup-static-ip-addr-req 420
+VALUE SN1-Disconnect-Reason apn-restrict-violation 421
+VALUE SN1-Disconnect-Reason invalid-wapn 422
+VALUE SN1-Disconnect-Reason ttg-nsapi-allocation-failed 423
+VALUE SN1-Disconnect-Reason mandatory-gtp-ie-missing 424
+VALUE SN1-Disconnect-Reason aaa-unreachable 425
+VALUE SN1-Disconnect-Reason asngw-service-flow-deletion 426
+VALUE SN1-Disconnect-Reason CT-PMIP-RRQ-NVSE-Value-Change 427
+VALUE SN1-Disconnect-Reason tcp-read-failed 428
+VALUE SN1-Disconnect-Reason tcp-write-failed 429
+VALUE SN1-Disconnect-Reason ssl-handshake-failed 430
+VALUE SN1-Disconnect-Reason ssl-renegotiate-failed 431
+VALUE SN1-Disconnect-Reason ssl-bad-message 432
+VALUE SN1-Disconnect-Reason ssl-alert-received 433
+VALUE SN1-Disconnect-Reason ssl-disconnect 434
+VALUE SN1-Disconnect-Reason ssl-migration 435
+VALUE SN1-Disconnect-Reason sgsn-ard-failure 436
+VALUE SN1-Disconnect-Reason sgsn-camel-release 437
+VALUE SN1-Disconnect-Reason Hotlining-Status-Change 447
+VALUE SN1-Disconnect-Reason ggsn-no-rsp-from-sgsn 448
+VALUE SN1-Disconnect-Reason diameter-protocol-error 449
+VALUE SN1-Disconnect-Reason diameter-request-timeout 450
+VALUE SN1-Disconnect-Reason operator-policy 451
+VALUE SN1-Disconnect-Reason spr-connection-timeout 452
+VALUE SN1-Disconnect-Reason mipha-dup-wimax-session 453
+VALUE SN1-Disconnect-Reason invalid-version-attr 454
+VALUE SN1-Disconnect-Reason sgsn-zone-code-failure 455
+
+VALUE SN1-PPP-Progress-Code Not-Defined 0
+VALUE SN1-PPP-Progress-Code Call-Lcp-Down 1
+VALUE SN1-PPP-Progress-Code Call-Disconnecting 2
+VALUE SN1-PPP-Progress-Code Call-PPP-Renegotiating 3
+VALUE SN1-PPP-Progress-Code Call-Lcp-Down_1 10
+VALUE SN1-PPP-Progress-Code Call-Arrived 11
+VALUE SN1-PPP-Progress-Code Call-Lcp-Up 12
+VALUE SN1-PPP-Progress-Code Call-Authenticating 13
+VALUE SN1-PPP-Progress-Code Call-Authenticated 14
+VALUE SN1-PPP-Progress-Code Call-Ipcp-Up 15
+VALUE SN1-PPP-Progress-Code Call-Simple-IP-Connected 16
+VALUE SN1-PPP-Progress-Code Call-Mobile-IP-Connected 17
+#VALUE SN1-PPP-Progress-Code Call-Disconnecting 20
+#VALUE SN1-PPP-Progress-Code Call-PPP-Renegotiating 30
+#VALUE SN1-PPP-Progress-Code Call-Arrived 40
+VALUE SN1-PPP-Progress-Code Call-Pdg-Tcp-Connecting 45
+VALUE SN1-PPP-Progress-Code Call-Pdg-Ssl-Connecting 46
+#VALUE SN1-PPP-Progress-Code Call-Lcp-Up 50
+#VALUE SN1-PPP-Progress-Code Call-Authenticating 60
+VALUE SN1-PPP-Progress-Code Call-Bcmcs-Authenticating 70
+#VALUE SN1-PPP-Progress-Code Call-Authenticated 80
+VALUE SN1-PPP-Progress-Code Call-Tunnel-Connecting 85
+#VALUE SN1-PPP-Progress-Code Call-Ipcp-Up 90
+VALUE SN1-PPP-Progress-Code Call-Imsa-Authorizing 95
+VALUE SN1-PPP-Progress-Code Call-Imsa-Authorized 97
+VALUE SN1-PPP-Progress-Code Call-MBMS-UE-Authorizing 98
+VALUE SN1-PPP-Progress-Code Call-MBMS-Bearer-Authorizing 99
+#VALUE SN1-PPP-Progress-Code Call-Simple-IP-Connected 100
+#VALUE SN1-PPP-Progress-Code Call-Mobile-IP-Connected 110
+VALUE SN1-PPP-Progress-Code Call-Tunnel-Connected 115
+VALUE SN1-PPP-Progress-Code Call-Pdp-Type-IP-Connected 120
+VALUE SN1-PPP-Progress-Code Call-Pdp-Type-IPv6-Connected 125
+VALUE SN1-PPP-Progress-Code Call-Pdp-Type-PPP-Connected 130
+VALUE SN1-PPP-Progress-Code Call-Proxy-Mobile-IP-Connected 140
+VALUE SN1-PPP-Progress-Code Call-Pdg-Connected 142
+VALUE SN1-PPP-Progress-Code Call-Pdg-Ssl-Connected 141
+VALUE SN1-PPP-Progress-Code Call-Pdg-Connected 142
+VALUE SN1-PPP-Progress-Code Call-Pdg-Connected 142
+VALUE SN1-PPP-Progress-Code Call-Ipsg-Connected 145
+VALUE SN1-PPP-Progress-Code Call-Bcmcs-Connected 150
+VALUE SN1-PPP-Progress-Code Call-MBMS-UE-Connected 155
+VALUE SN1-PPP-Progress-Code Call-MBMS-Bearer-Connected 156
+VALUE SN1-PPP-Progress-Code Call-Pending-Addr-From-DHCP 160
+VALUE SN1-PPP-Progress-Code Call-Got-Addr-From-DHCP 170
+VALUE SN1-PPP-Progress-Code Call-HA-IPSEC-Tunnel-Connecting 180
+VALUE SN1-PPP-Progress-Code Call-HA-IPSEC-Connected 190
+VALUE SN1-PPP-Progress-Code Call-ASN-Non-Anchor-Connected 200
+VALUE SN1-PPP-Progress-Code Call-ASNPC-Connected 210
+VALUE SN1-PPP-Progress-Code Call-Mobile-IPv6-Connected 220
+VALUE SN1-PPP-Progress-Code Call-PMIPv6-Connected 221
+VALUE SN1-PPP-Progress-Code Call-PHSPC-Connected 230
+VALUE SN1-PPP-Progress-Code Call-GTP-IPv4-Connected 235
+VALUE SN1-PPP-Progress-Code Call-GTP-IPv6-Connected 236
+VALUE SN1-PPP-Progress-Code Call-GTP-IPv4-IPv6-Connected 237
+VALUE SN1-PPP-Progress-Code Call-SGW-Connected 245
+VALUE SN1-PPP-Progress-Code Call-MME-Attached 246
+VALUE SN1-PPP-Progress-Code Call-Auth-Only-Connected 247
+
+VALUE SN1-PPP-Data-Compression None 0
+VALUE SN1-PPP-Data-Compression Stac-LZS 1
+VALUE SN1-PPP-Data-Compression MPPC 2
+VALUE SN1-PPP-Data-Compression MPCC-Stac-LZS 3
+VALUE SN1-PPP-Data-Compression Deflate 4
+VALUE SN1-PPP-Data-Compression Deflate-Stac-LZS 5
+VALUE SN1-PPP-Data-Compression Deflate-MPCC 6
+VALUE SN1-PPP-Data-Compression Deflate-MPCC-Stac-LZS 7
+
+VALUE SN1-IP-Source-Validation No 0
+VALUE SN1-IP-Source-Validation Yes 1
+
+VALUE SN1-Subscriber-Permission None 0
+VALUE SN1-Subscriber-Permission Simple-IP 1
+VALUE SN1-Subscriber-Permission Mobile-IP 2
+VALUE SN1-Subscriber-Permission Simple-IP-Mobile-IP 3
+VALUE SN1-Subscriber-Permission HA-Mobile-IP 4
+VALUE SN1-Subscriber-Permission Simple-IP-HA-Mobile-IP 5
+VALUE SN1-Subscriber-Permission Mobile-IP-HA-Mobile-IP 6
+VALUE SN1-Subscriber-Permission All 7
+VALUE SN1-Subscriber-Permission GGSN-PDP-TYPE-IP 8
+VALUE SN1-Subscriber-Permission GGSN-PDP-TYPE-PPP 16
+VALUE SN1-Subscriber-Permission Network-Mobility 32
+VALUE SN1-Subscriber-Permission FA-HA-NEMO 38
+VALUE SN1-Subscriber-Permission All_ 63
+
+VALUE SN1-Admin-Permission None 0
+VALUE SN1-Admin-Permission CLI 1
+VALUE SN1-Admin-Permission FTP 2
+VALUE SN1-Admin-Permission CLI-FTP 3
+VALUE SN1-Admin-Permission Intercept 4
+VALUE SN1-Admin-Permission CLI-Intercept 5
+VALUE SN1-Admin-Permission CLI-Intercept-FTP 7
+VALUE SN1-Admin-Permission ECS 8
+VALUE SN1-Admin-Permission CLI-ECS 9
+VALUE SN1-Admin-Permission CLI-FTP-ECS 11
+VALUE SN1-Admin-Permission CLI-Intercept-ECS 13
+VALUE SN1-Admin-Permission CLI-Intercept-FTP-ECS 15
+
+VALUE SN1-Simultaneous-SIP-MIP Disabled 0
+VALUE SN1-Simultaneous-SIP-MIP Enabled 1
+
+VALUE SN1-PPP-Data-Compression-Mode Normal 0
+VALUE SN1-PPP-Data-Compression-Mode Stateless 1
+
+VALUE SN1-Access-link-IP-Frag Normal 0
+VALUE SN1-Access-link-IP-Frag DF-Ignore 1
+VALUE SN1-Access-link-IP-Frag DF-Fragment-ICMP-Notify 2
+
+VALUE SN1-Change-Condition QOSCHANGE 0
+VALUE SN1-Change-Condition TARIFFTIMECHANGE 1
+VALUE SN1-Change-Condition SGSNCHANGE 500
+
+VALUE SN1-Data-Tunnel-Ignore-DF-Bit Disabled 0
+VALUE SN1-Data-Tunnel-Ignore-DF-Bit Enabled 1
+
+VALUE SN1-DHCP-Lease-Expiry-Policy auto-renew 0
+VALUE SN1-DHCP-Lease-Expiry-Policy disconnect 1
+
+VALUE SN1-Direction Any 0
+VALUE SN1-Direction Uplink 1
+VALUE SN1-Direction Downlink 2
+
+VALUE SN1-DNS-Proxy-Use-Subscr-Addr Disable 0
+VALUE SN1-DNS-Proxy-Use-Subscr-Addr Enable 1
+
+VALUE SN1-Enable-QoS-Renegotiation No 0
+VALUE SN1-Enable-QoS-Renegotiation Yes 1
+
+VALUE SN1-Firewall-Enabled False 0
+VALUE SN1-Firewall-Enabled True 1
+
+VALUE SN1-GGSN1-MIP-Required Disabled 0
+VALUE SN1-GGSN1-MIP-Required Enabled 1
+
+VALUE SN1-Gratuitous-ARP-Aggressive Disabled 0
+VALUE SN1-Gratuitous-ARP-Aggressive Enabled 1
+
+VALUE SN1-GTP-Version GTP_VERSION_0 0
+VALUE SN1-GTP-Version GTP_VERSION_1 1
+VALUE SN1-GTP-Version GTP_VERSION_2 2
+
+VALUE SN1-HA-Send-DNS-ADDRESS Disabled 0
+VALUE SN1-HA-Send-DNS-ADDRESS Enabled 1
+
+VALUE SN1-Home-Sub-Use-GGSN Deny 0
+VALUE SN1-Home-Sub-Use-GGSN Accept 1
+
+VALUE SN1-IP-Alloc-Method Alloc_Local_Pool 0
+VALUE SN1-IP-Alloc-Method Alloc_Dhcp_Client 1
+VALUE SN1-IP-Alloc-Method Alloc_Radius 2
+VALUE SN1-IP-Alloc-Method Alloc_No_Alloc 3
+VALUE SN1-IP-Alloc-Method Alloc_Static_Alloc 4
+VALUE SN1-IP-Alloc-Method Alloc_Dhcp_Relay 5
+
+VALUE SN1-IP-Header-Compression None 0
+VALUE SN1-IP-Header-Compression VJ 1
+VALUE SN1-IP-Header-Compression ROHC 2
+VALUE SN1-IP-Header-Compression VJ_ROHC 3
+
+VALUE SN1-IP-Hide-Service-Address Disabled 0
+VALUE SN1-IP-Hide-Service-Address Enabled 1
+
+VALUE SN1-IP-Source-Violate-No-Acct Disabled 0
+VALUE SN1-IP-Source-Violate-No-Acct Enabled 1
+
+VALUE SN1-IPv6-DNS-Proxy Disabled 0
+VALUE SN1-IPv6-DNS-Proxy Enabled 1
+
+VALUE SN1-IPv6-Egress-Filtering Disabled 0
+VALUE SN1-IPv6-Egress-Filtering Enabled 1
+
+VALUE SN1-L3-to-L2-Tun-Addr-Policy no-local-alloc-validate 0
+VALUE SN1-L3-to-L2-Tun-Addr-Policy local-alloc 1
+VALUE SN1-L3-to-L2-Tun-Addr-Policy local-alloc-validate 2
+
+VALUE SN1-Long-Duration-Action Detection 1
+VALUE SN1-Long-Duration-Action Disconnection 2
+VALUE SN1-Long-Duration-Action Dormant-Only-Disconnection 3
+VALUE SN1-Long-Duration-Action Dormant-Only-Detection 4
+
+VALUE SN1-Long-Duration-Notification Suppress 0
+VALUE SN1-Long-Duration-Notification Send 1
+
+VALUE SN1-Mediation-Acct-Rsp-Action None 0
+VALUE SN1-Mediation-Acct-Rsp-Action No_Early_PDUs 1
+VALUE SN1-Mediation-Acct-Rsp-Action Delay_GTP_Response 2
+
+VALUE SN1-Mediation-Enabled Disabled 0
+VALUE SN1-Mediation-Enabled Enabled 1
+
+VALUE SN1-Mediation-No-Interims Disabled 0
+VALUE SN1-Mediation-No-Interims Enabled 1
+
+VALUE SN1-MIP-AAA-Assign-Addr Disabled 0
+VALUE SN1-MIP-AAA-Assign-Addr Enabled 1
+
+VALUE SN1-MIP-Dual-Anchor Disabled 0
+VALUE SN1-MIP-Dual-Anchor Enabled 1
+
+VALUE SN1-MIP-Match-AAA-Assign-Addr Disabled 0
+VALUE SN1-MIP-Match-AAA-Assign-Addr Enabled 1
+
+VALUE SN1-MIP-Send-Ancid Disabled 0
+VALUE SN1-MIP-Send-Ancid Enabled 1
+
+VALUE SN1-MIP-Send-Correlation-Info Disabled 0
+# In StarOS 8.3 and later, supported value 1 is NVSE_Starent, before 8.3 it is Enabled.
+VALUE SN1-MIP-Send-Correlation-Info EnabledOrNVSE_Starent 1
+VALUE SN1-MIP-Send-Correlation-Info NVSE_CUstom1 2
+VALUE SN1-MIP-Send-Correlation-Info NVSE_Custom2 3
+
+VALUE SN1-MIP-Send-Imsi NoneOrDisabled 0
+VALUE SN1-MIP-Send-Imsi Starent_NVSE 1
+VALUE SN1-MIP-Send-Imsi NVSE_Custom1 2
+VALUE SN1-MIP-Send-Imsi NVSE_Custom2 3
+
+VALUE SN1-MIP-Send-Term-Verification Disabled 0
+VALUE SN1-MIP-Send-Term-Verification EnabledOrNVSE_Custom1 1
+VALUE SN1-MIP-Send-Term-Verification NVSE_Custom2 2
+VALUE SN1-MIP-Send-Term-Verification NVSE_Starent 3
+
+VALUE SN1-MN-HA-Hash-Algorithm MD5 1
+VALUE SN1-MN-HA-Hash-Algorithm MD5_RFC2002 2
+VALUE SN1-MN-HA-Hash-Algorithm HMAC_MD5 3
+
+VALUE SN1-Mode Reliable 0
+VALUE SN1-Mode Optimistic 1
+VALUE SN1-Mode Unidirectional 2
+
+VALUE SN1-NPU-Qos-Priority Best_Effort 0
+VALUE SN1-NPU-Qos-Priority Bronze 1
+VALUE SN1-NPU-Qos-Priority Silver 2
+VALUE SN1-NPU-Qos-Priority Gold 3
+VALUE SN1-NPU-Qos-Priority From_DSCP 4
+
+VALUE SN1-Ntk-Session-Disconnect-Flag Session-Disconnect 1
+
+VALUE SN1-PDIF-MIP-Release-TIA No 0
+VALUE SN1-PDIF-MIP-Release-TIA Yes 1
+
+VALUE SN1-PDIF-MIP-Required No 0
+VALUE SN1-PDIF-MIP-Required Yes 1
+
+VALUE SN1-PDIF-MIP-Simple-IP-Fallback No 0
+VALUE SN1-PDIF-MIP-Simple-IP-Fallback Yes 1
+
+VALUE SN1-PDSN1-Handoff-Req-IP-Addr Disabled 0
+VALUE SN1-PDSN1-Handoff-Req-IP-Addr Enabled 1
+
+VALUE SN1-Permit-User-Mcast-PDUs Disabled 0
+VALUE SN1-Permit-User-Mcast-PDUs Enabled 1
+
+VALUE SN1-PPP-Accept-Peer-v6Ifid Disabled 0
+VALUE SN1-PPP-Accept-Peer-v6Ifid Enabled 1
+
+VALUE SN1-PPP-Always-On-Vse Disabled 0
+VALUE SN1-PPP-Always-On-Vse Enabled 1
+
+VALUE SN1-PPP-NW-Layer-IPv4 Disabled 0
+VALUE SN1-PPP-NW-Layer-IPv4 Enabled 1
+VALUE SN1-PPP-NW-Layer-IPv4 Passive 2
+
+VALUE SN1-PPP-NW-Layer-IPv6 Disabled 0
+VALUE SN1-PPP-NW-Layer-IPv6 Enabled 1
+VALUE SN1-PPP-NW-Layer-IPv6 Passive 2
+
+VALUE SN1-PPP-Reneg-Disc Never 0
+VALUE SN1-PPP-Reneg-Disc Always 1
+VALUE SN1-PPP-Reneg-Disc NAI_Prefix_MSID_Mismatch 2
+
+VALUE SN1-Prepaid no_prepaid 0
+VALUE SN1-Prepaid custom_prepaid 1
+VALUE SN1-Prepaid standard_prepaid 2
+VALUE SN1-Prepaid wimax_prepaid 4
+
+VALUE SN1-Prepaid-Compressed-Count Uncompressed 0
+VALUE SN1-Prepaid-Compressed-Count Compressed 1
+
+VALUE SN1-Prepaid-Final-Duration-Alg current_time 0
+VALUE SN1-Prepaid-Final-Duration-Alg last-user-layer3-activity-time 1
+VALUE SN1-Prepaid-Final-Duration-Alg last-airlink-activity-time 2
+VALUE SN1-Prepaid-Final-Duration-Alg last-airlink-activity-time-last-reported 3
+
+VALUE SN1-Prepaid-Preference prepaid_duration 0
+VALUE SN1-Prepaid-Preference prepaid_volume 1
+
+VALUE SN1-Proxy-MIP Disabled 0
+VALUE SN1-Proxy-MIP Enabled 1
+
+VALUE SN1-QoS-Class-Background-PHB Best-Effort 0
+VALUE SN1-QoS-Class-Background-PHB Pass-Through 1
+VALUE SN1-QoS-Class-Background-PHB AF11 10
+VALUE SN1-QoS-Class-Background-PHB AF12 12
+VALUE SN1-QoS-Class-Background-PHB AF13 14
+VALUE SN1-QoS-Class-Background-PHB AF21 18
+VALUE SN1-QoS-Class-Background-PHB AF22 20
+VALUE SN1-QoS-Class-Background-PHB AF23 22
+VALUE SN1-QoS-Class-Background-PHB AF31 26
+VALUE SN1-QoS-Class-Background-PHB AF32 28
+VALUE SN1-QoS-Class-Background-PHB AF33 30
+VALUE SN1-QoS-Class-Background-PHB AF41 34
+VALUE SN1-QoS-Class-Background-PHB AF42 36
+VALUE SN1-QoS-Class-Background-PHB AF43 38
+VALUE SN1-QoS-Class-Background-PHB EF 46
+
+VALUE SN1-QoS-Class-Conversational-PHB Best-Effort 0
+VALUE SN1-QoS-Class-Conversational-PHB Pass-Through 1
+VALUE SN1-QoS-Class-Conversational-PHB AF11 10
+VALUE SN1-QoS-Class-Conversational-PHB AF12 12
+VALUE SN1-QoS-Class-Conversational-PHB AF13 14
+VALUE SN1-QoS-Class-Conversational-PHB AF21 18
+VALUE SN1-QoS-Class-Conversational-PHB AF22 20
+VALUE SN1-QoS-Class-Conversational-PHB AF23 22
+VALUE SN1-QoS-Class-Conversational-PHB AF31 26
+VALUE SN1-QoS-Class-Conversational-PHB AF32 28
+VALUE SN1-QoS-Class-Conversational-PHB AF33 30
+VALUE SN1-QoS-Class-Conversational-PHB AF41 34
+VALUE SN1-QoS-Class-Conversational-PHB AF42 36
+VALUE SN1-QoS-Class-Conversational-PHB AF43 38
+VALUE SN1-QoS-Class-Conversational-PHB EF 46
+
+VALUE SN1-QoS-Class-Interactive-1-PHB Best-Effort 0
+VALUE SN1-QoS-Class-Interactive-1-PHB Pass-Through 1
+VALUE SN1-QoS-Class-Interactive-1-PHB AF11 10
+VALUE SN1-QoS-Class-Interactive-1-PHB AF12 12
+VALUE SN1-QoS-Class-Interactive-1-PHB AF13 14
+VALUE SN1-QoS-Class-Interactive-1-PHB AF21 18
+VALUE SN1-QoS-Class-Interactive-1-PHB AF22 20
+VALUE SN1-QoS-Class-Interactive-1-PHB AF23 22
+VALUE SN1-QoS-Class-Interactive-1-PHB AF31 26
+VALUE SN1-QoS-Class-Interactive-1-PHB AF32 28
+VALUE SN1-QoS-Class-Interactive-1-PHB AF33 30
+VALUE SN1-QoS-Class-Interactive-1-PHB AF41 34
+VALUE SN1-QoS-Class-Interactive-1-PHB AF42 36
+VALUE SN1-QoS-Class-Interactive-1-PHB AF43 38
+VALUE SN1-QoS-Class-Interactive-1-PHB EF 46
+
+VALUE SN1-QoS-Class-Interactive-2-PHB Best-Effort 0
+VALUE SN1-QoS-Class-Interactive-2-PHB Pass-Through 1
+VALUE SN1-QoS-Class-Interactive-2-PHB AF11 10
+VALUE SN1-QoS-Class-Interactive-2-PHB AF12 12
+VALUE SN1-QoS-Class-Interactive-2-PHB AF13 14
+VALUE SN1-QoS-Class-Interactive-2-PHB AF21 18
+VALUE SN1-QoS-Class-Interactive-2-PHB AF22 20
+VALUE SN1-QoS-Class-Interactive-2-PHB AF23 22
+VALUE SN1-QoS-Class-Interactive-2-PHB AF31 26
+VALUE SN1-QoS-Class-Interactive-2-PHB AF32 28
+VALUE SN1-QoS-Class-Interactive-2-PHB AF33 30
+VALUE SN1-QoS-Class-Interactive-2-PHB AF41 34
+VALUE SN1-QoS-Class-Interactive-2-PHB AF42 36
+VALUE SN1-QoS-Class-Interactive-2-PHB AF43 38
+VALUE SN1-QoS-Class-Interactive-2-PHB EF 46
+
+VALUE SN1-QoS-Class-Interactive-3-PHB Best-Effort 0
+VALUE SN1-QoS-Class-Interactive-3-PHB Pass-Through 1
+VALUE SN1-QoS-Class-Interactive-3-PHB AF11 10
+VALUE SN1-QoS-Class-Interactive-3-PHB AF12 12
+VALUE SN1-QoS-Class-Interactive-3-PHB AF13 14
+VALUE SN1-QoS-Class-Interactive-3-PHB AF21 18
+VALUE SN1-QoS-Class-Interactive-3-PHB AF22 20
+VALUE SN1-QoS-Class-Interactive-3-PHB AF23 22
+VALUE SN1-QoS-Class-Interactive-3-PHB AF31 26
+VALUE SN1-QoS-Class-Interactive-3-PHB AF32 28
+VALUE SN1-QoS-Class-Interactive-3-PHB AF33 30
+VALUE SN1-QoS-Class-Interactive-3-PHB AF41 34
+VALUE SN1-QoS-Class-Interactive-3-PHB AF42 36
+VALUE SN1-QoS-Class-Interactive-3-PHB AF43 38
+VALUE SN1-QoS-Class-Interactive-3-PHB EF 46
+
+VALUE SN1-QoS-Class-Streaming-PHB Best-Effort 0
+VALUE SN1-QoS-Class-Streaming-PHB Pass-Through 1
+VALUE SN1-QoS-Class-Streaming-PHB AF11 10
+VALUE SN1-QoS-Class-Streaming-PHB AF12 12
+VALUE SN1-QoS-Class-Streaming-PHB AF13 14
+VALUE SN1-QoS-Class-Streaming-PHB AF21 18
+VALUE SN1-QoS-Class-Streaming-PHB AF22 20
+VALUE SN1-QoS-Class-Streaming-PHB AF23 22
+VALUE SN1-QoS-Class-Streaming-PHB AF31 26
+VALUE SN1-QoS-Class-Streaming-PHB AF32 28
+VALUE SN1-QoS-Class-Streaming-PHB AF33 30
+VALUE SN1-QoS-Class-Streaming-PHB AF41 34
+VALUE SN1-QoS-Class-Streaming-PHB AF42 36
+VALUE SN1-QoS-Class-Streaming-PHB AF43 38
+VALUE SN1-QoS-Class-Streaming-PHB EF 46
+
+VALUE SN1-QoS-Tp-Dnlk Disabled 0
+VALUE SN1-QoS-Tp-Dnlk Policing 1
+VALUE SN1-QoS-Tp-Dnlk Shaping 2
+
+VALUE SN1-QoS-Tp-Uplk Disabled 0
+VALUE SN1-QoS-Tp-Uplk Policing 1
+VALUE SN1-QoS-Tp-Uplk Shaping 2
+
+VALUE SN1-Radius-Returned-Username No 0
+VALUE SN1-Radius-Returned-Username Yes 1
+
+VALUE SN1-Roaming-Sub-Use-GGSN Deny 0
+VALUE SN1-Roaming-Sub-Use-GGSN Accept 1
+
+VALUE SN1-Service-Type None 0
+VALUE SN1-Service-Type PDSN 1
+VALUE SN1-Service-Type Management 2
+VALUE SN1-Service-Type HA 3
+VALUE SN1-Service-Type GGSN 4
+VALUE SN1-Service-Type LNS 5
+VALUE SN1-Service-Type IPSG 6
+VALUE SN1-Service-Type CSCF 7
+VALUE SN1-Service-Type ASNGW 8
+VALUE SN1-Service-Type PDIF 9
+VALUE SN1-Service-Type STANDALONE_FA 10
+VALUE SN1-Service-Type SGSN 11
+VALUE SN1-Service-Type PHSGW 12
+VALUE SN1-Service-Type PDG 13
+VALUE SN1-Service-Type MIPV6HA 14
+VALUE SN1-Service-Type PGW 15
+VALUE SN1-Service-Type SGW 16
+VALUE SN1-Service-Type FNG 17
+VALUE SN1-Service-Type OGW 18
+VALUE SN1-Service-Type HNBGW 19
+VALUE SN1-Service-Type BNG 20
+
+VALUE SN1-Subs-Acc-Flow-Traffic-Valid Disabled 0
+VALUE SN1-Subs-Acc-Flow-Traffic-Valid Enabled 1
+
+VALUE SN1-Subscriber-Accounting None 0
+VALUE SN1-Subscriber-Accounting Radius 1
+VALUE SN1-Subscriber-Accounting GTPP 2
+
+VALUE SN1-Subscriber-Acct-Interim Normal 0
+VALUE SN1-Subscriber-Acct-Interim Suppress 1
+
+VALUE SN1-Subscriber-Acct-Mode flow-based-auxilliary 0
+VALUE SN1-Subscriber-Acct-Mode flow-based-all 1
+VALUE SN1-Subscriber-Acct-Mode flow-based-none 2
+VALUE SN1-Subscriber-Acct-Mode session-based 3
+VALUE SN1-Subscriber-Acct-Mode main-a10-only 4
+
+VALUE SN1-Subscriber-Acct-Rsp-Action None 0
+VALUE SN1-Subscriber-Acct-Rsp-Action No_Early_PDUs 1
+VALUE SN1-Subscriber-Acct-Rsp-Action Delay_GTP_Response 2
+
+VALUE SN1-Subscriber-Acct-Start Normal 0
+VALUE SN1-Subscriber-Acct-Start Suppress 1
+
+VALUE SN1-Subscriber-Acct-Stop Normal 0
+VALUE SN1-Subscriber-Acct-Stop Suppress 1
+
+VALUE SN1-Subscriber-Class Normal_Subscriber 0
+VALUE SN1-Subscriber-Class Ting_100 1
+VALUE SN1-Subscriber-Class Ting_500 2
+VALUE SN1-Subscriber-Class Ting_Buddy 3
+VALUE SN1-Subscriber-Class Ting_Star 4
+VALUE SN1-Subscriber-Class Ting_Nolimit_SMS 5
+VALUE SN1-Subscriber-Class Kids_Locator 6
+VALUE SN1-Subscriber-Class Ting_2000 7
+VALUE SN1-Subscriber-Class Handicapped_Welfare 8
+VALUE SN1-Subscriber-Class Reserved 9
+
+VALUE SN1-Subscriber-IP-Hdr-Neg-Mode Force 0
+VALUE SN1-Subscriber-IP-Hdr-Neg-Mode Detect 1
+
+VALUE SN1-Subscriber-IP-TOS-Copy None 0
+VALUE SN1-Subscriber-IP-TOS-Copy Access-Tunnel 1
+VALUE SN1-Subscriber-IP-TOS-Copy Data-Tunnel 2
+VALUE SN1-Subscriber-IP-TOS-Copy Both 3
+
+VALUE SN1-Subscriber-No-Interims Disabled 0
+VALUE SN1-Subscriber-No-Interims Enabled 1
+
+VALUE SN1-Subs-VJ-Slotid-Cmp-Neg-Mode None 0
+VALUE SN1-Subs-VJ-Slotid-Cmp-Neg-Mode Receive 1
+VALUE SN1-Subs-VJ-Slotid-Cmp-Neg-Mode Transmit 2
+VALUE SN1-Subs-VJ-Slotid-Cmp-Neg-Mode Both 3
+
+VALUE SN1-Tp-Dnlk-Exceed-Action Transmit 0
+VALUE SN1-Tp-Dnlk-Exceed-Action Drop 1
+VALUE SN1-Tp-Dnlk-Exceed-Action Lower-IP-Precedence 2
+VALUE SN1-Tp-Dnlk-Exceed-Action Buffer 3
+VALUE SN1-Tp-Dnlk-Exceed-Action Transmit-On-Buffer-Full 4
+
+VALUE SN1-Tp-Dnlk-Violate-Action Transmit 0
+VALUE SN1-Tp-Dnlk-Violate-Action Drop 1
+VALUE SN1-Tp-Dnlk-Violate-Action Lower-IP-Precedence 2
+VALUE SN1-Tp-Dnlk-Violate-Action Buffer 3
+VALUE SN1-Tp-Dnlk-Violate-Action Transmit-On-Buffer-Full 4
+
+VALUE SN1-Tp-Uplk-Exceed-Action Transmit 0
+VALUE SN1-Tp-Uplk-Exceed-Action Drop 1
+VALUE SN1-Tp-Uplk-Exceed-Action Lower-IP-Precedence 2
+VALUE SN1-Tp-Uplk-Exceed-Action Buffer 3
+VALUE SN1-Tp-Uplk-Exceed-Action Transmit-On-Buffer-Full 4
+
+VALUE SN1-Tp-Uplk-Violate-Action Transmit 0
+VALUE SN1-Tp-Uplk-Violate-Action Drop 1
+VALUE SN1-Tp-Uplk-Violate-Action Lower-IP-Precedence 2
+VALUE SN1-Tp-Uplk-Violate-Action Buffer 3
+VALUE SN1-Tp-Uplk-Violate-Action Transmit-On-Buffer-Full 4
+
+VALUE SN1-Tun-Addr-Policy no-local-alloc-validate 0
+VALUE SN1-Tun-Addr-Policy local-alloc 1
+VALUE SN1-Tun-Addr-Policy local-alloc-validate 2
+
+VALUE SN1-Tunnel-Gn Disabled 0
+VALUE SN1-Tunnel-Gn Enabled 1
+
+VALUE SN1-Tunnel-Load-Balancing random 1
+VALUE SN1-Tunnel-Load-Balancing balanced 2
+VALUE SN1-Tunnel-Load-Balancing prioritized 3
+
+VALUE SN1-Visiting-Sub-Use-GGSN Deny 0
+VALUE SN1-Visiting-Sub-Use-GGSN Accept 1
+
+END-VENDOR Starent
diff --git a/share/dictionary.surfnet b/share/dictionary.surfnet
new file mode 100644
index 0000000..b7ac158
--- /dev/null
+++ b/share/dictionary.surfnet
@@ -0,0 +1,21 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Surfnet
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR Surfnet 1076
+
+BEGIN-VENDOR Surfnet
+
+ATTRIBUTE Surfnet-AVPair 1 string
+ATTRIBUTE Surfnet-Service-Identifier 2 string
+ATTRIBUTE Surfnet-Service-Provider 3 string
+
+END-VENDOR Surfnet
diff --git a/share/dictionary.symbol b/share/dictionary.symbol
new file mode 100644
index 0000000..333dcd8
--- /dev/null
+++ b/share/dictionary.symbol
@@ -0,0 +1,55 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Symbol VSAs
+#
+# Symbol Technologies has been acquired by Motorola in 2007.
+# Some attributes remain in use by products after the acquisition.
+#
+# $Id$
+#
+##############################################################################
+VENDOR Symbol 388
+
+BEGIN-VENDOR Symbol
+
+ATTRIBUTE Symbol-Admin-Role 1 integer
+
+VALUE Symbol-Admin-Role Monitor 1
+VALUE Symbol-Admin-Role Helpdesk 2
+VALUE Symbol-Admin-Role NetworkAdmin 4
+VALUE Symbol-Admin-Role SysAdmin 8
+VALUE Symbol-Admin-Role WebAdmin 16
+VALUE Symbol-Admin-Role Security 32
+VALUE Symbol-Admin-Role SuperUser 32768
+
+ATTRIBUTE Symbol-Current-ESSID 2 string
+ATTRIBUTE Symbol-Allowed-ESSID 3 string
+ATTRIBUTE Symbol-WLAN-Index 4 integer
+ATTRIBUTE Symbol-QoS-Profile 5 integer
+
+VALUE Symbol-QoS-Profile BestEffort 1
+VALUE Symbol-QoS-Profile Background 2
+VALUE Symbol-QoS-Profile Video 3
+VALUE Symbol-QoS-Profile Voice 4
+
+ATTRIBUTE Symbol-Allowed-Radio 6 string
+ATTRIBUTE Symbol-Expiry-Date-Time 7 string # Format: MM/DD/YYYY-HH:MM
+ATTRIBUTE Symbol-Start-Date-Time 8 string # Format: MM/DD/YYYY-HH:MM
+ATTRIBUTE Symbol-Posture-Status 9 string
+ATTRIBUTE Symbol-Downlink-Limit 10 string # Format: 100-10000 (Kbps), 0 = Disabled
+ATTRIBUTE Symbol-Uplink-Limit 11 string # Format: 100-10000 (Kbps), 0 = Disabled
+ATTRIBUTE Symbol-User-Group 12 string
+
+ATTRIBUTE Symbol-Login-Source 100 integer
+
+VALUE Symbol-Login-Source HTTP 16
+VALUE Symbol-Login-Source SSH 32
+VALUE Symbol-Login-Source Telnet 64
+VALUE Symbol-Login-Source Console 128
+VALUE Symbol-Login-Source All 240
+
+END-VENDOR Symbol
diff --git a/share/dictionary.t_systems_nova b/share/dictionary.t_systems_nova
new file mode 100644
index 0000000..009746a
--- /dev/null
+++ b/share/dictionary.t_systems_nova
@@ -0,0 +1,35 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# T-Systems-Nova
+#
+# $Id$
+#
+##############################################################################
+VENDOR T-Systems-Nova 16787
+
+BEGIN-VENDOR T-Systems-Nova
+
+ATTRIBUTE T-Systems-Nova-Location-ID 1 string
+ATTRIBUTE T-Systems-Nova-Location-Name 2 string
+ATTRIBUTE T-Systems-Nova-Logoff-URL 3 string
+ATTRIBUTE T-Systems-Nova-Redirection-URL 4 string
+ATTRIBUTE T-Systems-Nova-Bandwidth-Min-Up 5 integer
+ATTRIBUTE T-Systems-Nova-Bandwidth-Min-Down 6 integer
+ATTRIBUTE T-Systems-Nova-Bandwidth-Max-Up 7 integer
+ATTRIBUTE T-Systems-Nova-Bandwidth-Max-Down 8 integer
+ATTRIBUTE T-Systems-Nova-Session-Terminate-Time 9 integer
+
+#ATTRIBUTE T-Systems-Nova-Session-Terminate-End-Of-Day 10 integer
+ATTRIBUTE T-Systems-Nova-Session-Terminate-EoD 10 integer
+
+ATTRIBUTE T-Systems-Nova-Billing-Class-Of-Service 11 string
+ATTRIBUTE T-Systems-Nova-Service-Name 12 string
+ATTRIBUTE T-Systems-Nova-Price-Of-Service 13 integer
+ATTRIBUTE T-Systems-Nova-Visiting-Provider-Code 14 string
+ATTRIBUTE T-Systems-Nova-UnknownAVP 15 string
+
+END-VENDOR T-Systems-Nova
diff --git a/share/dictionary.telebit b/share/dictionary.telebit
new file mode 100644
index 0000000..fc36c27
--- /dev/null
+++ b/share/dictionary.telebit
@@ -0,0 +1,21 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Telebit dictionary
+#
+# Telebit was acquired by Cisco in 1996.
+#
+# $Id$
+#
+VENDOR Telebit 117
+
+BEGIN-VENDOR Telebit
+
+ATTRIBUTE Telebit-Login-Command 1 string
+ATTRIBUTE Telebit-Port-Name 2 string
+ATTRIBUTE Telebit-Activate-Command 3 string
+ATTRIBUTE Telebit-Accounting-Info 4 string
+ATTRIBUTE Telebit-Login-Option 5 string
+
+END-VENDOR Telebit
diff --git a/share/dictionary.telkom b/share/dictionary.telkom
new file mode 100644
index 0000000..af17e6d
--- /dev/null
+++ b/share/dictionary.telkom
@@ -0,0 +1,31 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors#
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+#############################################################################
+#
+# Telkom SA - RADIUS dictionary
+# Used to convey Telkom Specific Information in proxied requests
+# EDS 20031007 eddie@saix.net
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR Telkom 1431
+
+BEGIN-VENDOR Telkom
+
+# Access-Type is used to describe the Access Medium used eg
+# Dial/ADSL/VSAT etc. Used in both Access-Requests and Accounting
+ATTRIBUTE Telkom-Access-Type 1 string
+
+#
+# Service-Type is used to indicate the Service used main in conjunction
+# with the SSG. Used in both Access-Requests and Accounting
+ATTRIBUTE Telkom-Service-Type 2 string
+
+# YFi Hotspot Manager trick to implement government regulation (South African)
+ATTRIBUTE Telkom-Degrade-Token 200 string
+
+END-VENDOR Telkom
diff --git a/share/dictionary.telrad b/share/dictionary.telrad
new file mode 100644
index 0000000..5056f22
--- /dev/null
+++ b/share/dictionary.telrad
@@ -0,0 +1,23 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# If the WiMAX format isn't crazy enough, why not have other vendors
+# do the same thing?
+#
+VENDOR Telrad 5323 format=1,1,c
+
+BEGIN-VENDOR Telrad
+
+ATTRIBUTE Telrad-TSDF-Table 1 tlv
+ATTRIBUTE Telrad-Item-Identity 1.1 byte
+ATTRIBUTE Telrad-Reference-VPWS-PDN-Name 1.2 octets
+ATTRIBUTE Telrad-TSDF-Parameters 1.3 tlv
+ATTRIBUTE Telrad-C-VLAN-ID 1.3.1 integer
+ATTRIBUTE Telrad-C-VLAN-ID-Retag 1.3.2 integer
+ATTRIBUTE Telrad-S-VLAN-ID 1.3.3 integer
+ATTRIBUTE Telrad-Reference-QOS-Profile-Name 1.3.4 string
+
+END-VENDOR Telrad
diff --git a/share/dictionary.terena b/share/dictionary.terena
new file mode 100644
index 0000000..7b7b857
--- /dev/null
+++ b/share/dictionary.terena
@@ -0,0 +1,19 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors#
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# For TERENA VSA's
+#
+# The reference for these values is:
+# http://www.terena.org/activities/tf-emc2/oid.html
+#
+# $Id$
+#
+VENDOR TERENA 25178
+
+BEGIN-VENDOR TERENA
+
+ATTRIBUTE Eduroam-SP-Country 10 string
+ATTRIBUTE Eduroam-Monitoring-Inflate 11 string
+
+END-VENDOR TERENA
diff --git a/share/dictionary.trapeze b/share/dictionary.trapeze
new file mode 100644
index 0000000..aa99390
--- /dev/null
+++ b/share/dictionary.trapeze
@@ -0,0 +1,40 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# dictionary.trapeze
+#
+# For use with FreeRadius and Trapeze/Juniper MSS software
+# 1.1 or greater.
+#
+# Trapeze Networks has been acquired by Juniper in 2010.
+#
+# $Id$
+#
+#
+VENDOR Trapeze 14525
+
+# Attributes for MSS 1.1 and later
+
+BEGIN-VENDOR Trapeze
+
+ATTRIBUTE Trapeze-VLAN-Name 1 string
+ATTRIBUTE Trapeze-Mobility-Profile 2 string
+ATTRIBUTE Trapeze-Encryption-Type 3 string
+ATTRIBUTE Trapeze-Time-Of-Day 4 string
+
+# New attributes for MSS 3.0 and later
+
+ATTRIBUTE Trapeze-SSID 5 string
+ATTRIBUTE Trapeze-End-Date 6 string
+ATTRIBUTE Trapeze-Start-Date 7 string
+ATTRIBUTE Trapeze-URL 8 string
+
+# Additional attributes, not known when added
+ATTRIBUTE Trapeze-User-Group-Name 9 string
+ATTRIBUTE Trapeze-QoS-Profile 10 string
+ATTRIBUTE Trapeze-Simultaneous-Logins 11 string
+ATTRIBUTE Trapeze-CoA-Username 12 string
+ATTRIBUTE Trapeze-Audit 13 string
+
+END-VENDOR Trapeze
diff --git a/share/dictionary.travelping b/share/dictionary.travelping
new file mode 100644
index 0000000..a42e420
--- /dev/null
+++ b/share/dictionary.travelping
@@ -0,0 +1,76 @@
+#
+# dictionary.travelping
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+
+VENDOR Travelping 18681
+
+BEGIN-VENDOR Travelping
+
+#
+# Standard attribute
+#
+ATTRIBUTE TP-Gateway-Version 1 string
+ATTRIBUTE TP-Firmware-Variant 2 string
+ATTRIBUTE TP-Firmware-Version 3 string
+ATTRIBUTE TP-Gateway-Config 4 string
+ATTRIBUTE TP-ENC-IV 5 string
+ATTRIBUTE TP-Password 6 string
+ATTRIBUTE TP-User-Agent 7 string
+ATTRIBUTE TP-Auth-Reply 8 integer
+ATTRIBUTE TP-Access-Class-Id 9 string
+ATTRIBUTE TP-Host-Name 10 string
+ATTRIBUTE TP-DHCP-Request-Option-List 11 string
+ATTRIBUTE TP-DHCP-Parameter-Request-List 12 string
+ATTRIBUTE TP-DHCP-Vendor-Class-Id 13 string
+ATTRIBUTE TP-DHCP-Client-Id 14 string
+ATTRIBUTE TP-Location-Id 15 string
+ATTRIBUTE TP-NAT-IP-Address 16 ipaddr
+ATTRIBUTE TP-Zone-Id 17 string
+ATTRIBUTE TP-Monitor-Id 18 string
+ATTRIBUTE TP-Related-Session-Id 19 string
+ATTRIBUTE TP-Monitor-Session-Id 20 integer
+ATTRIBUTE TP-Max-Input-Octets 21 integer64
+ATTRIBUTE TP-Max-Output-Octets 22 integer64
+ATTRIBUTE TP-Max-Total-Octets 23 integer64
+ATTRIBUTE TP-Exit-Access-Class-Id 24 string
+ATTRIBUTE TP-Access-Rule 25 string
+ATTRIBUTE TP-Access-Group 26 string
+ATTRIBUTE TP-NAT-Pool-Id 27 string
+ATTRIBUTE TP-NAT-Port-Start 28 integer
+ATTRIBUTE TP-NAT-Port-End 29 integer
+ATTRIBUTE TP-Keep-Alive-Timeout 30 integer
+ATTRIBUTE TP-TLS-Auth-Type 31 integer
+ATTRIBUTE TP-TLS-Pre-Shared-Key 32 string
+ATTRIBUTE TP-CAPWAP-Timestamp 33 integer
+ATTRIBUTE TP-CAPWAP-WTP-Version 34 string
+ATTRIBUTE TP-CAPWAP-Session-Id 35 octets
+ATTRIBUTE TP-CAPWAP-Radio-Id 36 integer
+ATTRIBUTE TP-CAPWAP-WWAN-Id 37 integer
+ATTRIBUTE TP-CAPWAP-WWAN-RAT 38 integer
+ATTRIBUTE TP-CAPWAP-WWAN-RSSi 39 integer
+ATTRIBUTE TP-CAPWAP-WWAN-CREG 40 integer
+ATTRIBUTE TP-CAPWAP-WWAN-LAC 41 integer
+ATTRIBUTE TP-CAPWAP-WWAN-Latency 42 integer
+ATTRIBUTE TP-CAPWAP-WWAN-MCC 43 integer
+ATTRIBUTE TP-CAPWAP-WWAN-MNC 44 integer
+ATTRIBUTE TP-CAPWAP-WWAN-Cell-Id 45 integer
+ATTRIBUTE TP-CAPWAP-POWER-SAVE-IDLE-TIMEOUT 46 integer
+ATTRIBUTE TP-CAPWAP-POWER-SAVE-BUSY-TIMEOUT 47 integer
+ATTRIBUTE TP-CAPWAP-SSID 48 string
+ATTRIBUTE TP-CAPWAP-Max-WIFI-Clients 49 integer
+ATTRIBUTE TP-CAPWAP-Walled-Garden 50 string
+ATTRIBUTE TP-CAPWAP-GPS-Latitude 51 string
+ATTRIBUTE TP-CAPWAP-GPS-Longitude 52 string
+ATTRIBUTE TP-CAPWAP-GPS-Altitude 53 string
+ATTRIBUTE TP-CAPWAP-GPS-Hdop 54 string
+ATTRIBUTE TP-CAPWAP-GPS-Timestamp 55 string
+ATTRIBUTE TP-CAPWAP-Hardware-Version 56 string
+ATTRIBUTE TP-CAPWAP-Software-Version 57 string
+ATTRIBUTE TP-CAPWAP-Boot-Version 58 string
+ATTRIBUTE TP-CAPWAP-Other-Software-Version 59 string
+
+VALUE TP-TLS-Auth-Type Pre-Shared-Key 0
+VALUE TP-TLS-Auth-Type X509-Subject-CommonName 1
+
+END-VENDOR Travelping
diff --git a/share/dictionary.tripplite b/share/dictionary.tripplite
new file mode 100644
index 0000000..00757cd
--- /dev/null
+++ b/share/dictionary.tripplite
@@ -0,0 +1,63 @@
+# -*- text -*-
+# # Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# # This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+# # Version $Id$
+# #
+# # Attributes and values defined in RFC 8045
+# # http://www.ietf.org/rfc/rfc8045.txt
+# #
+##############################################################################
+##
+## TrippLite attributes
+##
+## $Id$
+##
+###############################################################################
+
+VENDOR TrippLite 850
+
+BEGIN-VENDOR TrippLite
+
+#
+## Access is granted to the various facilities within the PowerAlert software
+## by means of the TrippLite-Authorization attribute, which is a comma-delimited
+## string of facility-code to access-level pairs.
+##
+## Facility Codes: default, security, networksettings, systemsettings, systreminfo,
+## logging, devicestatus, devicecontrols, deviceevents,
+## deviceloads, actions, schedules, discovery
+##
+## Access Levels: none (or 0), ro (or 1), rw (or 2)
+##
+## Example: default=rw,security=none,systemsettings=ro
+##
+## - The default access for all non-specified facilitys is read/write
+## - The user has no access to the security facility
+##
+
+ATTRIBUTE TrippLite-Authorization 1 string
+
+#
+## Comma-delimited string of outlet security realms from 1 through 32 to which
+## an otherwise restricted user has read-write access.
+##
+## Example: 1-5,10,15
+##
+## - User has read-write access to realms 1, 2, 3, 4 and 5
+## - User has read-write access to realms 10 and 15
+##
+
+ATTRIBUTE TrippLite-Outlet-Realms 2 string
+
+#
+## Simple message, usually sent as part of accounting
+##
+
+ATTRIBUTE TrippLite-Message 3 string
+
+#
+## PADM20 user role. Role with same name should exists on the device.
+##
+ATTRIBUTE TrippLite-User-Role 4 string
+
+END-VENDOR TrippLite
diff --git a/share/dictionary.tropos b/share/dictionary.tropos
new file mode 100644
index 0000000..bde1b34
--- /dev/null
+++ b/share/dictionary.tropos
@@ -0,0 +1,55 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# See support@tropos.com
+#
+# $Id$
+#
+##############################################################################
+VENDOR Tropos 14529
+
+BEGIN-VENDOR Tropos
+
+ATTRIBUTE Tropos-Unicast-Cipher 1 integer
+ATTRIBUTE Tropos-Layer2-Input-Octets 2 integer
+ATTRIBUTE Tropos-Layer2-Output-Octets 3 integer
+ATTRIBUTE Tropos-Layer2-Input-Frames 4 integer
+ATTRIBUTE Tropos-Layer2-Output-Frames 5 integer
+ATTRIBUTE Tropos-Layer2-Input-Drops 6 integer
+ATTRIBUTE Tropos-Noise-Floor 7 ifid
+ATTRIBUTE Tropos-Noise-Upper-Bound 8 ifid
+ATTRIBUTE Tropos-Release 9 string
+ATTRIBUTE Tropos-Secondary-IP 11 octets
+ATTRIBUTE Tropos-Terminate-Cause 12 integer
+ATTRIBUTE Tropos-Average-RSSI 13 integer
+ATTRIBUTE Tropos-Channel 15 ifid
+ATTRIBUTE Tropos-Retries-Sent 16 integer
+ATTRIBUTE Tropos-Retry-Bits 17 integer
+ATTRIBUTE Tropos-Rates-Sent 18 octets
+ATTRIBUTE Tropos-Rates-Received 19 octets
+ATTRIBUTE Tropos-Routed-Time 21 integer
+ATTRIBUTE Tropos-Routless-Since 22 integer
+ATTRIBUTE Tropos-Capability-Info 23 octets
+ATTRIBUTE Tropos-Input-Cap 24 integer
+ATTRIBUTE Tropos-Output-Cap 25 integer
+ATTRIBUTE Tropos-Class-Mult 26 integer
+ATTRIBUTE Tropos-Cell-Name 27 string
+ATTRIBUTE Tropos-Cell-Location 28 string
+ATTRIBUTE Tropos-Serial-Number 29 string
+ATTRIBUTE Tropos-Latitude 30 string
+ATTRIBUTE Tropos-Longitude 31 string
+
+# These are commented out because FreeRadius does not have a way of
+# putting the numerical value into SQL.
+#
+#VALUE Tropos-Unicast-Cipher Legacy-Open 0
+#VALUE Tropos-Unicast-Cipher Legacy-WEP 1
+#VALUE Tropos-Unicast-Cipher WPA-TKIP 5304834
+#VALUE Tropos-Unicast-Cipher WPA-AES-CCMP 5304836
+#VALUE Tropos-Unicast-Cipher WPA2-TKIP 1027074
+#VALUE Tropos-Unicast-Cipher WPA2-AES-CCMP 1027076
+
+END-VENDOR Tropos
diff --git a/share/dictionary.ukerna b/share/dictionary.ukerna
new file mode 100644
index 0000000..fddb1f4
--- /dev/null
+++ b/share/dictionary.ukerna
@@ -0,0 +1,39 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# GSS-EAP VSAs
+#
+# $Id$
+#
+
+VENDOR UKERNA 25622
+
+BEGIN-VENDOR UKERNA
+
+# Previously-vendor-defined IANA attributes
+ATTRIBUTE UKERNA-GSS-Acceptor-Service-Name 128 string
+ATTRIBUTE UKERNA-GSS-Acceptor-Host-Name 129 string
+ATTRIBUTE UKERNA-GSS-Acceptor-Service-Specific 130 string
+ATTRIBUTE UKERNA-GSS-Acceptor-Realm-Name 131 string
+
+# ABFAB-specific attributes for attributes and unlang recipe items
+ATTRIBUTE SAML-AAA-Assertion 132 string
+ATTRIBUTE EAP-Channel-Binding-Message 135 octets
+ATTRIBUTE Trust-Router-COI 136 string
+ATTRIBUTE Trust-Router-APC 137 string
+
+# ABFAB-specific TargetedIds for the three realms of 'influence'
+ATTRIBUTE Moonshot-Host-TargetedId 138 string
+ATTRIBUTE Moonshot-Realm-TargetedId 139 string
+ATTRIBUTE Moonshot-TR-COI-TargetedId 140 string
+
+# ABFAB-specific attributes for the unlang generation of the above
+ATTRIBUTE Moonshot-MSTID-GSS-Acceptor 141 string
+ATTRIBUTE Moonshot-MSTID-Namespace 142 string
+ATTRIBUTE Moonshot-MSTID-TargetedId 143 string
+
+# ABFAB-specific OTP token value
+ATTRIBUTE Moonshot-OTP-Secret 144 string
+
+END-VENDOR UKERNA
diff --git a/share/dictionary.unix b/share/dictionary.unix
new file mode 100644
index 0000000..fe5b09a
--- /dev/null
+++ b/share/dictionary.unix
@@ -0,0 +1,21 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Allegedly for ProFTPd.
+#
+# $Id$
+#
+
+VENDOR Unix 4
+
+BEGIN-VENDOR Unix
+
+ATTRIBUTE Unix-FTP-UID 10 integer
+ATTRIBUTE Unix-FTP-GID 11 integer
+ATTRIBUTE Unix-FTP-Home 12 string
+ATTRIBUTE Unix-FTP-Shell 13 string
+ATTRIBUTE Unix-FTP-Group-Names 14 string
+ATTRIBUTE Unix-FTP-Group-Ids 15 string
+
+END-VENDOR Unix
diff --git a/share/dictionary.usr b/share/dictionary.usr
new file mode 100644
index 0000000..4847f84
--- /dev/null
+++ b/share/dictionary.usr
@@ -0,0 +1,1618 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# dictionary.usr USR Robotics dictionary.
+#
+# Taken from the dictionary included with the USR RADIUS server,
+# and adjusted a bit.
+#
+# Version: $Id$
+#
+
+#
+# USR Extensions: USR Vendor-Specific stuff.
+#
+# For now in NMC format (whatever that stands for), though the
+# normal vendor-specific format would work just as well.
+#
+#
+VENDOR USR 429 format=4,0
+BEGIN-VENDOR USR
+
+ATTRIBUTE USR-Last-Number-Dialed-Out 0x0066 string
+ATTRIBUTE USR-Last-Number-Dialed-In-DNIS 0x00E8 string
+ATTRIBUTE USR-Last-Callers-Number-ANI 0x00E9 string
+ATTRIBUTE USR-Channel 0xBF38 integer
+ATTRIBUTE USR-Event-Id 0xBFBE integer
+ATTRIBUTE USR-Event-Date-Time 0xBF2F date
+ATTRIBUTE USR-Call-Start-Date-Time 0xBFF7 date
+ATTRIBUTE USR-Call-End-Date-Time 0xBFF6 date
+ATTRIBUTE USR-Default-DTE-Data-Rate 0x005E integer
+ATTRIBUTE USR-Initial-Rx-Link-Data-Rate 0xBF2D integer
+ATTRIBUTE USR-Final-Rx-Link-Data-Rate 0xBF2C integer
+ATTRIBUTE USR-Initial-Tx-Link-Data-Rate 0x006A integer
+ATTRIBUTE USR-Final-Tx-Link-Data-Rate 0x006B integer
+ATTRIBUTE USR-Chassis-Temperature 0xBF31 integer
+ATTRIBUTE USR-Chassis-Temp-Threshold 0xBE84 integer
+ATTRIBUTE USR-Actual-Voltage 0xBF32 integer
+ATTRIBUTE USR-Expected-Voltage 0xBF33 integer
+ATTRIBUTE USR-Power-Supply-Number 0xBF34 integer
+ATTRIBUTE USR-Card-Type 0xBE85 integer
+ATTRIBUTE USR-Chassis-Slot 0xBF39 integer
+ATTRIBUTE USR-Sync-Async-Mode 0x0067 integer
+ATTRIBUTE USR-Originate-Answer-Mode 0x0068 integer
+ATTRIBUTE USR-Modulation-Type 0x006C integer
+ATTRIBUTE USR-Connect-Term-Reason 0x009B integer
+ATTRIBUTE USR-Failure-to-Connect-Reason 0x0069 integer
+ATTRIBUTE USR-Equalization-Type 0x006F integer
+ATTRIBUTE USR-Fallback-Enabled 0x0070 integer
+ATTRIBUTE USR-Connect-Time-Limit 0xBFE7 integer
+ATTRIBUTE USR-Number-of-Rings-Limit 0xBFE6 integer
+ATTRIBUTE USR-DTE-Data-Idle-Timout 0x0048 integer
+ATTRIBUTE USR-Characters-Sent 0x0071 integer
+ATTRIBUTE USR-Characters-Received 0x0072 integer
+ATTRIBUTE USR-Blocks-Sent 0x0075 integer
+ATTRIBUTE USR-Blocks-Received 0x0076 integer
+ATTRIBUTE USR-Blocks-Resent 0x0077 integer
+ATTRIBUTE USR-Retrains-Requested 0x0078 integer
+ATTRIBUTE USR-Retrains-Granted 0x0079 integer
+ATTRIBUTE USR-Line-Reversals 0x007A integer
+ATTRIBUTE USR-Number-Of-Characters-Lost 0x007B integer
+ATTRIBUTE USR-Number-of-Blers 0x007D integer
+ATTRIBUTE USR-Number-of-Link-Timeouts 0x007E integer
+ATTRIBUTE USR-Number-of-Fallbacks 0x007F integer
+ATTRIBUTE USR-Number-of-Upshifts 0x0080 integer
+ATTRIBUTE USR-Number-of-Link-NAKs 0x0081 integer
+ATTRIBUTE USR-DTR-False-Timeout 0x00BE integer
+ATTRIBUTE USR-Fallback-Limit 0x00BF integer
+ATTRIBUTE USR-Block-Error-Count-Limit 0x00C0 integer
+ATTRIBUTE USR-DTR-True-Timeout 0x00DA integer
+ATTRIBUTE USR-Security-Login-Limit 0xBEDE integer
+ATTRIBUTE USR-Security-Resp-Limit 0xBEFA integer
+ATTRIBUTE USR-DTE-Ring-No-Answer-Limit 0xBF17 integer
+ATTRIBUTE USR-Back-Channel-Data-Rate 0x007C integer
+ATTRIBUTE USR-Simplified-MNP-Levels 0x0099 integer
+ATTRIBUTE USR-Simplified-V42bis-Usage 0x00C7 integer
+ATTRIBUTE USR-Mbi_Ct_PRI_Card_Slot 0x0184 integer
+ATTRIBUTE USR-Mbi_Ct_TDM_Time_Slot 0x0185 integer
+ATTRIBUTE USR-Mbi_Ct_PRI_Card_Span_Line 0x0186 integer
+ATTRIBUTE USR-Mbi_Ct_BChannel_Used 0x0187 integer
+ATTRIBUTE USR-Physical-State 0xBE77 integer
+ATTRIBUTE USR-Packet-Bus-Session 0xBF14 integer
+ATTRIBUTE USR-Server-Time 0xF000 date
+
+# 0xBE5D-0xBE63 sent with Event-Id 79
+ATTRIBUTE USR-Channel-Connected-To 0xBE5D integer
+ATTRIBUTE USR-Slot-Connected-To 0xBE5E integer
+ATTRIBUTE USR-Device-Connected-To 0xBE5F integer
+ATTRIBUTE USR-NFAS-ID 0xBE60 integer
+ATTRIBUTE USR-Q931-Call-Reference-Value 0xBE61 integer
+ATTRIBUTE USR-Call-Event-Code 0xBE62 integer
+ATTRIBUTE USR-DS0 0xBE63 integer
+# DS0s sent with Event-Id 77,78
+ATTRIBUTE USR-DS0s 0xBE64 string
+# Gateway-IP-Address sent with Event-Id 71,72
+ATTRIBUTE USR-Gateway-IP-Address 0xBE66 ipaddr
+
+#
+#
+#
+ATTRIBUTE CW-Version-Id 0x8000 integer
+ATTRIBUTE CW-Account-Id 0x8001 string
+ATTRIBUTE CW-Acct-Type 0x8002 integer
+ATTRIBUTE CW-Acct-Identification-Code 0x8003 integer
+ATTRIBUTE CW-Service-Type 0x8004 integer
+ATTRIBUTE CW-Rate-Plan-Id 0x8005 integer
+ATTRIBUTE CW-Source-Identifier 0x8006 integer
+ATTRIBUTE CW-Session-Id 0x8007 string
+ATTRIBUTE CW-Num-Call-Attempt-Session 0x8008 integer
+ATTRIBUTE CW-Session-Sequence-Num 0x8009 integer
+ATTRIBUTE CW-Session-Sequence-End 0x800a integer
+ATTRIBUTE CW-Authentication-Fail-Cnt 0x800b integer
+ATTRIBUTE CW-Clg-Party-E164-Type 0x800c integer
+ATTRIBUTE CW-Clg-Party-E164-Number 0x800d string
+ATTRIBUTE CW-Clg-Party-Trans-Protocol 0x800e integer
+ATTRIBUTE CW-Clg-Party-Trans-Port 0x800f integer
+ATTRIBUTE CW-Clg-Party-Trans-IP 0x8010 ipaddr
+ATTRIBUTE CW-Clg-Party-Trans-DNS 0x8011 string
+ATTRIBUTE CW-Cld-Party-E164-Type 0x8012 integer
+ATTRIBUTE CW-Cld-Party-E164-Number 0x8013 string
+ATTRIBUTE CW-Cld-Party-Trans-Protocol 0x8014 integer
+ATTRIBUTE CW-Cld-Party-Trans-Port 0x8015 integer
+ATTRIBUTE CW-Cld-Party-Trans-IP 0x8016 ipaddr
+ATTRIBUTE CW-Cld-Party-Trans-DNS 0x8017 string
+ATTRIBUTE CW-Orig-Line-Identifier 0x8018 integer
+ATTRIBUTE CW-PSTN-Interface-Number 0x8019 integer
+ATTRIBUTE CW-Ingr-Gway-E164-Type 0x801a integer
+ATTRIBUTE CW-Ingr-Gway-E164-Number 0x801b string
+ATTRIBUTE CW-Ingr-Gway-Trans-Protocol 0x801c integer
+ATTRIBUTE CW-Ingr-Gway-Trans-Port 0x801d integer
+ATTRIBUTE CW-Ingr-Gway-Trans-IP 0x801e ipaddr
+ATTRIBUTE CW-Ingr-Gway-Trans-DNS 0x801f string
+ATTRIBUTE CW-Egr-Gway-Trans-Protocol 0x8020 integer
+ATTRIBUTE CW-Egr-Gway-Trans-Port 0x8021 integer
+ATTRIBUTE CW-Egr-Gway-Trans-IP 0x8022 ipaddr
+ATTRIBUTE CW-Egr-Gway-Trans-DNS 0x8023 string
+ATTRIBUTE CW-Ingr-Gtkpr-Trans-Protocol 0x8024 integer
+ATTRIBUTE CW-Ingr-Gtkpr-Trans-Port 0x8025 integer
+ATTRIBUTE CW-Ingr-Gtkpr-Trans-IP 0x8026 ipaddr
+ATTRIBUTE CW-Ingr-Gtkpr-Trans-DNS 0x8027 string
+ATTRIBUTE CW-Egr-Gtkpr-Trans-Protocol 0x8028 integer
+ATTRIBUTE CW-Egr-Gtkpr-Trans-Port 0x8029 integer
+ATTRIBUTE CW-Egr-Gtkpr-Trans-IP 0x802a ipaddr
+ATTRIBUTE CW-Egr-Gtkpr-Trans-DNS 0x802b string
+ATTRIBUTE CW-Call-Identifier 0x802c string
+ATTRIBUTE CW-Call-Type 0x802d integer
+ATTRIBUTE CW-Call-Start-Ingr-GW-Sec 0x802e string
+ATTRIBUTE CW-Call-Start-Ingr-GW-Msec 0x802f integer
+ATTRIBUTE CW-Call-Start-Time-Ans-Sec 0x8030 string
+ATTRIBUTE CW-Call-Start-Time-Ans-Msec 0x8031 integer
+ATTRIBUTE CW-Call-End-Time-Sec 0x8032 string
+ATTRIBUTE CW-Call-End-Time-Msec 0x8033 integer
+ATTRIBUTE CW-Call-Durn-Connect-Disc 0x8034 integer
+ATTRIBUTE CW-Codec-Type 0x8035 integer
+ATTRIBUTE CW-Call-Termination-Cause 0x8036 integer
+ATTRIBUTE CW-Audio-Packets-Sent 0x8037 integer
+ATTRIBUTE CW-Audio-Packets-Received 0x8038 integer
+ATTRIBUTE CW-Audio-Packets-Lost 0x8039 integer
+ATTRIBUTE CW-Audio-Packets-In-Frame 0x803a integer
+ATTRIBUTE CW-Audio-Bytes-In-Frame 0x803b integer
+ATTRIBUTE CW-Audio-Signal-In-Packet 0x803c integer
+ATTRIBUTE CW-Port-Id-For-Call 0x803d integer
+ATTRIBUTE CW-Slot-Id-For-Call 0x803e integer
+ATTRIBUTE CW-Acct-Balance-Start-Curr 0x803f integer
+ATTRIBUTE CW-Acct-Balance-Start-Amt 0x8040 integer
+ATTRIBUTE CW-Acct-Balance-Start-Dec 0x8041 integer
+ATTRIBUTE CW-Acct-Balance-Decr-Curr 0x8042 integer
+ATTRIBUTE CW-LRQ-Token 0x8043 string
+ATTRIBUTE CW-ARQ-Token 0x8044 string
+ATTRIBUTE CW-Token-Status 0x8045 integer
+ATTRIBUTE CW-SS7-Destn-Ptcode-Type 0x8046 integer
+ATTRIBUTE CW-SS7-Destn-Ptcode-Address 0x8047 integer
+ATTRIBUTE CW-SS7-Orig-Ptcode-Type 0x8048 integer
+ATTRIBUTE CW-SS7-Orig-Ptcode-Address 0x8049 integer
+ATTRIBUTE CW-SS7-CIC 0x804a integer
+ATTRIBUTE CW-MGC-Id 0x804b integer
+ATTRIBUTE CW-MG-Id 0x804c integer
+ATTRIBUTE CW-Signaling-Protocol 0x804d integer
+ATTRIBUTE CW-Protocol-Transport 0x804e integer
+ATTRIBUTE CW-Local-Sig-Trans-Protocol 0x804f integer
+ATTRIBUTE CW-Local-Sig-Trans-Port 0x8050 integer
+ATTRIBUTE CW-Local-Sig-Trans-IP 0x8051 ipaddr
+ATTRIBUTE CW-Local-Sig-Trans-DNS 0x8052 string
+ATTRIBUTE CW-Remote-Sig-Trans-Protocol 0x8053 integer
+ATTRIBUTE CW-Remote-Sig-Trans-Port 0x8054 integer
+ATTRIBUTE CW-Remote-Sig-Trans-IP 0x8055 ipaddr
+ATTRIBUTE CW-Remote-Sig-Trans-DNS 0x8056 string
+ATTRIBUTE CW-Local-MG-RTP-Protocol 0x8057 integer
+ATTRIBUTE CW-Local-MG-RTP-Port 0x8058 integer
+ATTRIBUTE CW-Local-MG-RTP-IP 0x8059 ipaddr
+ATTRIBUTE CW-Local-MG-RTP-DNS 0x805a string
+ATTRIBUTE CW-Remote-MG-RTP-Protocol 0x805b integer
+ATTRIBUTE CW-Remote-MG-RTP-Port 0x805c integer
+ATTRIBUTE CW-Remote-MG-RTP-IP 0x805d ipaddr
+ATTRIBUTE CW-Remote-MG-RTP-DNS 0x805e string
+ATTRIBUTE CW-Call-Model 0x805f integer
+ATTRIBUTE CW-Call-Plan-Id 0x8060 integer
+ATTRIBUTE CW-Trans-Cld-Party-E164-Type 0x8061 integer
+ATTRIBUTE CW-Trans-Cld-Party-E164-Num 0x8062 string
+ATTRIBUTE CW-OSP-Source-Device 0x8063 string
+
+#
+# These are CCA Radius attributes
+#
+ATTRIBUTE USR-PW_USR_IFilter_IP 0x9000 string
+ATTRIBUTE USR-PW_USR_IFilter_IPX 0x9001 string
+ATTRIBUTE USR-PW_USR_OFilter_IP 0x9003 string
+ATTRIBUTE USR-PW_USR_OFilter_IPX 0x9004 string
+ATTRIBUTE USR-PW_USR_OFilter_SAP 0x9005 string
+ATTRIBUTE USR-PW_VPN_ID 0x9006 string
+ATTRIBUTE USR-PW_VPN_Name 0x9007 string
+ATTRIBUTE USR-PW_VPN_Neighbor 0x9008 ipaddr
+ATTRIBUTE USR-PW_Framed_Routing_V2 0x9009 string
+ATTRIBUTE USR-PW_VPN_Gateway 0x900a string
+ATTRIBUTE USR-PW_Tunnel_Authentication 0x900b string
+ATTRIBUTE USR-PW_Index 0x900c string
+ATTRIBUTE USR-PW_Cutoff 0x900d string
+ATTRIBUTE USR-PW_Packet 0x900e string
+ATTRIBUTE USR-Primary_DNS_Server 0x900f ipaddr
+ATTRIBUTE USR-Secondary_DNS_Server 0x9010 ipaddr
+ATTRIBUTE USR-Primary_NBNS_Server 0x9011 ipaddr
+ATTRIBUTE USR-Secondary_NBNS_Server 0x9012 ipaddr
+ATTRIBUTE USR-Syslog-Tap 0x9013 integer
+ATTRIBUTE USR-Chassis-Call-Slot 0x9019 integer
+ATTRIBUTE USR-Chassis-Call-Span 0x901A integer
+ATTRIBUTE USR-Chassis-Call-Channel 0x901B integer
+ATTRIBUTE USR-Keypress-Timeout 0x901C integer
+ATTRIBUTE USR-Unauthenticated-Time 0x901D integer
+ATTRIBUTE USR-Connect-Speed 0x9023 integer
+ATTRIBUTE USR-Framed_IP_Address_Pool_Name 0x9024 string
+ATTRIBUTE USR-MP-EDO 0x9025 string
+
+#
+# Pilgrim attributes
+#
+ATTRIBUTE USR-Bearer-Capabilities 0x9800 integer
+ATTRIBUTE USR-Speed-Of-Connection 0x9801 integer
+ATTRIBUTE USR-Max-Channels 0x9802 integer
+ATTRIBUTE USR-Channel-Expansion 0x9803 integer
+ATTRIBUTE USR-Channel-Decrement 0x9804 integer
+ATTRIBUTE USR-Expansion-Algorithm 0x9805 integer
+ATTRIBUTE USR-Compression-Algorithm 0x9806 integer
+ATTRIBUTE USR-Receive-Acc-Map 0x9807 integer
+ATTRIBUTE USR-Transmit-Acc-Map 0x9808 integer
+ATTRIBUTE USR-Compression-Reset-Mode 0x980a integer
+ATTRIBUTE USR-Min-Compression-Size 0x980b integer
+ATTRIBUTE USR-IP 0x980c integer
+ATTRIBUTE USR-IPX 0x980d integer
+ATTRIBUTE USR-Filter-Zones 0x980e integer
+ATTRIBUTE USR-Appletalk 0x980f integer
+ATTRIBUTE USR-Bridging 0x9810 integer
+ATTRIBUTE USR-Spoofing 0x9811 integer
+ATTRIBUTE USR-Host-Type 0x9812 integer
+ATTRIBUTE USR-Send-Name 0x9813 string
+ATTRIBUTE USR-Send-Password 0x9814 string
+ATTRIBUTE USR-Start-Time 0x9815 integer
+ATTRIBUTE USR-End-Time 0x9816 integer
+ATTRIBUTE USR-Send-Script1 0x9817 string
+ATTRIBUTE USR-Reply-Script1 0x9818 string
+ATTRIBUTE USR-Send-Script2 0x9819 string
+ATTRIBUTE USR-Reply-Script2 0x981a string
+ATTRIBUTE USR-Send-Script3 0x981b string
+ATTRIBUTE USR-Reply-Script3 0x981c string
+ATTRIBUTE USR-Send-Script4 0x981d string
+ATTRIBUTE USR-Reply-Script4 0x981e string
+ATTRIBUTE USR-Send-Script5 0x981f string
+ATTRIBUTE USR-Reply-Script5 0x9820 string
+ATTRIBUTE USR-Send-Script6 0x9821 string
+ATTRIBUTE USR-Reply-Script6 0x9822 string
+ATTRIBUTE USR-Terminal-Type 0x9823 string
+ATTRIBUTE USR-Appletalk-Network-Range 0x9824 integer
+ATTRIBUTE USR-Local-IP-Address 0x9825 string
+ATTRIBUTE USR-Routing-Protocol 0x9826 integer
+ATTRIBUTE USR-Modem-Group 0x9827 integer
+ATTRIBUTE USR-Modem-Training-Time 0x9842 integer
+ATTRIBUTE USR-Interface-Index 0x9843 integer
+ATTRIBUTE USR-MP-MRRU 0x982f integer
+
+ATTRIBUTE USR-SAP-Filter-In 0x9002 string
+ATTRIBUTE USR-MIC 0x9014 string
+ATTRIBUTE USR-Log-Filter-Packets 0x9017 string
+ATTRIBUTE USR-VPN-Encrypter 0x901e integer
+ATTRIBUTE USR-Re-Chap-Timeout 0x9020 integer
+ATTRIBUTE USR-Tunnel-Switch-Endpoint 0x9868 string
+
+ATTRIBUTE USR-IP-SAA-Filter 0x9870 integer
+ATTRIBUTE Initial-Modulation-Type 0x0923 integer
+ATTRIBUTE USR-VTS-Session-Key 0x9856 string
+ATTRIBUTE USR-Orig-NAS-Type 0x9857 string
+ATTRIBUTE USR-Call-Arrival-Time 0x9858 integer
+ATTRIBUTE USR-Call-End-Time 0x9859 integer
+ATTRIBUTE USR-Tunnel-Auth-Hostname 0x986b string
+ATTRIBUTE USR-Acct-Reason-Code 0x986c integer
+ATTRIBUTE USR-Supports-Tags 0x9889 integer
+ATTRIBUTE USR-HARC-Disconnect-Code 0x988b integer
+ATTRIBUTE USR-RMMIE-Status 0x01cd integer
+ATTRIBUTE USR-RMMIE-Last-Update-Event 0x0901 integer
+ATTRIBUTE USR-RMMIE-x2-Status 0x0909 integer
+ATTRIBUTE USR-RMMIE-Planned-Disconnect 0x090a integer
+ATTRIBUTE USR-VPN-GW-Location-Id 0x901f string
+ATTRIBUTE USR-CCP-Algorithm 0x9021 integer
+ATTRIBUTE USR-ACCM-Type 0x9022 integer
+ATTRIBUTE USR-Local-Framed-IP-Addr 0x9026 ipaddr
+ATTRIBUTE USR-IPX-Routing 0x9828 integer
+ATTRIBUTE USR-IPX-WAN 0x9829 integer
+ATTRIBUTE USR-IP-RIP-Policies 0x982a integer
+ATTRIBUTE USR-IP-RIP-Simple-Auth-Password 0x982b string
+ATTRIBUTE USR-IP-RIP-Input-Filter 0x982c string
+ATTRIBUTE USR-IP-Call-Input-Filter 0x982d string
+ATTRIBUTE USR-IPX-RIP-Input-Filter 0x982e string
+ATTRIBUTE USR-IPX-Call-Input-Filter 0x9830 string
+ATTRIBUTE USR-AT-Input-Filter 0x9831 string
+ATTRIBUTE USR-AT-RTMP-Input-Filter 0x9832 string
+ATTRIBUTE USR-AT-Zip-Input-Filter 0x9833 string
+ATTRIBUTE USR-AT-Call-Input-Filter 0x9834 string
+ATTRIBUTE USR-ET-Bridge-Input-Filter 0x9835 string
+ATTRIBUTE USR-IP-RIP-Output-Filter 0x9836 string
+ATTRIBUTE USR-IP-Call-Output-Filter 0x9837 string
+ATTRIBUTE USR-IPX-RIP-Output-Filter 0x9838 string
+ATTRIBUTE USR-IPX-Call-Output-Filter 0x9839 string
+ATTRIBUTE USR-AT-Output-Filter 0x983a string
+ATTRIBUTE USR-AT-RTMP-Output-Filter 0x983b string
+ATTRIBUTE USR-AT-Zip-Output-Filter 0x983c string
+ATTRIBUTE USR-AT-Call-Output-Filter 0x983d string
+ATTRIBUTE USR-ET-Bridge-Output-Filter 0x983e string
+# This item name is too long for the server to parse; had to chop the r off. FIXME?
+ATTRIBUTE USR-ET-Bridge-Call-Output-Filte 0x983f string
+ATTRIBUTE USR-IP-Default-Route-Option 0x9840 integer
+ATTRIBUTE USR-MP-EDO-HIPER 0x9841 string
+ATTRIBUTE USR-Tunnel-Security 0x9844 integer
+ATTRIBUTE USR-Port-Tap 0x9845 integer
+ATTRIBUTE USR-Port-Tap-Format 0x9846 integer
+ATTRIBUTE USR-Port-Tap-Output 0x9847 integer
+ATTRIBUTE USR-Port-Tap-Facility 0x9848 integer
+ATTRIBUTE USR-Port-Tap-Priority 0x9849 integer
+ATTRIBUTE USR-Port-Tap-Address 0x984a ipaddr
+ATTRIBUTE USR-MobileIP-Home-Agent-Address 0x984b ipaddr
+ATTRIBUTE USR-Tunneled-MLPP 0x984c integer
+ATTRIBUTE USR-Multicast-Proxy 0x984d integer
+ATTRIBUTE USR-Multicast-Receive 0x984e integer
+ATTRIBUTE USR-Multicast-Forwarding 0x9850 integer
+ATTRIBUTE USR-IGMP-Query-Interval 0x9851 integer
+ATTRIBUTE USR-IGMP-Maximum-Response-Time 0x9852 integer
+ATTRIBUTE USR-IGMP-Robustness 0x9853 integer
+ATTRIBUTE USR-IGMP-Version 0x9854 integer
+ATTRIBUTE USR-Callback-Type 0x986a integer
+ATTRIBUTE USR-Request-Type 0xf001 integer
+ATTRIBUTE USR-RMMIE-Num-Of-Updates 0x01ce integer
+ATTRIBUTE USR-RMMIE-Manufacturer-ID 0x01df integer
+ATTRIBUTE USR-RMMIE-Product-Code 0x01e0 string
+ATTRIBUTE USR-RMMIE-Serial-Number 0x01e1 string
+ATTRIBUTE USR-RMMIE-Firmware-Version 0x01e2 string
+ATTRIBUTE USR-RMMIE-Firmware-Build-Date 0x01e3 string
+ATTRIBUTE USR-Call-Arrival-in-GMT 0xbe52 date
+ATTRIBUTE USR-Call-Connect-in-GMT 0xbe51 date
+ATTRIBUTE USR-Call-Terminate-in-GMT 0xbe50 date
+ATTRIBUTE USR-IDS0-Call-Type 0xbe4f integer
+ATTRIBUTE USR-Call-Reference-Number 0xbe7d integer
+ATTRIBUTE USR-CDMA-Call-Reference-Number 0x0183 integer
+ATTRIBUTE USR-Mobile-IP-Address 0x088e ipaddr
+ATTRIBUTE USR-QNC1-Service-Destination 0x08f4 ipaddr
+ATTRIBUTE USR-IWF-IP-Address 0x03f4 ipaddr
+ATTRIBUTE USR-Called-Party-Number 0x0890 string
+ATTRIBUTE USR-Calling-Party-Number 0x088f string
+ATTRIBUTE USR-Call-Type 0x0891 integer
+ATTRIBUTE USR-ESN 0x0892 string
+ATTRIBUTE USR-IWF-Call-Identifier 0x0893 integer
+ATTRIBUTE USR-IMSI 0x0894 string
+ATTRIBUTE USR-Service-Option 0x0895 integer
+ATTRIBUTE USR-Disconnect-Cause-Indicator 0x0896 integer
+ATTRIBUTE USR-Mobile-NumBytes-Txed 0x0897 integer
+ATTRIBUTE USR-Mobile-NumBytes-Rxed 0x0898 integer
+ATTRIBUTE USR-Num-Fax-Pages-Processed 0x0899 integer
+ATTRIBUTE USR-Compression-Type 0x089a integer
+ATTRIBUTE USR-Call-Error-Code 0x089b integer
+ATTRIBUTE USR-Modem-Setup-Time 0x089c integer
+ATTRIBUTE USR-Call-Connecting-Time 0x089d integer
+ATTRIBUTE USR-Connect-Time 0x089e integer
+ATTRIBUTE USR-RMMIE-Last-Update-Time 0x0900 integer
+ATTRIBUTE USR-RMMIE-Rcv-Tot-PwrLvl 0x0902 integer
+ATTRIBUTE USR-RMMIE-Rcv-PwrLvl-3300Hz 0x0903 integer
+ATTRIBUTE USR-RMMIE-Rcv-PwrLvl-3750Hz 0x0904 integer
+ATTRIBUTE USR-RMMIE-PwrLvl-NearEcho-Canc 0x0905 integer
+ATTRIBUTE USR-RMMIE-PwrLvl-FarEcho-Canc 0x0906 integer
+ATTRIBUTE USR-RMMIE-PwrLvl-Noise-Lvl 0x0907 integer
+ATTRIBUTE USR-RMMIE-PwrLvl-Xmit-Lvl 0x0908 integer
+ATTRIBUTE USR-Framed-IPX-Route 0x9027 ipaddr
+ATTRIBUTE USR-MPIP-Tunnel-Originator 0x9028 ipaddr
+ATTRIBUTE USR-IGMP-Routing 0x9855 integer
+ATTRIBUTE USR-Rad-Multicast-Routing-Ttl 0x9860 integer
+# again, too long for cistron to parse "rate-limit", "protocol" and "boundary"
+ATTRIBUTE USR-Rad-Multicast-Routing-RtLim 0x9861 integer
+ATTRIBUTE USR-Rad-Multicast-Routing-Proto 0x9862 integer
+ATTRIBUTE USR-Rad-Multicast-Routing-Bound 0x9863 string
+ATTRIBUTE USR-Rad-Dvmrp-Metric 0x9864 integer
+ATTRIBUTE USR-Chat-Script-Name 0x9865 string
+ATTRIBUTE USR-CUSR-hat-Script-Rules 0x9866 string
+ATTRIBUTE USR-Rad-Location-Type 0x9867 integer
+ATTRIBUTE USR-OSPF-Addressless-Index 0x9869 integer
+ATTRIBUTE USR-QoS-Queuing-Mehtod 0x986d integer
+ATTRIBUTE USR-PQ-Default-Priority 0x986e integer
+ATTRIBUTE USR-FQ-Default-Priority 0x9871 integer
+ATTRIBUTE USR-IPP-Enable 0x9872 integer
+ATTRIBUTE USR-Pre-Shared-MN-Key 0x9873 string
+ATTRIBUTE USR-MIP-NAI 0x9874 integer
+ATTRIBUTE USR-DNIS-ReAuthentication 0x9875 integer
+ATTRIBUTE USR-Agent 0x9876 integer
+ATTRIBUTE USR-PQ-Parameters 0x9877 integer
+ATTRIBUTE USR-Dvmrp-Prune-Lifetime 0x9878 integer
+ATTRIBUTE USR-Special-Xon-Xoff-Flow 0x9879 integer
+ATTRIBUTE USR-Dvmrp-Advertised-Metric 0x987a integer
+ATTRIBUTE USR-Dvmrp-Retransmit-Prunes 0x987b integer
+ATTRIBUTE USR-Dvmrp-Non-Pruners 0x987c integer
+ATTRIBUTE USR-Dvmrp-Route-Transit 0x987d integer
+ATTRIBUTE USR-Dvmrp-Input-Filter 0x987e string
+ATTRIBUTE USR-Dvmrp-Output-Filter 0x9880 string
+ATTRIBUTE USR-Policy-Access 0x9881 integer
+ATTRIBUTE USR-Policy-Configuration 0x9882 integer
+ATTRIBUTE USR-Policy-Filename 0x9883 string
+ATTRIBUTE USR-Policy-Type 0x9884 integer
+ATTRIBUTE USR-Mobile-Session-ID 0x9885 integer
+ATTRIBUTE USR-Mobile-Accounting-Type 0x9886 integer
+ATTRIBUTE USR-Mobile-Service-Option 0x9887 integer
+ATTRIBUTE USR-Wallclock-Timestamp 0x9888 integer
+ATTRIBUTE USR-Dvmrp-Initial-Flooding 0x988a integer
+ATTRIBUTE USR-Telnet-Options 0x988c integer
+ATTRIBUTE USR-CDMA-PktData-Network-ID 0x988d integer
+ATTRIBUTE USR-Auth-Next-Server-Address 0x988e ipaddr
+ATTRIBUTE USR-User-PPP-AODI-Type 0x988f integer
+ATTRIBUTE USR-MLPPP-Fragmentation-Threshld 0x9890 integer
+ATTRIBUTE USR-Unnumbered-Local-IP-Address 0x9891 ipaddr
+ATTRIBUTE USR-Traffic-Threshold 0x9892 integer
+ATTRIBUTE USR-Keep-Alive-Interval 0x9893 integer
+ATTRIBUTE USR-Tunnel-Challenge-Outgoing 0x9894 integer
+ATTRIBUTE USR-X25-Trunk-Profile 0x9895 string
+ATTRIBUTE USR-X25-Acct-Input-Segment-Count 0x9896 integer
+ATTRIBUTE USR-X25-Acct-Output-Segment-Coun 0x9897 integer
+ATTRIBUTE USR-X25-Acct-Segment-Size 0x9898 integer
+ATTRIBUTE USR-X25-Acct-Termination-Code 0x9899 integer
+ATTRIBUTE USR-X25-SVC-Logical-Channel-Numb 0x989a integer
+ATTRIBUTE USR-Nailed-B-Channel-Indicator 0x989b integer
+ATTRIBUTE USR-X25-SVC-Call-Attributes 0x989c integer
+ATTRIBUTE USR-Init-Reg-Server-Addr 0x989d ipaddr
+ATTRIBUTE USR-Re-Reg-Server-Addr 0x989e ipaddr
+ATTRIBUTE USR-Bytes-TX-Remain 0x989f integer
+ATTRIBUTE USR-Bytes-RX-Remain 0x98a0 integer
+ATTRIBUTE USR-Session-Time-Remain 0x98a1 integer
+ATTRIBUTE USR-Pre-Paid-Enabled 0x98a2 integer
+ATTRIBUTE USR-Reg-Server-Prov-Timeout 0x98a3 integer
+ATTRIBUTE USR-Redirect 0x98a4 integer
+ATTRIBUTE USR-VLAN-Tag 0x98a5 integer
+ATTRIBUTE USR-Rad-IP-Pool-Definition 0x98a6 string
+ATTRIBUTE USR-Rad-NMC-Call-Progress-Status 0x98a7 integer
+ATTRIBUTE USR-Rad-NMC-Blocks_RX 0x98a8 integer
+
+ATTRIBUTE USR-NAS-Type 0xf002 integer
+ATTRIBUTE USR-Auth-Mode 0xf003 integer
+#
+# Integer Translations
+#
+
+#VALUE USR-Character-Echo Echo-On 0
+#VALUE USR-Character-Echo Echo-Off 1
+
+#VALUE USR-PW_Framed_Routing_V2 Off 0
+#VALUE USR-PW_Framed_Routing_V2 On 1
+
+VALUE USR-Syslog-Tap Off 0
+VALUE USR-Syslog-Tap On-Raw 1
+VALUE USR-Syslog-Tap On-Framed 2
+VALUE USR-Syslog-Tap Unknown 4294967295
+
+# Event Indentifiers
+
+VALUE USR-Event-Id Module-Inserted 6
+VALUE USR-Event-Id Module-Removed 7
+VALUE USR-Event-Id PSU-Voltage-Alarm 8
+VALUE USR-Event-Id PSU-Failed 9
+VALUE USR-Event-Id HUB-Temp-Out-of-Range 10
+VALUE USR-Event-Id Fan-Failed 11
+VALUE USR-Event-Id Watchdog-Timeout 12
+VALUE USR-Event-Id Mgmt-Bus-Failure 13
+VALUE USR-Event-Id In-Connection-Est 14
+VALUE USR-Event-Id Out-Connection-Est 15
+VALUE USR-Event-Id In-Connection-Term 16
+VALUE USR-Event-Id Out-Connection-Term 17
+VALUE USR-Event-Id Connection-Failed 18
+VALUE USR-Event-Id Connection-Timeout 19
+VALUE USR-Event-Id DTE-Transmit-Idle 20
+VALUE USR-Event-Id DTR-True 21
+VALUE USR-Event-Id DTR-False 22
+VALUE USR-Event-Id Block-Error-at-Threshold 23
+VALUE USR-Event-Id Fallbacks-at-Threshold 24
+VALUE USR-Event-Id No-Dial-Tone-Detected 25
+VALUE USR-Event-Id No-Loop-Current-Detected 26
+VALUE USR-Event-Id Yellow-Alarm 27
+VALUE USR-Event-Id Red-Alarm 28
+VALUE USR-Event-Id Loss-Of-Signal 29
+VALUE USR-Event-Id Rcv-Alrm-Ind-Signal 30
+VALUE USR-Event-Id Timing-Source-Switch 31
+VALUE USR-Event-Id Modem-Reset-by-DTE 32
+VALUE USR-Event-Id Modem-Ring-No-Answer 33
+VALUE USR-Event-Id DTE-Ring-No-Answer 34
+VALUE USR-Event-Id Pkt-Bus-Session-Active 35
+VALUE USR-Event-Id Pkt-Bus-Session-Congestion 36
+VALUE USR-Event-Id Pkt-Bus-Session-Lost 37
+VALUE USR-Event-Id Pkt-Bus-Session-Inactive 38
+VALUE USR-Event-Id User-Interface-Reset 39
+VALUE USR-Event-Id Gateway-Port-Out-of-Service 40
+VALUE USR-Event-Id Gateway-Port-Link-Active 41
+VALUE USR-Event-Id Dial-Out-Login-Failure 42
+VALUE USR-Event-Id Dial-In-Login-Failure 43
+VALUE USR-Event-Id Dial-Out-Restricted-Number 44
+VALUE USR-Event-Id Dial-Back-Restricted-Number 45
+VALUE USR-Event-Id User-Blacklisted 46
+VALUE USR-Event-Id Attempted-Login-Blacklisted 47
+VALUE USR-Event-Id Response-Attempt-Limit-Exceeded 48
+VALUE USR-Event-Id Login-Attempt-Limit-Exceeded 49
+VALUE USR-Event-Id Dial-Out-Call-Duration 50
+VALUE USR-Event-Id Dial-In-Call-Duration 51
+VALUE USR-Event-Id Pkt-Bus-Session-Err-Status 52
+VALUE USR-Event-Id NMC-AutoRespnse-Trap 53
+VALUE USR-Event-Id Acct-Server-Contact-Loss 54
+VALUE USR-Event-Id Yellow-Alarm-Clear 55
+VALUE USR-Event-Id Red-Alarm-Clear 56
+VALUE USR-Event-Id Loss-Of-Signal-Clear 57
+VALUE USR-Event-Id Rcv-Alrm-Ind-Signal-Clear 58
+VALUE USR-Event-Id Incoming-Connection-Established 59
+VALUE USR-Event-Id Outgoing-Connection-Established 60
+VALUE USR-Event-Id Incoming-Connection-Terminated 61
+VALUE USR-Event-Id Outgoing-Connection-Terminated 62
+VALUE USR-Event-Id Connection-Attempt-Failure 63
+VALUE USR-Event-Id Continuous-CRC-Alarm 64
+VALUE USR-Event-Id Continuous-CRC-Alarm-Clear 65
+VALUE USR-Event-Id Physical-State-Change 66
+VALUE USR-Event-Id Gateway-Network-Failed 71
+VALUE USR-Event-Id Gateway-Network-Restored 72
+VALUE USR-Event-Id Packet-Bus-Clock-Lost 73
+VALUE USR-Event-Id Packet-Bus-Clock-Restored 74
+VALUE USR-Event-Id D-Channel-In-Service 75
+VALUE USR-Event-Id D-Channel-Out-of-Service 76
+VALUE USR-Event-Id DS0s-In-Service 77
+VALUE USR-Event-Id DS0s-Out-of-Service 78
+VALUE USR-Event-Id T1/T1PRI/E1PRI-Call-Event 79
+VALUE USR-Event-Id Psu-Incompatible 80
+VALUE USR-Event-Id T1,T1-E1/PRI-Call-Arrive-Event 81
+VALUE USR-Event-Id T1,T1-E1/PRI-Call-Connect-Event 82
+VALUE USR-Event-Id T1,T1-E1/PRI-Call-Termina-Event 83
+VALUE USR-Event-Id T1,T1-E1/PRI-Call-Failed-Event 84
+VALUE USR-Event-Id DNS-Contact-Lost 85
+VALUE USR-Event-Id NTP-Contact-Lost 86
+VALUE USR-Event-Id NTP-Contact-Restored 87
+VALUE USR-Event-Id IPGW-Link-Up 88
+VALUE USR-Event-Id IPGW-Link-Down 89
+VALUE USR-Event-Id NTP-Contact-Degraded 90
+VALUE USR-Event-Id In-Connection-Failed 91
+VALUE USR-Event-Id Out-Connection-Failed 92
+VALUE USR-Event-Id Application-ProcessorReset 93
+VALUE USR-Event-Id DSP-Reset 94
+VALUE USR-Event-Id Changed-to-Maint-Srvs-State 95
+VALUE USR-Event-Id Loop-Back-cleared-on-channel 96
+VALUE USR-Event-Id Loop-Back-on-channel 97
+VALUE USR-Event-Id Telco-Abnormal-Response 98
+VALUE USR-Event-Id DNS-Contact-Restored 99
+VALUE USR-Event-Id DNS-Contact-Degraded 100
+VALUE USR-Event-Id RADIUS-Accounting-Restored 101
+VALUE USR-Event-Id RADIUS-Accounting-Group-Restore 102
+VALUE USR-Event-Id RADIUS-Accounting-Group-Degrade 103
+VALUE USR-Event-Id RADIUS-Accounting-Group-NonOper 104
+VALUE USR-Event-Id T1/T1-E1/PRI-InCall-Fail-Event 119
+VALUE USR-Event-Id T1/T1-E1/PRI-OutCall-Fail-Event 120
+VALUE USR-Event-Id RMMIE-Retrain-Event 121
+VALUE USR-Event-Id RMMIE-Speed-Shift-Event 122
+VALUE USR-Event-Id CDMA-Call-Start 191
+VALUE USR-Event-Id CDMA-Call-End 192
+
+VALUE USR-Card-Type SlotEmpty 1
+VALUE USR-Card-Type SlotUnknown 2
+VALUE USR-Card-Type NetwMgtCard 3
+VALUE USR-Card-Type DualT1NAC 4
+VALUE USR-Card-Type DualModemNAC 5
+VALUE USR-Card-Type QuadModemNAC 6
+VALUE USR-Card-Type TrGatewayNAC 7
+VALUE USR-Card-Type X25GatewayNAC 8
+VALUE USR-Card-Type DualV34ModemNAC 9
+VALUE USR-Card-Type QuadV32DigitalModemNAC 10
+VALUE USR-Card-Type QuadV32AnalogModemNAC 11
+VALUE USR-Card-Type QuadV32DigAnlModemNAC 12
+VALUE USR-Card-Type QuadV34DigModemNAC 13
+VALUE USR-Card-Type QuadV34AnlModemNAC 14
+VALUE USR-Card-Type QuadV34DigAnlModemNAC 15
+VALUE USR-Card-Type SingleT1NAC 16
+VALUE USR-Card-Type EthernetGatewayNAC 17
+VALUE USR-Card-Type AccessServer 18
+VALUE USR-Card-Type 486TrGatewayNAC 19
+VALUE USR-Card-Type 486EthernetGatewayNAC 20
+VALUE USR-Card-Type DualRS232NAC 22
+VALUE USR-Card-Type 486X25GatewayNAC 23
+VALUE USR-Card-Type ApplicationServerNAC 25
+VALUE USR-Card-Type ISDNGatewayNAC 26
+VALUE USR-Card-Type ISDNpriT1NAC 27
+VALUE USR-Card-Type ClkedNetMgtCard 28
+VALUE USR-Card-Type ModemPoolManagementNAC 29
+VALUE USR-Card-Type ModemPoolNetserverNAC 30
+VALUE USR-Card-Type ModemPoolV34ModemNAC 31
+VALUE USR-Card-Type ModemPoolISDNNAC 32
+VALUE USR-Card-Type NTServerNAC 33
+VALUE USR-Card-Type QuadV34DigitalG2NAC 34
+VALUE USR-Card-Type QuadV34AnalogG2NAC 35
+VALUE USR-Card-Type QuadV34DigAnlgG2NAC 36
+VALUE USR-Card-Type NETServerFrameRelayNAC 37
+VALUE USR-Card-Type NETServerTokenRingNAC 38
+VALUE USR-Card-Type X2524ChannelNAC 39
+VALUE USR-Card-Type WirelessGatewayNac 42
+
+VALUE USR-Card-Type EnhancedAccessServer 44
+VALUE USR-Card-Type EnhancedISDNGatewayNAC 45
+
+VALUE USR-Card-Type DualT1NIC 1001
+VALUE USR-Card-Type DualAlogMdmNIC 1002
+VALUE USR-Card-Type QuadDgtlMdmNIC 1003
+VALUE USR-Card-Type QuadAlogDgtlMdmNIC 1004
+VALUE USR-Card-Type TokenRingNIC 1005
+VALUE USR-Card-Type SingleT1NIC 1006
+VALUE USR-Card-Type EthernetNIC 1007
+VALUE USR-Card-Type ShortHaulDualT1NIC 1008
+VALUE USR-Card-Type DualAlogMgdIntlMdmNIC 1009
+VALUE USR-Card-Type X25NIC 1010
+VALUE USR-Card-Type QuadAlogNonMgdMdmNIC 1011
+VALUE USR-Card-Type QuadAlogMgdIntlMdmNIC 1012
+VALUE USR-Card-Type QuadAlogNonMgdIntlMdmNIC 1013
+VALUE USR-Card-Type QuadLsdLiMgdMdmNIC 1014
+VALUE USR-Card-Type QuadLsdLiNonMgdMdmNIC 1015
+VALUE USR-Card-Type QuadLsdLiMgdIntlMdmNIC 1016
+VALUE USR-Card-Type QuadLsdLiNonMgdIntlMdmNIC 1017
+VALUE USR-Card-Type HSEthernetWithV35NIC 1018
+VALUE USR-Card-Type HSEthernetWithoutV35NIC 1019
+VALUE USR-Card-Type DualHighSpeedV35NIC 1020
+VALUE USR-Card-Type QuadV35RS232LowSpeedNIC 1021
+VALUE USR-Card-Type DualE1NIC 1022
+VALUE USR-Card-Type ShortHaulDualE1NIC 1023
+VALUE USR-Card-Type BellcoreLongHaulDualT1NIC 1025
+VALUE USR-Card-Type BellcoreShrtHaulDualT1NIC 1026
+VALUE USR-Card-Type SCSIEdgeServerNIC 1027
+
+VALUE USR-Default-DTE-Data-Rate 110-BPS 1
+VALUE USR-Default-DTE-Data-Rate 300-BPS 2
+VALUE USR-Default-DTE-Data-Rate 600-BPS 3
+VALUE USR-Default-DTE-Data-Rate 1200-BPS 4
+VALUE USR-Default-DTE-Data-Rate 2400-BPS 5
+VALUE USR-Default-DTE-Data-Rate 4800-BPS 6
+VALUE USR-Default-DTE-Data-Rate 7200-BPS 7
+VALUE USR-Default-DTE-Data-Rate 9600-BPS 8
+VALUE USR-Default-DTE-Data-Rate 12K-BPS 9
+VALUE USR-Default-DTE-Data-Rate 14.4K-BPS 10
+VALUE USR-Default-DTE-Data-Rate 16.8-BPS 11
+VALUE USR-Default-DTE-Data-Rate 19.2K-BPS 12
+VALUE USR-Default-DTE-Data-Rate 38.4K-BPS 13
+VALUE USR-Default-DTE-Data-Rate 75-BPS 14
+VALUE USR-Default-DTE-Data-Rate 450-BPS 15
+VALUE USR-Default-DTE-Data-Rate UNKNOWN-BPS 16
+VALUE USR-Default-DTE-Data-Rate 57.6K-BPS 17
+VALUE USR-Default-DTE-Data-Rate 21.6K-BPS 18
+VALUE USR-Default-DTE-Data-Rate 24K-BPS 19
+VALUE USR-Default-DTE-Data-Rate 26K-BPS 20
+VALUE USR-Default-DTE-Data-Rate 28K-BPS 21
+VALUE USR-Default-DTE-Data-Rate 115K-BPS 22
+
+VALUE USR-Initial-Rx-Link-Data-Rate 110-BPS 1
+VALUE USR-Initial-Rx-Link-Data-Rate 300-BPS 2
+VALUE USR-Initial-Rx-Link-Data-Rate 600-BPS 3
+VALUE USR-Initial-Rx-Link-Data-Rate 1200-BPS 4
+VALUE USR-Initial-Rx-Link-Data-Rate 2400-BPS 5
+VALUE USR-Initial-Rx-Link-Data-Rate 4800-BPS 6
+VALUE USR-Initial-Rx-Link-Data-Rate 7200-BPS 7
+VALUE USR-Initial-Rx-Link-Data-Rate 9600-BPS 8
+VALUE USR-Initial-Rx-Link-Data-Rate 12000-BPS 9
+VALUE USR-Initial-Rx-Link-Data-Rate 14400-BPS 10
+VALUE USR-Initial-Rx-Link-Data-Rate 16800-BPS 11
+VALUE USR-Initial-Rx-Link-Data-Rate 19200-BPS 12
+VALUE USR-Initial-Rx-Link-Data-Rate 38400-BPS 13
+VALUE USR-Initial-Rx-Link-Data-Rate 75-BPS 14
+VALUE USR-Initial-Rx-Link-Data-Rate 450-BPS 15
+VALUE USR-Initial-Rx-Link-Data-Rate UNKNOWN-BPS 16
+VALUE USR-Initial-Rx-Link-Data-Rate 57600-BPS 17
+VALUE USR-Initial-Rx-Link-Data-Rate 21600-BPS 18
+VALUE USR-Initial-Rx-Link-Data-Rate 24000-BPS 19
+VALUE USR-Initial-Rx-Link-Data-Rate 26400-BPS 20
+VALUE USR-Initial-Rx-Link-Data-Rate 28800-BPS 21
+VALUE USR-Initial-Rx-Link-Data-Rate 115200-BPS 22
+VALUE USR-Initial-Rx-Link-Data-Rate 31200-BPS 23
+VALUE USR-Initial-Rx-Link-Data-Rate 33600-BPS 24
+VALUE USR-Initial-Rx-Link-Data-Rate 25333-BPS 25
+VALUE USR-Initial-Rx-Link-Data-Rate 26666-BPS 26
+VALUE USR-Initial-Rx-Link-Data-Rate 28000-BPS 27
+VALUE USR-Initial-Rx-Link-Data-Rate 29333-BPS 28
+VALUE USR-Initial-Rx-Link-Data-Rate 30666-BPS 29
+VALUE USR-Initial-Rx-Link-Data-Rate 32000-BPS 30
+VALUE USR-Initial-Rx-Link-Data-Rate 33333-BPS 31
+VALUE USR-Initial-Rx-Link-Data-Rate 34666-BPS 32
+VALUE USR-Initial-Rx-Link-Data-Rate 36000-BPS 33
+VALUE USR-Initial-Rx-Link-Data-Rate 37333-BPS 34
+VALUE USR-Initial-Rx-Link-Data-Rate 38666-BPS 35
+VALUE USR-Initial-Rx-Link-Data-Rate 40000-BPS 36
+VALUE USR-Initial-Rx-Link-Data-Rate 41333-BPS 37
+VALUE USR-Initial-Rx-Link-Data-Rate 42666-BPS 38
+VALUE USR-Initial-Rx-Link-Data-Rate 44000-BPS 39
+VALUE USR-Initial-Rx-Link-Data-Rate 45333-BPS 40
+VALUE USR-Initial-Rx-Link-Data-Rate 46666-BPS 41
+VALUE USR-Initial-Rx-Link-Data-Rate 48000-BPS 42
+VALUE USR-Initial-Rx-Link-Data-Rate 49333-BPS 43
+VALUE USR-Initial-Rx-Link-Data-Rate 50666-BPS 44
+VALUE USR-Initial-Rx-Link-Data-Rate 52000-BPS 45
+VALUE USR-Initial-Rx-Link-Data-Rate 53333-BPS 46
+VALUE USR-Initial-Rx-Link-Data-Rate 54666-BPS 47
+VALUE USR-Initial-Rx-Link-Data-Rate 56000-BPS 48
+VALUE USR-Initial-Rx-Link-Data-Rate 57333-BPS 49
+VALUE USR-Initial-Rx-Link-Data-Rate 58666-BPS 50
+VALUE USR-Initial-Rx-Link-Data-Rate 60000-BPS 51
+VALUE USR-Initial-Rx-Link-Data-Rate 61333-BPS 52
+VALUE USR-Initial-Rx-Link-Data-Rate 62666-BPS 53
+VALUE USR-Initial-Rx-Link-Data-Rate 64000-BPS 54
+
+VALUE USR-Final-Rx-Link-Data-Rate 110-BPS 1
+VALUE USR-Final-Rx-Link-Data-Rate 300-BPS 2
+VALUE USR-Final-Rx-Link-Data-Rate 600-BPS 3
+VALUE USR-Final-Rx-Link-Data-Rate 1200-BPS 4
+VALUE USR-Final-Rx-Link-Data-Rate 2400-BPS 5
+VALUE USR-Final-Rx-Link-Data-Rate 4800-BPS 6
+VALUE USR-Final-Rx-Link-Data-Rate 7200-BPS 7
+VALUE USR-Final-Rx-Link-Data-Rate 9600-BPS 8
+VALUE USR-Final-Rx-Link-Data-Rate 12000-BPS 9
+VALUE USR-Final-Rx-Link-Data-Rate 14400-BPS 10
+VALUE USR-Final-Rx-Link-Data-Rate 16800-BPS 11
+VALUE USR-Final-Rx-Link-Data-Rate 19200-BPS 12
+VALUE USR-Final-Rx-Link-Data-Rate 38400-BPS 13
+VALUE USR-Final-Rx-Link-Data-Rate 75-BPS 14
+VALUE USR-Final-Rx-Link-Data-Rate 450-BPS 15
+VALUE USR-Final-Rx-Link-Data-Rate UNKNOWN-BPS 16
+VALUE USR-Final-Rx-Link-Data-Rate 57600-BPS 17
+VALUE USR-Final-Rx-Link-Data-Rate 21600-BPS 18
+VALUE USR-Final-Rx-Link-Data-Rate 24000-BPS 19
+VALUE USR-Final-Rx-Link-Data-Rate 26400-BPS 20
+VALUE USR-Final-Rx-Link-Data-Rate 28800-BPS 21
+VALUE USR-Final-Rx-Link-Data-Rate 115200-BPS 22
+VALUE USR-Final-Rx-Link-Data-Rate 31200-BPS 23
+VALUE USR-Final-Rx-Link-Data-Rate 33600-BPS 24
+VALUE USR-Final-Rx-Link-Data-Rate 25333-BPS 25
+VALUE USR-Final-Rx-Link-Data-Rate 26666-BPS 26
+VALUE USR-Final-Rx-Link-Data-Rate 28000-BPS 27
+VALUE USR-Final-Rx-Link-Data-Rate 29333-BPS 28
+VALUE USR-Final-Rx-Link-Data-Rate 30666-BPS 29
+VALUE USR-Final-Rx-Link-Data-Rate 32000-BPS 30
+VALUE USR-Final-Rx-Link-Data-Rate 33333-BPS 31
+VALUE USR-Final-Rx-Link-Data-Rate 34666-BPS 32
+VALUE USR-Final-Rx-Link-Data-Rate 36000-BPS 33
+VALUE USR-Final-Rx-Link-Data-Rate 37333-BPS 34
+VALUE USR-Final-Rx-Link-Data-Rate 38666-BPS 35
+VALUE USR-Final-Rx-Link-Data-Rate 40000-BPS 36
+VALUE USR-Final-Rx-Link-Data-Rate 41333-BPS 37
+VALUE USR-Final-Rx-Link-Data-Rate 42666-BPS 38
+VALUE USR-Final-Rx-Link-Data-Rate 44000-BPS 39
+VALUE USR-Final-Rx-Link-Data-Rate 45333-BPS 40
+VALUE USR-Final-Rx-Link-Data-Rate 46666-BPS 41
+VALUE USR-Final-Rx-Link-Data-Rate 48000-BPS 42
+VALUE USR-Final-Rx-Link-Data-Rate 49333-BPS 43
+VALUE USR-Final-Rx-Link-Data-Rate 50666-BPS 44
+VALUE USR-Final-Rx-Link-Data-Rate 52000-BPS 45
+VALUE USR-Final-Rx-Link-Data-Rate 53333-BPS 46
+VALUE USR-Final-Rx-Link-Data-Rate 54666-BPS 47
+VALUE USR-Final-Rx-Link-Data-Rate 56000-BPS 48
+VALUE USR-Final-Rx-Link-Data-Rate 57333-BPS 49
+VALUE USR-Final-Rx-Link-Data-Rate 58666-BPS 50
+VALUE USR-Final-Rx-Link-Data-Rate 60000-BPS 51
+VALUE USR-Final-Rx-Link-Data-Rate 61333-BPS 52
+VALUE USR-Final-Rx-Link-Data-Rate 62666-BPS 53
+VALUE USR-Final-Rx-Link-Data-Rate 64000-BPS 54
+
+VALUE USR-Initial-Tx-Link-Data-Rate 110-BPS 1
+VALUE USR-Initial-Tx-Link-Data-Rate 300-BPS 2
+VALUE USR-Initial-Tx-Link-Data-Rate 600-BPS 3
+VALUE USR-Initial-Tx-Link-Data-Rate 1200-BPS 4
+VALUE USR-Initial-Tx-Link-Data-Rate 2400-BPS 5
+VALUE USR-Initial-Tx-Link-Data-Rate 4800-BPS 6
+VALUE USR-Initial-Tx-Link-Data-Rate 7200-BPS 7
+VALUE USR-Initial-Tx-Link-Data-Rate 9600-BPS 8
+VALUE USR-Initial-Tx-Link-Data-Rate 12000-BPS 9
+VALUE USR-Initial-Tx-Link-Data-Rate 14400-BPS 10
+VALUE USR-Initial-Tx-Link-Data-Rate 16800-BPS 11
+VALUE USR-Initial-Tx-Link-Data-Rate 19200-BPS 12
+VALUE USR-Initial-Tx-Link-Data-Rate 38400-BPS 13
+VALUE USR-Initial-Tx-Link-Data-Rate 75-BPS 14
+VALUE USR-Initial-Tx-Link-Data-Rate 450-BPS 15
+VALUE USR-Initial-Tx-Link-Data-Rate UNKNOWN-BPS 16
+VALUE USR-Initial-Tx-Link-Data-Rate 57600-BPS 17
+VALUE USR-Initial-Tx-Link-Data-Rate 21600-BPS 18
+VALUE USR-Initial-Tx-Link-Data-Rate 24000-BPS 19
+VALUE USR-Initial-Tx-Link-Data-Rate 26400-BPS 20
+VALUE USR-Initial-Tx-Link-Data-Rate 28800-BPS 21
+VALUE USR-Initial-Tx-Link-Data-Rate 115200-BPS 22
+VALUE USR-Initial-Tx-Link-Data-Rate 31200-BPS 23
+VALUE USR-Initial-Tx-Link-Data-Rate 33600-BPS 24
+VALUE USR-Initial-Tx-Link-Data-Rate 25333-BPS 25
+VALUE USR-Initial-Tx-Link-Data-Rate 26666-BPS 26
+VALUE USR-Initial-Tx-Link-Data-Rate 28000-BPS 27
+VALUE USR-Initial-Tx-Link-Data-Rate 29333-BPS 28
+VALUE USR-Initial-Tx-Link-Data-Rate 30666-BPS 29
+VALUE USR-Initial-Tx-Link-Data-Rate 32000-BPS 30
+VALUE USR-Initial-Tx-Link-Data-Rate 33333-BPS 31
+VALUE USR-Initial-Tx-Link-Data-Rate 34666-BPS 32
+VALUE USR-Initial-Tx-Link-Data-Rate 36000-BPS 33
+VALUE USR-Initial-Tx-Link-Data-Rate 37333-BPS 34
+VALUE USR-Initial-Tx-Link-Data-Rate 38666-BPS 35
+VALUE USR-Initial-Tx-Link-Data-Rate 40000-BPS 36
+VALUE USR-Initial-Tx-Link-Data-Rate 41333-BPS 37
+VALUE USR-Initial-Tx-Link-Data-Rate 42666-BPS 38
+VALUE USR-Initial-Tx-Link-Data-Rate 44000-BPS 39
+VALUE USR-Initial-Tx-Link-Data-Rate 45333-BPS 40
+VALUE USR-Initial-Tx-Link-Data-Rate 46666-BPS 41
+VALUE USR-Initial-Tx-Link-Data-Rate 48000-BPS 42
+VALUE USR-Initial-Tx-Link-Data-Rate 49333-BPS 43
+VALUE USR-Initial-Tx-Link-Data-Rate 50666-BPS 44
+VALUE USR-Initial-Tx-Link-Data-Rate 52000-BPS 45
+VALUE USR-Initial-Tx-Link-Data-Rate 53333-BPS 46
+VALUE USR-Initial-Tx-Link-Data-Rate 54666-BPS 47
+VALUE USR-Initial-Tx-Link-Data-Rate 56000-BPS 48
+VALUE USR-Initial-Tx-Link-Data-Rate 57333-BPS 49
+VALUE USR-Initial-Tx-Link-Data-Rate 58666-BPS 50
+VALUE USR-Initial-Tx-Link-Data-Rate 60000-BPS 51
+VALUE USR-Initial-Tx-Link-Data-Rate 61333-BPS 52
+VALUE USR-Initial-Tx-Link-Data-Rate 62666-BPS 53
+VALUE USR-Initial-Tx-Link-Data-Rate 64000-BPS 54
+
+VALUE USR-Final-Tx-Link-Data-Rate 110-BPS 1
+VALUE USR-Final-Tx-Link-Data-Rate 300-BPS 2
+VALUE USR-Final-Tx-Link-Data-Rate 600-BPS 3
+VALUE USR-Final-Tx-Link-Data-Rate 1200-BPS 4
+VALUE USR-Final-Tx-Link-Data-Rate 2400-BPS 5
+VALUE USR-Final-Tx-Link-Data-Rate 4800-BPS 6
+VALUE USR-Final-Tx-Link-Data-Rate 7200-BPS 7
+VALUE USR-Final-Tx-Link-Data-Rate 9600-BPS 8
+VALUE USR-Final-Tx-Link-Data-Rate 12000-BPS 9
+VALUE USR-Final-Tx-Link-Data-Rate 14400-BPS 10
+VALUE USR-Final-Tx-Link-Data-Rate 16800-BPS 11
+VALUE USR-Final-Tx-Link-Data-Rate 19200-BPS 12
+VALUE USR-Final-Tx-Link-Data-Rate 38400-BPS 13
+VALUE USR-Final-Tx-Link-Data-Rate 75-BPS 14
+VALUE USR-Final-Tx-Link-Data-Rate 450-BPS 15
+VALUE USR-Final-Tx-Link-Data-Rate UNKNOWN-BPS 16
+VALUE USR-Final-Tx-Link-Data-Rate 57600-BPS 17
+VALUE USR-Final-Tx-Link-Data-Rate 21600-BPS 18
+VALUE USR-Final-Tx-Link-Data-Rate 24000-BPS 19
+VALUE USR-Final-Tx-Link-Data-Rate 26400-BPS 20
+VALUE USR-Final-Tx-Link-Data-Rate 28800-BPS 21
+VALUE USR-Final-Tx-Link-Data-Rate 115200-BPS 22
+VALUE USR-Final-Tx-Link-Data-Rate 31200-BPS 23
+VALUE USR-Final-Tx-Link-Data-Rate 33600-BPS 24
+VALUE USR-Final-Tx-Link-Data-Rate 25333-BPS 25
+VALUE USR-Final-Tx-Link-Data-Rate 26666-BPS 26
+VALUE USR-Final-Tx-Link-Data-Rate 28000-BPS 27
+VALUE USR-Final-Tx-Link-Data-Rate 29333-BPS 28
+VALUE USR-Final-Tx-Link-Data-Rate 30666-BPS 29
+VALUE USR-Final-Tx-Link-Data-Rate 32000-BPS 30
+VALUE USR-Final-Tx-Link-Data-Rate 33333-BPS 31
+VALUE USR-Final-Tx-Link-Data-Rate 34666-BPS 32
+VALUE USR-Final-Tx-Link-Data-Rate 36000-BPS 33
+VALUE USR-Final-Tx-Link-Data-Rate 37333-BPS 34
+VALUE USR-Final-Tx-Link-Data-Rate 38666-BPS 35
+VALUE USR-Final-Tx-Link-Data-Rate 40000-BPS 36
+VALUE USR-Final-Tx-Link-Data-Rate 41333-BPS 37
+VALUE USR-Final-Tx-Link-Data-Rate 42666-BPS 38
+VALUE USR-Final-Tx-Link-Data-Rate 44000-BPS 39
+VALUE USR-Final-Tx-Link-Data-Rate 45333-BPS 40
+VALUE USR-Final-Tx-Link-Data-Rate 46666-BPS 41
+VALUE USR-Final-Tx-Link-Data-Rate 48000-BPS 42
+VALUE USR-Final-Tx-Link-Data-Rate 49333-BPS 43
+VALUE USR-Final-Tx-Link-Data-Rate 50666-BPS 44
+VALUE USR-Final-Tx-Link-Data-Rate 52000-BPS 45
+VALUE USR-Final-Tx-Link-Data-Rate 53333-BPS 46
+VALUE USR-Final-Tx-Link-Data-Rate 54666-BPS 47
+VALUE USR-Final-Tx-Link-Data-Rate 56000-BPS 48
+VALUE USR-Final-Tx-Link-Data-Rate 57333-BPS 49
+VALUE USR-Final-Tx-Link-Data-Rate 58666-BPS 50
+VALUE USR-Final-Tx-Link-Data-Rate 60000-BPS 51
+VALUE USR-Final-Tx-Link-Data-Rate 61333-BPS 52
+VALUE USR-Final-Tx-Link-Data-Rate 62666-BPS 53
+VALUE USR-Final-Tx-Link-Data-Rate 64000-BPS 54
+
+VALUE USR-Connect-Speed NONE 1
+VALUE USR-Connect-Speed 300-BPS 2
+VALUE USR-Connect-Speed 1200-BPS 3
+VALUE USR-Connect-Speed 2400-BPS 4
+VALUE USR-Connect-Speed 4800-BPS 5
+VALUE USR-Connect-Speed 7200-BPS 6
+VALUE USR-Connect-Speed 9600-BPS 7
+VALUE USR-Connect-Speed 12000-BPS 8
+VALUE USR-Connect-Speed 14400-BPS 9
+VALUE USR-Connect-Speed 16800-BPS 10
+VALUE USR-Connect-Speed 19200-BPS 11
+VALUE USR-Connect-Speed 21600-BPS 12
+VALUE USR-Connect-Speed 28800-BPS 13
+VALUE USR-Connect-Speed 38400-BPS 14
+VALUE USR-Connect-Speed 57600-BPS 15
+VALUE USR-Connect-Speed 115200-BPS 16
+VALUE USR-Connect-Speed 288000-BPS 17
+VALUE USR-Connect-Speed 75-1200-BPS 18
+VALUE USR-Connect-Speed 1200-75-BPS 19
+VALUE USR-Connect-Speed 24000-BPS 20
+VALUE USR-Connect-Speed 26400-BPS 21
+VALUE USR-Connect-Speed 31200-BPS 22
+VALUE USR-Connect-Speed 33600-BPS 23
+VALUE USR-Connect-Speed 33333-BPS 24
+VALUE USR-Connect-Speed 37333-BPS 25
+VALUE USR-Connect-Speed 41333-BPS 26
+VALUE USR-Connect-Speed 42666-BPS 27
+VALUE USR-Connect-Speed 44000-BPS 28
+VALUE USR-Connect-Speed 45333-BPS 29
+VALUE USR-Connect-Speed 46666-BPS 30
+VALUE USR-Connect-Speed 48000-BPS 31
+VALUE USR-Connect-Speed 49333-BPS 32
+VALUE USR-Connect-Speed 50666-BPS 33
+VALUE USR-Connect-Speed 52000-BPS 34
+VALUE USR-Connect-Speed 53333-BPS 35
+VALUE USR-Connect-Speed 54666-BPS 36
+VALUE USR-Connect-Speed 56000-BPS 37
+VALUE USR-Connect-Speed 57333-BPS 38
+VALUE USR-Connect-Speed 64000-BPS 39
+VALUE USR-Connect-Speed 25333-BPS 40
+VALUE USR-Connect-Speed 26666-BPS 41
+VALUE USR-Connect-Speed 28000-BPS 42
+VALUE USR-Connect-Speed 29333-BPS 43
+VALUE USR-Connect-Speed 30666-BPS 44
+VALUE USR-Connect-Speed 32000-BPS 45
+VALUE USR-Connect-Speed 34666-BPS 46
+VALUE USR-Connect-Speed 36000-BPS 47
+VALUE USR-Connect-Speed 38666-BPS 48
+VALUE USR-Connect-Speed 40000-BPS 49
+VALUE USR-Connect-Speed 58666-BPS 50
+VALUE USR-Connect-Speed 60000-BPS 51
+VALUE USR-Connect-Speed 61333-BPS 52
+VALUE USR-Connect-Speed 62666-BPS 53
+
+VALUE USR-Sync-Async-Mode Asynchronous 1
+VALUE USR-Sync-Async-Mode Synchronous 2
+
+VALUE USR-Originate-Answer-Mode Originate_in_Originate_Mode 1
+VALUE USR-Originate-Answer-Mode Originate_in_Answer_Mode 2
+VALUE USR-Originate-Answer-Mode Answer_in_Originate_Mode 3
+VALUE USR-Originate-Answer-Mode Answer_in_Answer_Mode 4
+
+VALUE USR-Modulation-Type usRoboticsHST 1
+VALUE USR-Modulation-Type ccittV32 2
+VALUE USR-Modulation-Type ccittV22bis 3
+VALUE USR-Modulation-Type bell103 4
+VALUE USR-Modulation-Type ccittV21 5
+VALUE USR-Modulation-Type bell212 6
+VALUE USR-Modulation-Type ccittV32bis 7
+VALUE USR-Modulation-Type ccittV23 8
+VALUE USR-Modulation-Type negotiationFailed 9
+VALUE USR-Modulation-Type bell208b 10
+VALUE USR-Modulation-Type v21FaxClass1 11
+VALUE USR-Modulation-Type v27FaxClass1 12
+VALUE USR-Modulation-Type v29FaxClass1 13
+VALUE USR-Modulation-Type v17FaxClass1 14
+VALUE USR-Modulation-Type v21FaxClass2 15
+VALUE USR-Modulation-Type v27FaxClass2 16
+VALUE USR-Modulation-Type v29FaxClass2 17
+VALUE USR-Modulation-Type v17FaxClass2 18
+VALUE USR-Modulation-Type v32Terbo 19
+VALUE USR-Modulation-Type v34 20
+VALUE USR-Modulation-Type vFC 21
+VALUE USR-Modulation-Type v34plus 22
+VALUE USR-Modulation-Type x2 23
+VALUE USR-Modulation-Type v110 24
+VALUE USR-Modulation-Type v120 25
+VALUE USR-Modulation-Type x75 26
+VALUE USR-Modulation-Type asyncSyncPPP 27
+VALUE USR-Modulation-Type clearChannel 28
+VALUE USR-Modulation-Type x2client 29
+VALUE USR-Modulation-Type x2symmetric 30
+VALUE USR-Modulation-Type piafs 31
+VALUE USR-Modulation-Type x2version2 32
+VALUE USR-Modulation-Type v90Analog 33
+VALUE USR-Modulation-Type v90Digital 34
+VALUE USR-Modulation-Type v90AllDigital 35
+
+VALUE Initial-Modulation-Type usRoboticsHST 1
+VALUE Initial-Modulation-Type ccittV32 2
+VALUE Initial-Modulation-Type ccittV22bis 3
+VALUE Initial-Modulation-Type bell103 4
+VALUE Initial-Modulation-Type ccittV21 5
+VALUE Initial-Modulation-Type bell212 6
+VALUE Initial-Modulation-Type ccittV32bis 7
+VALUE Initial-Modulation-Type ccittV23 8
+VALUE Initial-Modulation-Type negotiationFailed 9
+VALUE Initial-Modulation-Type bell208b 10
+VALUE Initial-Modulation-Type v21FaxClass1 11
+VALUE Initial-Modulation-Type v27FaxClass1 12
+VALUE Initial-Modulation-Type v29FaxClass1 13
+VALUE Initial-Modulation-Type v17FaxClass1 14
+VALUE Initial-Modulation-Type v21FaxClass2 15
+VALUE Initial-Modulation-Type v27FaxClass2 16
+VALUE Initial-Modulation-Type v29FaxClass2 17
+VALUE Initial-Modulation-Type v17FaxClass2 18
+VALUE Initial-Modulation-Type v32Terbo 19
+VALUE Initial-Modulation-Type v34 20
+VALUE Initial-Modulation-Type vFC 21
+VALUE Initial-Modulation-Type v34plus 22
+VALUE Initial-Modulation-Type x2 23
+VALUE Initial-Modulation-Type v110 24
+VALUE Initial-Modulation-Type v120 25
+VALUE Initial-Modulation-Type x75 26
+VALUE Initial-Modulation-Type asyncSyncPPP 27
+VALUE Initial-Modulation-Type clearChannel 28
+VALUE Initial-Modulation-Type x2client 29
+VALUE Initial-Modulation-Type x2symmetric 30
+VALUE Initial-Modulation-Type piafs 31
+VALUE Initial-Modulation-Type x2version2 32
+VALUE Initial-Modulation-Type v90Analogue 33
+VALUE Initial-Modulation-Type v90Digital 34
+VALUE Initial-Modulation-Type v90AllDigital 35
+
+VALUE USR-Connect-Term-Reason dtrDrop 1
+VALUE USR-Connect-Term-Reason escapeSequence 2
+VALUE USR-Connect-Term-Reason athCommand 3
+VALUE USR-Connect-Term-Reason carrierLoss 4
+VALUE USR-Connect-Term-Reason inactivityTimout 5
+VALUE USR-Connect-Term-Reason mnpIncompatible 6
+VALUE USR-Connect-Term-Reason undefined 7
+VALUE USR-Connect-Term-Reason remotePassword 8
+VALUE USR-Connect-Term-Reason linkPassword 9
+VALUE USR-Connect-Term-Reason retransmitLimit 10
+VALUE USR-Connect-Term-Reason linkDisconnectMsgReceived 11
+VALUE USR-Connect-Term-Reason noLoopCurrent 12
+VALUE USR-Connect-Term-Reason invalidSpeed 13
+VALUE USR-Connect-Term-Reason unableToRetrain 14
+VALUE USR-Connect-Term-Reason managementCommand 15
+VALUE USR-Connect-Term-Reason noDialTone 16
+VALUE USR-Connect-Term-Reason keyAbort 17
+VALUE USR-Connect-Term-Reason lineBusy 18
+VALUE USR-Connect-Term-Reason noAnswer 19
+VALUE USR-Connect-Term-Reason voice 20
+VALUE USR-Connect-Term-Reason noAnswerTone 21
+VALUE USR-Connect-Term-Reason noCarrier 22
+VALUE USR-Connect-Term-Reason undetermined 23
+VALUE USR-Connect-Term-Reason v42SabmeTimeout 24
+VALUE USR-Connect-Term-Reason v42BreakTimeout 25
+VALUE USR-Connect-Term-Reason v42DisconnectCmd 26
+VALUE USR-Connect-Term-Reason v42IdExchangeFail 27
+VALUE USR-Connect-Term-Reason v42BadSetup 28
+VALUE USR-Connect-Term-Reason v42InvalidCodeWord 29
+VALUE USR-Connect-Term-Reason v42StringToLong 30
+VALUE USR-Connect-Term-Reason v42InvalidCommand 31
+VALUE USR-Connect-Term-Reason none 32
+VALUE USR-Connect-Term-Reason v32Cleardown 33
+VALUE USR-Connect-Term-Reason dialSecurity 34
+VALUE USR-Connect-Term-Reason remoteAccessDenied 35
+VALUE USR-Connect-Term-Reason loopLoss 36
+VALUE USR-Connect-Term-Reason ds0Teardown 37
+VALUE USR-Connect-Term-Reason promptNotEnabled 38
+VALUE USR-Connect-Term-Reason noPromptingInSync 39
+VALUE USR-Connect-Term-Reason nonArqMode 40
+VALUE USR-Connect-Term-Reason modeIncompatible 41
+VALUE USR-Connect-Term-Reason noPromptInNonARQ 42
+VALUE USR-Connect-Term-Reason dialBackLink 43
+VALUE USR-Connect-Term-Reason linkAbort 44
+VALUE USR-Connect-Term-Reason autopassFailed 45
+VALUE USR-Connect-Term-Reason pbGenericError 46
+VALUE USR-Connect-Term-Reason pbLinkErrTxPreAck 47
+VALUE USR-Connect-Term-Reason pbLinkErrTxTardyACK 48
+VALUE USR-Connect-Term-Reason pbTransmitBusTimeout 49
+VALUE USR-Connect-Term-Reason pbReceiveBusTimeout 50
+VALUE USR-Connect-Term-Reason pbLinkErrTxTAL 51
+VALUE USR-Connect-Term-Reason pbLinkErrRxTAL 52
+VALUE USR-Connect-Term-Reason pbTransmitMasterTimeout 53
+VALUE USR-Connect-Term-Reason pbClockMissing 54
+VALUE USR-Connect-Term-Reason pbReceivedLsWhileLinkUp 55
+VALUE USR-Connect-Term-Reason pbOutOfSequenceFrame 56
+VALUE USR-Connect-Term-Reason pbBadFrame 57
+VALUE USR-Connect-Term-Reason pbAckWaitTimeout 58
+VALUE USR-Connect-Term-Reason pbReceivedAckSeqErr 59
+VALUE USR-Connect-Term-Reason pbReceiveOvrflwRNRFail 60
+VALUE USR-Connect-Term-Reason pbReceiveMsgBufOvrflw 61
+VALUE USR-Connect-Term-Reason rcvdGatewayDiscCmd 62
+VALUE USR-Connect-Term-Reason tokenPassingTimeout 63
+VALUE USR-Connect-Term-Reason dspInterruptTimeout 64
+VALUE USR-Connect-Term-Reason mnpProtocolViolation 65
+VALUE USR-Connect-Term-Reason class2FaxHangupCmd 66
+VALUE USR-Connect-Term-Reason hstSpeedSwitchTimeout 67
+VALUE USR-Connect-Term-Reason tooManyUnacked 68
+VALUE USR-Connect-Term-Reason timerExpired 69
+VALUE USR-Connect-Term-Reason t1Glare 70
+VALUE USR-Connect-Term-Reason priDialoutRqTimeout 71
+VALUE USR-Connect-Term-Reason abortAnlgDstOvrIsdn 72
+VALUE USR-Connect-Term-Reason normalUserCallClear 73
+VALUE USR-Connect-Term-Reason normalUnspecified 74
+VALUE USR-Connect-Term-Reason bearerIncompatibility 75
+VALUE USR-Connect-Term-Reason protocolErrorEvent 76
+VALUE USR-Connect-Term-Reason abnormalDisconnect 77
+VALUE USR-Connect-Term-Reason invalidCauseValue 78
+VALUE USR-Connect-Term-Reason resourceUnavailable 79
+VALUE USR-Connect-Term-Reason remoteHungUpDuringTraining 80
+VALUE USR-Connect-Term-Reason trainingTimeout 81
+VALUE USR-Connect-Term-Reason incomingModemNotAvailable 82
+VALUE USR-Connect-Term-Reason incomingInvalidBearerCap 83
+VALUE USR-Connect-Term-Reason incomingInvalidChannelID 84
+VALUE USR-Connect-Term-Reason incomingInvalidProgInd 85
+VALUE USR-Connect-Term-Reason incomingInvalidCallingPty 86
+VALUE USR-Connect-Term-Reason incomingInvalidCalledPty 87
+VALUE USR-Connect-Term-Reason incomingCallBlock 88
+VALUE USR-Connect-Term-Reason incomingLoopStNoRingOff 89
+VALUE USR-Connect-Term-Reason outgoingTelcoDisconnect 90
+VALUE USR-Connect-Term-Reason outgoingEMWinkTimeout 91
+VALUE USR-Connect-Term-Reason outgoingEMWinkTooShort 92
+VALUE USR-Connect-Term-Reason outgoingNoChannelAvail 93
+VALUE USR-Connect-Term-Reason dspReboot 94
+VALUE USR-Connect-Term-Reason noDSPRespToKA 95
+VALUE USR-Connect-Term-Reason noDSPRespToDisc 96
+VALUE USR-Connect-Term-Reason dspTailPtrInvalid 97
+VALUE USR-Connect-Term-Reason dspHeadPtrInvalid 98
+
+VALUE USR-Failure-to-Connect-Reason dtrDrop 1
+VALUE USR-Failure-to-Connect-Reason escapeSequence 2
+VALUE USR-Failure-to-Connect-Reason athCommand 3
+VALUE USR-Failure-to-Connect-Reason carrierLoss 4
+VALUE USR-Failure-to-Connect-Reason inactivityTimout 5
+VALUE USR-Failure-to-Connect-Reason mnpIncompatible 6
+VALUE USR-Failure-to-Connect-Reason undefined 7
+VALUE USR-Failure-to-Connect-Reason remotePassword 8
+VALUE USR-Failure-to-Connect-Reason linkPassword 9
+VALUE USR-Failure-to-Connect-Reason retransmitLimit 10
+VALUE USR-Failure-to-Connect-Reason linkDisconnectMsgRec 11
+VALUE USR-Failure-to-Connect-Reason noLoopCurrent 12
+VALUE USR-Failure-to-Connect-Reason invalidSpeed 13
+VALUE USR-Failure-to-Connect-Reason unableToRetrain 14
+VALUE USR-Failure-to-Connect-Reason managementCommand 15
+VALUE USR-Failure-to-Connect-Reason noDialTone 16
+VALUE USR-Failure-to-Connect-Reason keyAbort 17
+VALUE USR-Failure-to-Connect-Reason lineBusy 18
+VALUE USR-Failure-to-Connect-Reason noAnswer 19
+VALUE USR-Failure-to-Connect-Reason voice 20
+VALUE USR-Failure-to-Connect-Reason noAnswerTone 21
+VALUE USR-Failure-to-Connect-Reason noCarrier 22
+VALUE USR-Failure-to-Connect-Reason undetermined 23
+VALUE USR-Failure-to-Connect-Reason v42SabmeTimeout 24
+VALUE USR-Failure-to-Connect-Reason v42BreakTimeout 25
+VALUE USR-Failure-to-Connect-Reason v42DisconnectCmd 26
+VALUE USR-Failure-to-Connect-Reason v42IdExchangeFail 27
+VALUE USR-Failure-to-Connect-Reason v42BadSetup 28
+VALUE USR-Failure-to-Connect-Reason v42InvalidCodeWord 29
+VALUE USR-Failure-to-Connect-Reason v42StringToLong 30
+VALUE USR-Failure-to-Connect-Reason v42InvalidCommand 31
+VALUE USR-Failure-to-Connect-Reason none 32
+VALUE USR-Failure-to-Connect-Reason v32Cleardown 33
+VALUE USR-Failure-to-Connect-Reason dialSecurity 34
+VALUE USR-Failure-to-Connect-Reason remoteAccessDenied 35
+VALUE USR-Failure-to-Connect-Reason loopLoss 36
+VALUE USR-Failure-to-Connect-Reason ds0Teardown 37
+VALUE USR-Failure-to-Connect-Reason promptNotEnabled 38
+VALUE USR-Failure-to-Connect-Reason noPromptingInSync 39
+VALUE USR-Failure-to-Connect-Reason nonArqMode 40
+VALUE USR-Failure-to-Connect-Reason modeIncompatible 41
+VALUE USR-Failure-to-Connect-Reason noPromptInNonARQ 42
+VALUE USR-Failure-to-Connect-Reason dialBackLink 43
+VALUE USR-Failure-to-Connect-Reason linkAbort 44
+VALUE USR-Failure-to-Connect-Reason autopassFailed 45
+VALUE USR-Failure-to-Connect-Reason pbGenericError 46
+VALUE USR-Failure-to-Connect-Reason pbLinkErrTxPreAck 47
+VALUE USR-Failure-to-Connect-Reason pbLinkErrTxTardyACK 48
+VALUE USR-Failure-to-Connect-Reason pbTransmitBusTimeout 49
+VALUE USR-Failure-to-Connect-Reason pbReceiveBusTimeout 50
+VALUE USR-Failure-to-Connect-Reason pbLinkErrTxTAL 51
+VALUE USR-Failure-to-Connect-Reason pbLinkErrRxTAL 52
+VALUE USR-Failure-to-Connect-Reason pbTransmitMasterTimeout 53
+VALUE USR-Failure-to-Connect-Reason pbClockMissing 54
+VALUE USR-Failure-to-Connect-Reason pbReceivedLsWhileLinkUp 55
+VALUE USR-Failure-to-Connect-Reason pbOutOfSequenceFrame 56
+VALUE USR-Failure-to-Connect-Reason pbBadFrame 57
+VALUE USR-Failure-to-Connect-Reason pbAckWaitTimeout 58
+VALUE USR-Failure-to-Connect-Reason pbReceivedAckSeqErr 59
+VALUE USR-Failure-to-Connect-Reason pbReceiveOvrflwRNRFail 60
+VALUE USR-Failure-to-Connect-Reason pbReceiveMsgBufOvrflw 61
+VALUE USR-Failure-to-Connect-Reason rcvdGatewayDiscCmd 62
+VALUE USR-Failure-to-Connect-Reason tokenPassingTimeout 63
+VALUE USR-Failure-to-Connect-Reason dspInterruptTimeout 64
+VALUE USR-Failure-to-Connect-Reason mnpProtocolViolation 65
+VALUE USR-Failure-to-Connect-Reason class2FaxHangupCmd 66
+VALUE USR-Failure-to-Connect-Reason hstSpeedSwitchTimeout 67
+VALUE USR-Failure-to-Connect-Reason tooManyUnacked 68
+VALUE USR-Failure-to-Connect-Reason timerExpired 69
+VALUE USR-Failure-to-Connect-Reason t1Glare 70
+VALUE USR-Failure-to-Connect-Reason priDialoutRqTimeout 71
+VALUE USR-Failure-to-Connect-Reason abortAnlgDstOvrIsdn 72
+VALUE USR-Failure-to-Connect-Reason normalUserCallClear 73
+VALUE USR-Failure-to-Connect-Reason normalUnspecified 74
+VALUE USR-Failure-to-Connect-Reason bearerIncompatibility 75
+VALUE USR-Failure-to-Connect-Reason protocolErrorEvent 76
+VALUE USR-Failure-to-Connect-Reason abnormalDisconnect 77
+VALUE USR-Failure-to-Connect-Reason invalidCauseValue 78
+VALUE USR-Failure-to-Connect-Reason resourceUnavailable 79
+VALUE USR-Failure-to-Connect-Reason remoteHungUpDuringTraining 80
+VALUE USR-Failure-to-Connect-Reason trainingTimeout 81
+VALUE USR-Failure-to-Connect-Reason incomingModemNotAvailable 82
+VALUE USR-Failure-to-Connect-Reason incomingInvalidBearerCap 83
+VALUE USR-Failure-to-Connect-Reason incomingInvalidChannelID 84
+VALUE USR-Failure-to-Connect-Reason incomingInvalidProgInd 85
+VALUE USR-Failure-to-Connect-Reason incomingInvalidCallingPty 86
+VALUE USR-Failure-to-Connect-Reason incomingInvalidCalledPty 87
+VALUE USR-Failure-to-Connect-Reason incomingCallBlock 88
+VALUE USR-Failure-to-Connect-Reason incomingLoopStNoRingOff 89
+VALUE USR-Failure-to-Connect-Reason outgoingTelcoDisconnect 90
+VALUE USR-Failure-to-Connect-Reason outgoingEMWinkTimeout 91
+VALUE USR-Failure-to-Connect-Reason outgoingEMWinkTooShort 92
+VALUE USR-Failure-to-Connect-Reason outgoingNoChannelAvail 93
+VALUE USR-Failure-to-Connect-Reason dspReboot 94
+VALUE USR-Failure-to-Connect-Reason noDSPRespToKA 95
+VALUE USR-Failure-to-Connect-Reason noDSPRespToDisc 96
+VALUE USR-Failure-to-Connect-Reason dspTailPtrInvalid 97
+VALUE USR-Failure-to-Connect-Reason dspHeadPtrInvalid 98
+
+VALUE USR-Simplified-MNP-Levels none 1
+VALUE USR-Simplified-MNP-Levels mnpLevel3 2
+VALUE USR-Simplified-MNP-Levels mnpLevel4 3
+VALUE USR-Simplified-MNP-Levels ccittV42 4
+VALUE USR-Simplified-MNP-Levels usRoboticsHST 5
+VALUE USR-Simplified-MNP-Levels synchronousNone 6
+VALUE USR-Simplified-MNP-Levels mnpLevel2 7
+VALUE USR-Simplified-MNP-Levels mnp10 8
+VALUE USR-Simplified-MNP-Levels v42Etc 9
+VALUE USR-Simplified-MNP-Levels mnp10Etc 10
+VALUE USR-Simplified-MNP-Levels lapmEtc 11
+VALUE USR-Simplified-MNP-Levels v42Etc2 12
+VALUE USR-Simplified-MNP-Levels v42SRej 13
+VALUE USR-Simplified-MNP-Levels piafs 14
+
+VALUE USR-Simplified-V42bis-Usage none 1
+VALUE USR-Simplified-V42bis-Usage ccittV42bis 2
+VALUE USR-Simplified-V42bis-Usage mnpLevel5 3
+
+VALUE USR-Equalization-Type Long 1
+VALUE USR-Equalization-Type Short 2
+
+VALUE USR-Fallback-Enabled Disabled 1
+VALUE USR-Fallback-Enabled Enabled 2
+
+VALUE USR-Back-Channel-Data-Rate 450BPS 1
+VALUE USR-Back-Channel-Data-Rate 300BPS 2
+VALUE USR-Back-Channel-Data-Rate None 3
+
+VALUE USR-Device-Connected-To None 1
+VALUE USR-Device-Connected-To isdnGateway 2
+VALUE USR-Device-Connected-To quadModem 3
+
+VALUE USR-Call-Event-Code notSupported 1
+VALUE USR-Call-Event-Code setup 2
+VALUE USR-Call-Event-Code usrSetup 3
+VALUE USR-Call-Event-Code telcoDisconnect 4
+VALUE USR-Call-Event-Code usrDisconnect 5
+VALUE USR-Call-Event-Code noFreeModem 6
+VALUE USR-Call-Event-Code modemsNotAllowed 7
+VALUE USR-Call-Event-Code modemsRejectCall 8
+VALUE USR-Call-Event-Code modemSetupTimeout 9
+VALUE USR-Call-Event-Code noFreeIGW 10
+VALUE USR-Call-Event-Code igwRejectCall 11
+VALUE USR-Call-Event-Code igwSetupTimeout 12
+VALUE USR-Call-Event-Code noFreeTdmts 13
+VALUE USR-Call-Event-Code bcReject 14
+VALUE USR-Call-Event-Code ieReject 15
+VALUE USR-Call-Event-Code chidReject 16
+VALUE USR-Call-Event-Code progReject 17
+VALUE USR-Call-Event-Code callingPartyReject 18
+VALUE USR-Call-Event-Code calledPartyReject 19
+VALUE USR-Call-Event-Code blocked 20
+VALUE USR-Call-Event-Code analogBlocked 21
+VALUE USR-Call-Event-Code digitalBlocked 22
+VALUE USR-Call-Event-Code outOfService 23
+VALUE USR-Call-Event-Code busy 24
+VALUE USR-Call-Event-Code congestion 25
+VALUE USR-Call-Event-Code protocolError 26
+VALUE USR-Call-Event-Code noFreeBchannel 27
+VALUE USR-Call-Event-Code inOutCallCollision 28
+VALUE USR-Call-Event-Code inCallArrival 29
+VALUE USR-Call-Event-Code outCallArrival 30
+VALUE USR-Call-Event-Code inCallConnect 31
+VALUE USR-Call-Event-Code outCallConnect 32
+
+VALUE USR-HARC-Disconnect-Code No-Error 0
+VALUE USR-HARC-Disconnect-Code No-Carrier 1
+VALUE USR-HARC-Disconnect-Code No-DSR 2
+VALUE USR-HARC-Disconnect-Code Timeout 3
+VALUE USR-HARC-Disconnect-Code Reset 4
+VALUE USR-HARC-Disconnect-Code Call-Drop-Req 5
+VALUE USR-HARC-Disconnect-Code Idle-Timeout 6
+VALUE USR-HARC-Disconnect-Code Session-Timeout 7
+VALUE USR-HARC-Disconnect-Code User-Req-Drop 8
+VALUE USR-HARC-Disconnect-Code Host-Req-Drop 9
+VALUE USR-HARC-Disconnect-Code Service-Interruption 10
+VALUE USR-HARC-Disconnect-Code Service-Unavailable 11
+VALUE USR-HARC-Disconnect-Code User-Input-Error 12
+VALUE USR-HARC-Disconnect-Code NAS-Drop-For-Callback 13
+VALUE USR-HARC-Disconnect-Code NAS-Drop-Misc-Non-Error 14
+VALUE USR-HARC-Disconnect-Code NAS-Internal-Error 15
+VALUE USR-HARC-Disconnect-Code Line-Busy 16
+VALUE USR-HARC-Disconnect-Code Tunnel-Term-Unreach 19
+VALUE USR-HARC-Disconnect-Code Tunnel-Refused 20
+VALUE USR-HARC-Disconnect-Code Tunnel-Auth-Failed 21
+VALUE USR-HARC-Disconnect-Code Tunnel-Session-Timeout 22
+VALUE USR-HARC-Disconnect-Code Tunnel-Timeout 23
+VALUE USR-HARC-Disconnect-Code Radius-Res-Reclaim 25
+VALUE USR-HARC-Disconnect-Code DNIS-Auth-Failed 26
+VALUE USR-HARC-Disconnect-Code PAP-Auth-Failure 27
+VALUE USR-HARC-Disconnect-Code CHAP-Auth-Failure 28
+VALUE USR-HARC-Disconnect-Code PPP-LCP-Failed 29
+VALUE USR-HARC-Disconnect-Code PPP-NCP-Failed 30
+VALUE USR-HARC-Disconnect-Code Radius-Timeout 31
+
+VALUE USR-CCP-Algorithm NONE 1
+VALUE USR-CCP-Algorithm Stac 2
+VALUE USR-CCP-Algorithm MS 3
+VALUE USR-CCP-Algorithm Any 4
+
+VALUE USR-Tunnel-Security None 0
+VALUE USR-Tunnel-Security Control-Only 1
+VALUE USR-Tunnel-Security Data-Only 2
+VALUE USR-Tunnel-Security Both-Data-and-Control 3
+
+VALUE USR-RMMIE-Status notEnabledInLocalModem 1
+VALUE USR-RMMIE-Status notDetectedInRemoteModem 2
+VALUE USR-RMMIE-Status ok 3
+
+VALUE USR-RMMIE-x2-Status notOperational 1
+VALUE USR-RMMIE-x2-Status operational 2
+VALUE USR-RMMIE-x2-Status x2Disabled 3
+VALUE USR-RMMIE-x2-Status v8Disabled 4
+VALUE USR-RMMIE-x2-Status remote3200Disabled 5
+VALUE USR-RMMIE-x2-Status invalidSpeedSetting 6
+VALUE USR-RMMIE-x2-Status v8NotDetected 7
+VALUE USR-RMMIE-x2-Status x2NotDetected 8
+VALUE USR-RMMIE-x2-Status incompatibleVersion 9
+VALUE USR-RMMIE-x2-Status incompatibleModes 10
+VALUE USR-RMMIE-x2-Status local3200Disabled 11
+VALUE USR-RMMIE-x2-Status excessHighFrequencyAtten 12
+VALUE USR-RMMIE-x2-Status connectNotSupport3200 13
+VALUE USR-RMMIE-x2-Status retrainBeforeConnection 14
+
+VALUE USR-RMMIE-Planned-Disconnect none 1
+VALUE USR-RMMIE-Planned-Disconnect dteNotReady 2
+VALUE USR-RMMIE-Planned-Disconnect dteInterfaceError 3
+VALUE USR-RMMIE-Planned-Disconnect dteRequest 4
+VALUE USR-RMMIE-Planned-Disconnect escapeToOnlineCommandMode 5
+VALUE USR-RMMIE-Planned-Disconnect athCommand 6
+VALUE USR-RMMIE-Planned-Disconnect inactivityTimeout 7
+VALUE USR-RMMIE-Planned-Disconnect arqProtocolError 8
+VALUE USR-RMMIE-Planned-Disconnect arqProtocolRetransmitLim 9
+VALUE USR-RMMIE-Planned-Disconnect invalidComprDataCodeword 10
+VALUE USR-RMMIE-Planned-Disconnect invalidComprDataStringLen 11
+VALUE USR-RMMIE-Planned-Disconnect invalidComprDataCommand 12
+
+VALUE USR-RMMIE-Last-Update-Event none 1
+VALUE USR-RMMIE-Last-Update-Event initialConnection 2
+VALUE USR-RMMIE-Last-Update-Event retrain 3
+VALUE USR-RMMIE-Last-Update-Event speedShift 4
+VALUE USR-RMMIE-Last-Update-Event plannedDisconnect 5
+
+VALUE USR-Request-Type Access-Request 1
+VALUE USR-Request-Type Access-Accept 2
+VALUE USR-Request-Type Access-Reject 3
+VALUE USR-Request-Type Accounting-Request 4
+VALUE USR-Request-Type Accounting-Response 5
+# The next three non standard packet types are used by
+# US Robotics Security/Accounting Server
+VALUE USR-Request-Type Access-Password-Change 7
+VALUE USR-Request-Type Access-Password-Ack 8
+VALUE USR-Request-Type Access-Password-Reject 9
+VALUE USR-Request-Type Access-Challenge 11
+VALUE USR-Request-Type Status-Server 12
+VALUE USR-Request-Type Status-Client 13
+# Non standard packet types used by NetServer to implement
+# resource management and NAS reboot conditions
+VALUE USR-Request-Type Resource-Free-Request 21
+VALUE USR-Request-Type Resource-Free-Response 22
+VALUE USR-Request-Type Resource-Query-Request 23
+VALUE USR-Request-Type Resource-Query-Response 24
+VALUE USR-Request-Type Disconnect-User 25
+VALUE USR-Request-Type NAS-Reboot-Request 26
+VALUE USR-Request-Type NAS-Reboot-Response 27
+# This value is used for Tacacs Plus translation
+VALUE USR-Request-Type Tacacs-Message 253
+VALUE USR-Request-Type Reserved 255
+
+VALUE USR-Speed-Of-Connection Auto 0
+VALUE USR-Speed-Of-Connection 56 1
+VALUE USR-Speed-Of-Connection 64 2
+VALUE USR-Speed-Of-Connection Voice 3
+
+VALUE USR-Expansion-Algorithm Constant 1
+VALUE USR-Expansion-Algorithm Linear 2
+
+VALUE USR-Compression-Algorithm None 0
+VALUE USR-Compression-Algorithm Stac 1
+VALUE USR-Compression-Algorithm Ascend 2
+VALUE USR-Compression-Algorithm Microsoft 3
+VALUE USR-Compression-Algorithm Auto 4
+
+VALUE USR-Compression-Reset-Mode Auto 0
+VALUE USR-Compression-Reset-Mode Reset-Every-Packet 1
+VALUE USR-Compression-Reset-Mode Reset-On-Error 2
+
+VALUE USR-Filter-Zones enabled 1
+VALUE USR-Filter-Zones disabled 2
+
+VALUE USR-Bridging enabled 1
+VALUE USR-Bridging disabled 2
+
+VALUE USR-Appletalk enabled 1
+VALUE USR-Appletalk disabled 2
+
+VALUE USR-Spoofing enabled 1
+VALUE USR-Spoofing disabled 2
+
+VALUE USR-Routing-Protocol Rip1 1
+VALUE USR-Routing-Protocol Rip2 2
+
+VALUE USR-IPX-Routing none 0
+VALUE USR-IPX-Routing send 1
+VALUE USR-IPX-Routing listen 2
+VALUE USR-IPX-Routing respond 3
+VALUE USR-IPX-Routing all 4
+
+VALUE USR-IPX-WAN enabled 1
+VALUE USR-IPX-WAN disabled 2
+
+VALUE USR-IP-Default-Route-Option enabled 1
+VALUE USR-IP-Default-Route-Option disabled 2
+
+VALUE USR-IP-RIP-Policies SendDefault 0x0
+VALUE USR-IP-RIP-Policies SendRoutes 0x2
+VALUE USR-IP-RIP-Policies SendSubnets 0x4
+VALUE USR-IP-RIP-Policies AcceptDefault 0x8
+VALUE USR-IP-RIP-Policies SplitHorizon 0x10
+VALUE USR-IP-RIP-Policies PoisonReserve 0x20
+VALUE USR-IP-RIP-Policies FlashUpdate 0x40
+VALUE USR-IP-RIP-Policies SimpleAuth 0x80
+VALUE USR-IP-RIP-Policies V1Send 0x100
+VALUE USR-IP-RIP-Policies V1Receive 0x200
+VALUE USR-IP-RIP-Policies V2Receive 0x400
+VALUE USR-IP-RIP-Policies Silent 0x80000000
+
+VALUE USR-Callback-Type Normal 1
+VALUE USR-Callback-Type ANI 2
+VALUE USR-Callback-Type Static 3
+VALUE USR-Callback-Type Dynamic 4
+
+VALUE USR-Agent FA 1
+VALUE USR-Agent HA 2
+
+VALUE USR-NAS-Type 3Com-NMC 0
+VALUE USR-NAS-Type 3Com-NETServer 1
+VALUE USR-NAS-Type 3Com-HiPerArc 2
+VALUE USR-NAS-Type TACACS+-Server 3
+VALUE USR-NAS-Type 3Com-SA-Server 4
+VALUE USR-NAS-Type Ascend 5
+VALUE USR-NAS-Type Generic-RADIUS 6
+VALUE USR-NAS-Type 3Com-NETBuilder-II 7
+
+VALUE USR-Auth-Mode Auth-3Com 0
+VALUE USR-Auth-Mode Auth-Ace 1
+VALUE USR-Auth-Mode Auth-Safeword 2
+VALUE USR-Auth-Mode Auth-UNIX-PW 3
+VALUE USR-Auth-Mode Auth-Defender 4
+VALUE USR-Auth-Mode Auth-TACACSP 5
+VALUE USR-Auth-Mode Auth-Netware 6
+VALUE USR-Auth-Mode Auth-Skey 7
+VALUE USR-Auth-Mode Auth-EAP-Proxy 8
+VALUE USR-Auth-Mode Auth-UNIX-Crypt 9
+
+VALUE CW-Acct-Type COMS-UNKNOWN-ACCT-TYPE 0
+VALUE CW-Acct-Type COMS-PREPAID-ACCT 1
+VALUE CW-Acct-Type COMS-NEW-ACCT 2
+VALUE CW-Acct-Type COMS-SUSPENDED-ACCT 3
+VALUE CW-Acct-Type COMS-ADMINISTRATIVE-ACCT 4
+
+VALUE CW-Source-Identifier COMS-UNKNOWN-SOURCE 0
+VALUE CW-Source-Identifier COMS-INGRESS-OPEN 257
+VALUE CW-Source-Identifier COMS-EGRESS-OPEN 258
+VALUE CW-Source-Identifier COMS-GTKPR-GEN-INGR-OPEN 259
+VALUE CW-Source-Identifier COMS-GTKPR-GEN-EGR-OPEN 260
+VALUE CW-Source-Identifier COMS-INGRESS-CLOSE 513
+VALUE CW-Source-Identifier COMS-EGRESS-CLOSE 514
+VALUE CW-Source-Identifier COMS-GTKPR-GEN-INGR-CLOSE 515
+VALUE CW-Source-Identifier COMS-GTKPR-GEN-EGR-CLOSE 516
+
+VALUE CW-Session-Sequence-End NOT-THE-LAST-CALL 0
+VALUE CW-Session-Sequence-End LAST-CALL 1
+
+VALUE CW-Clg-Party-E164-Type comsUnknown 1
+VALUE CW-Clg-Party-E164-Type comsInternationalNumber 2
+VALUE CW-Clg-Party-E164-Type comsNationalNumber 3
+VALUE CW-Clg-Party-E164-Type comsNetworkSpecificNumber 4
+VALUE CW-Clg-Party-E164-Type comsSubscriberNumber 5
+VALUE CW-Clg-Party-E164-Type comsAbbreviatedNumber 6
+VALUE CW-Clg-Party-E164-Type comsReserved 7
+
+VALUE CW-Clg-Party-Trans-Protocol TCP 1
+VALUE CW-Clg-Party-Trans-Protocol UDP 2
+VALUE CW-Clg-Party-Trans-Protocol SCTP 3
+
+VALUE CW-Cld-Party-E164-Type comsUnknown 1
+VALUE CW-Cld-Party-E164-Type comsInternationalNumber 2
+VALUE CW-Cld-Party-E164-Type comsNationalNumber 3
+VALUE CW-Cld-Party-E164-Type comsNetworkSpecificNumber 4
+VALUE CW-Cld-Party-E164-Type comsSubscriberNumber 5
+VALUE CW-Cld-Party-E164-Type comsAbbreviatedNumber 6
+VALUE CW-Cld-Party-E164-Type comsReserved 7
+
+VALUE CW-Cld-Party-Trans-Protocol TCP 1
+VALUE CW-Cld-Party-Trans-Protocol UDP 2
+VALUE CW-Cld-Party-Trans-Protocol SCTP 3
+
+VALUE CW-Ingr-Gway-E164-Type comsUnknown 1
+VALUE CW-Ingr-Gway-E164-Type comsInternationalNumber 2
+VALUE CW-Ingr-Gway-E164-Type comsNationalNumber 3
+VALUE CW-Ingr-Gway-E164-Type comsNetworkSpecificNumber 4
+VALUE CW-Ingr-Gway-E164-Type comsSubscriberNumber 5
+VALUE CW-Ingr-Gway-E164-Type comsAbbreviatedNumber 6
+VALUE CW-Ingr-Gway-E164-Type comsReserved 7
+
+VALUE CW-Ingr-Gway-Trans-Protocol TCP 1
+VALUE CW-Ingr-Gway-Trans-Protocol UDP 2
+VALUE CW-Ingr-Gway-Trans-Protocol SCTP 3
+
+VALUE CW-Egr-Gway-Trans-Protocol TCP 1
+VALUE CW-Egr-Gway-Trans-Protocol UDP 2
+VALUE CW-Egr-Gway-Trans-Protocol SCTP 3
+
+VALUE CW-Ingr-Gtkpr-Trans-Protocol TCP 1
+VALUE CW-Ingr-Gtkpr-Trans-Protocol UDP 2
+VALUE CW-Ingr-Gtkpr-Trans-Protocol SCTP 3
+
+VALUE CW-Egr-Gtkpr-Trans-Protocol TCP 1
+VALUE CW-Egr-Gtkpr-Trans-Protocol UDP 2
+VALUE CW-Egr-Gtkpr-Trans-Protocol SCTP 3
+
+VALUE CW-Call-Type COMS-UNKNOWN-CALLTYPE 0
+VALUE CW-Call-Type COMS-PHONE-TO-PHONE 1
+VALUE CW-Call-Type COMS-PHONE-TO-PC 2
+VALUE CW-Call-Type COMS-PC-TO-PHONE 3
+VALUE CW-Call-Type COMS-PC-TO-PC 4
+
+VALUE CW-Codec-Type COMS-UNDEFINED-CODEC 0
+VALUE CW-Codec-Type COMS-G723-1 1
+VALUE CW-Codec-Type COMS-G729-A 2
+VALUE CW-Codec-Type COMS-G710-ALaw 3
+VALUE CW-Codec-Type COMS-G711-MuLaw 4
+VALUE CW-Codec-Type COMS-FAX-MODULATION 255
+
+VALUE CW-Call-Termination-Cause CAUSE-UNKNOWN 0
+VALUE CW-Call-Termination-Cause CAUSE-CLD-PARTY-TERMINATE 1
+VALUE CW-Call-Termination-Cause CAUSE-CLG-PARTY-TERMINATE 2
+VALUE CW-Call-Termination-Cause CAUSE-ACCT-BAL-DEPLETED 3
+VALUE CW-Call-Termination-Cause CAUSE-NO-EGR-PORTS-AVAIL 4
+VALUE CW-Call-Termination-Cause CAUSE-H225-UNABLE-TO-CON 5
+VALUE CW-Call-Termination-Cause CAUSE-H245-UNABLE-TO-CON 6
+VALUE CW-Call-Termination-Cause CAUSE-INGR-FACILITY-DISC 7
+VALUE CW-Call-Termination-Cause CAUSE-EGR-FACILITY-DISC 8
+VALUE CW-Call-Termination-Cause CAUSE-DIR-SERVER-DOWN 9
+VALUE CW-Call-Termination-Cause CAUSE-RATING-SERVER-DOWN 10
+VALUE CW-Call-Termination-Cause CAUSE-GATEWAY-SHUTDOWN 11
+VALUE CW-Call-Termination-Cause CAUSE-GTKPR-TERMINATE 12
+VALUE CW-Call-Termination-Cause CAUSE-GTKPR-SHUTDOWN-GTWAY 13
+VALUE CW-Call-Termination-Cause CAUSE-BUSY 14
+VALUE CW-Call-Termination-Cause CAUSE-ABANDON 15
+VALUE CW-Call-Termination-Cause CAUSE-INVALID-LOGIN-LIMIT 16
+VALUE CW-Call-Termination-Cause CAUSE-NOACCTNUMBER-ENTRY 17
+VALUE CW-Call-Termination-Cause CAUSE-SUSPENDED-ACCT-LOGIN 18
+VALUE CW-Call-Termination-Cause CAUSE-AUTHENT-SERVER-DOWN 19
+VALUE CW-Call-Termination-Cause CAUSE-GATEKEEPER-TIMEOUT 20
+VALUE CW-Call-Termination-Cause CAUSE-GATEWAY-NO-RESOURCES 21
+VALUE CW-Call-Termination-Cause CAUSE-ACCT-INUSE 22
+VALUE CW-Call-Termination-Cause CAUSE-DEBIT-ACCT-BAL-ZERO 23
+VALUE CW-Call-Termination-Cause CAUSE-DEBIT-ACCTBAL-INSUFF 24
+VALUE CW-Call-Termination-Cause CAUSE-INVALID-DESTNUMBER-THRESH 25
+VALUE CW-Call-Termination-Cause CAUSE-NO-DESTNUMBER-ENTRY 26
+VALUE CW-Call-Termination-Cause CAUSE-SEQUENCE-DIALING-THRESH 27
+
+VALUE CW-Signaling-Protocol SIG-UNKNOWN 0
+VALUE CW-Signaling-Protocol SIG-SIP 1
+VALUE CW-Signaling-Protocol SIG-H323 2
+
+VALUE CW-Protocol-Transport TCP 1
+VALUE CW-Protocol-Transport UDP 2
+VALUE CW-Protocol-Transport SCTP 3
+
+VALUE CW-Local-Sig-Trans-Protocol TCP 1
+VALUE CW-Local-Sig-Trans-Protocol UDP 2
+VALUE CW-Local-Sig-Trans-Protocol SCTP 3
+
+VALUE CW-Remote-Sig-Trans-Protocol TCP 1
+VALUE CW-Remote-Sig-Trans-Protocol UDP 2
+VALUE CW-Remote-Sig-Trans-Protocol SCTP 3
+
+VALUE CW-Local-MG-RTP-Protocol TCP 1
+VALUE CW-Local-MG-RTP-Protocol UDP 2
+VALUE CW-Local-MG-RTP-Protocol SCTP 3
+
+VALUE CW-Remote-MG-RTP-Protocol TCP 1
+VALUE CW-Remote-MG-RTP-Protocol UDP 2
+VALUE CW-Remote-MG-RTP-Protocol SCTP 3
+
+VALUE CW-Trans-Cld-Party-E164-Type Unknown 1
+VALUE CW-Trans-Cld-Party-E164-Type International-Number 2
+VALUE CW-Trans-Cld-Party-E164-Type National-Number 3
+VALUE CW-Trans-Cld-Party-E164-Type Network-Specific-Number 4
+VALUE CW-Trans-Cld-Party-E164-Type Subscriber-Number 5
+VALUE CW-Trans-Cld-Party-E164-Type Abbreviated-Number 6
+VALUE CW-Trans-Cld-Party-E164-Type Reserved 7
+
+END-VENDOR USR
diff --git a/share/dictionary.usr.illegal b/share/dictionary.usr.illegal
new file mode 100644
index 0000000..b751767
--- /dev/null
+++ b/share/dictionary.usr.illegal
@@ -0,0 +1,49 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# USE dictionary that illegally uses the RFC space.
+#
+# $Id$
+#
+##############################################################################
+#
+# USR specific attributes
+#
+# Prompt value should be 1 for echo, 0 for no echo, default 1.
+#ATTRIBUTE Prompt 64 integer
+ATTRIBUTE Multi-Link-Flag 126 integer
+ATTRIBUTE Char-Noecho 250 integer
+
+#
+# USR specific Integer Translations
+#
+
+VALUE Termination-Action Manage-Resources 2
+
+VALUE Acct-Status-Type Modem-Start 4
+VALUE Acct-Status-Type Modem-Stop 5
+VALUE Acct-Status-Type Cancel 6
+
+VALUE Multi-Link-Flag True 1
+VALUE Multi-Link-Flag False 0
+
+# USR specific Authentication Types
+
+#
+# These are commented out because the conflict with the standard
+# definitions.
+#
+#VALUE Acct-Authentic None 0
+#VALUE Acct-Authentic Remote 3
+#VALUE Acct-Authentic RADIUS 4
+#VALUE Acct-Authentic MNET 5
+#VALUE Acct-Authentic KCHAP 6
+#VALUE Acct-Authentic TACACS 7
+#VALUE Acct-Authentic Realm 8
+#VALUE Acct-Authentic Local 9
+#VALUE Acct-Authentic File 10
+#VALUE Acct-Authentic Local-VPN 11
+
diff --git a/share/dictionary.utstarcom b/share/dictionary.utstarcom
new file mode 100644
index 0000000..152d5c1
--- /dev/null
+++ b/share/dictionary.utstarcom
@@ -0,0 +1,45 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# UT Starcom (China)
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR UTStarcom 7064
+
+BEGIN-VENDOR UTStarcom
+
+ATTRIBUTE UTStarcom-VLAN-ID 140 integer
+ATTRIBUTE UTStarcom-CommittedBandwidth 142 integer
+ATTRIBUTE UTStarcom-MaxBandwidth 143 integer
+ATTRIBUTE UTStarcom-Priority 145 integer
+ATTRIBUTE UTStarcom-Error-Reason 147 integer
+ATTRIBUTE UTStarcom-PrimaryDNS 152 integer
+ATTRIBUTE UTStarcom-SecondaryDNS 153 integer
+ATTRIBUTE UTStarcom-MaxBurstSize 161 integer
+ATTRIBUTE UTStarcom-MaxDelay 162 integer
+ATTRIBUTE UTStarcom-MaxJitter 163 integer
+ATTRIBUTE UTStarcom-DeviceId 165 string
+ATTRIBUTE UTStarcom-Module-Id 166 integer
+ATTRIBUTE UTStarcom-Port-No 167 integer
+ATTRIBUTE UTStarcom-Logical-Port-No 168 integer
+ATTRIBUTE UTStarcom-UNI-MAX-MAC 169 integer
+ATTRIBUTE UTStarcom-Default-Gateway 170 integer
+ATTRIBUTE UTStarcom-CLI-Access-Level 171 integer
+ATTRIBUTE UTStarcom-Act-Input-Octets 180 string
+ATTRIBUTE UTStarcom-Act-Output-Octets 181 string
+ATTRIBUTE UTStarcom-Act-Input-Frames 182 string
+ATTRIBUTE UTStarcom-Act-Output-Frames 183 string
+ATTRIBUTE UTStarcom-Onu-MC-Filter-Enable 184 integer
+ATTRIBUTE UTStarcom-UNI-Auto-Negotiation 185 integer
+ATTRIBUTE UTStarcom-UNI-Speed 186 integer
+ATTRIBUTE UTStarcom-UNI-Duplex 187 integer
+ATTRIBUTE UTStarcom-ONU-Admin_status 188 integer
+ATTRIBUTE UTStarcom-ONU-FW-SC-Upgrade 189 integer
+
+END-VENDOR UTStarcom
diff --git a/share/dictionary.valemount b/share/dictionary.valemount
new file mode 100644
index 0000000..aeb61ba
--- /dev/null
+++ b/share/dictionary.valemount
@@ -0,0 +1,29 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Valemount Networks Corporation specific radius attributes
+# networks@valemount.com
+#
+# $Id$
+#
+
+VENDOR ValemountNetworks 16313
+
+BEGIN-VENDOR ValemountNetworks
+
+# Rates to give PPPoE customers, can be used in Authentication replies,
+# in bits/s
+ATTRIBUTE VNC-PPPoE-CBQ-RX 1 integer
+ATTRIBUTE VNC-PPPoE-CBQ-TX 2 integer
+
+# Fallback support for each direction. (1 / 0)
+ATTRIBUTE VNC-PPPoE-CBQ-RX-Fallback 3 integer
+ATTRIBUTE VNC-PPPoE-CBQ-TX-Fallback 4 integer
+
+ATTRIBUTE VNC-Splash 10 integer
+
+VALUE VNC-Splash Show 1
+VALUE VNC-Splash No-Show 0
+
+END-VENDOR ValemountNetworks
diff --git a/share/dictionary.vasexperts b/share/dictionary.vasexperts
new file mode 100644
index 0000000..a4c3a05
--- /dev/null
+++ b/share/dictionary.vasexperts
@@ -0,0 +1,93 @@
+# -*- text -*-
+# Copyright (C) 2020 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+# Version $Id$
+#
+# VAS Experts dictionary
+#
+VENDOR VasExperts 43823
+
+BEGIN-VENDOR VasExperts
+
+ATTRIBUTE VasExperts-Policing-Profile 1 string
+ATTRIBUTE VasExperts-Service-Profile 2 string
+ATTRIBUTE VasExperts-Enable-Service 3 string
+ATTRIBUTE VasExperts-Multi-IP-User 4 integer
+ATTRIBUTE VasExperts-UserName 5 string
+ATTRIBUTE VasExperts-Service-Type 6 integer
+ATTRIBUTE VasExperts-Restrict-User 7 integer
+ATTRIBUTE VasExperts-Enable-Interconnect 8 integer
+ATTRIBUTE VasExperts-OutVLAN 9 integer
+ATTRIBUTE VasExperts-Command-Code 10 integer # CoA command code
+ATTRIBUTE VasExperts-OutMAC 11 string
+
+VALUE VasExperts-Service-Type Auth 0 # L3-authorization, known IP
+VALUE VasExperts-Service-Type DHCP 1 # DHCP
+VALUE VasExperts-Service-Type PAP 2 # PAP authorization
+VALUE VasExperts-Service-Type CHAP 3 # CHAP authorization
+VALUE VasExperts-Service-Type MS_CHAPv2 4 # MS-CHAPv2 authorization
+VALUE VasExperts-Service-Type MAC_QinQ 5 # MAC/QinQ authorization
+VALUE VasExperts-Service-Type ARP 6 # ARP
+VALUE VasExperts-Service-Type DHCPv6 7 # DHCPv6
+
+VALUE VasExperts-Command-Code Check-Acct 1 # Check Accounting session for Framed-IP-Address
+
+# Accounting
+ATTRIBUTE VasExperts-Acct-Traffic-Class-Name 16 string
+ATTRIBUTE VasExperts-Acct-Traffic-Class-Input-Octets 17 integer64
+ATTRIBUTE VasExperts-Acct-Traffic-Class-Output-Octets 18 integer64
+ATTRIBUTE VasExperts-Acct-Traffic-Class-Input-Packets 19 integer64
+ATTRIBUTE VasExperts-Acct-Traffic-Class-Output-Packets 20 integer64
+ATTRIBUTE VasExperts-NAT-IP 21 ipaddr # NAT 1:1 white address
+
+# DHCP -> Radius attributes
+ATTRIBUTE VasExperts-DHCP-Hostname 32 octets # DHCP Opt12
+ATTRIBUTE VasExperts-DHCP-ClientId 33 octets # DHCP Opt61
+ATTRIBUTE VasExperts-DHCP-ClassId 34 octets # DHCP Opt60
+ATTRIBUTE VasExperts-DHCP-RelayInfo 35 octets # DHCP Opt82
+ATTRIBUTE VasExperts-DHCP-ClientIP 36 ipaddr # DHCP Opt50
+ATTRIBUTE VasExperts-DHCP-Request 37 integer
+ATTRIBUTE VasExperts-DHCP-RelayRemoteId 38 octets # DHCP Opt82 subopt 2
+ATTRIBUTE VasExperts-DHCP-RelayCircuitId 39 octets # DHCP Opt82 subopt 1
+
+VALUE VasExperts-DHCP-Request Discover 0
+VALUE VasExperts-DHCP-Request Inform 1
+VALUE VasExperts-DHCP-Request Request 2
+
+# Radius -> DHCP (Access-Accept, Access-Reject)
+ATTRIBUTE VasExperts-DHCP-Option 40 octets # Any DHCP option in binary form
+ATTRIBUTE VasExperts-DHCP-DNS 41 ipaddr # DNS IP address
+ATTRIBUTE VasExperts-DHCP-Gateway 42 ipaddr # Gateway IP address
+ATTRIBUTE VasExperts-BOOTP-SName 43 string # BOOTP SName
+ATTRIBUTE VasExperts-BOOTP-File 44 string # BOOTP File
+ATTRIBUTE VasExperts-DHCP-Option-IP 45 string # IPv4 option: "opt:192.168.6.90", for example: "42:192.168.6.90"
+ATTRIBUTE VasExperts-DHCP-Option-Num 46 string # Numeric option: "opt:1500", for example: "58:3600"
+ATTRIBUTE VasExperts-DHCP-Option-String 47 string # String option: "opt:text", for example: "56:Hello from DHCP!"
+ATTRIBUTE VasExperts-DHCP-Option-Bin 48 string # Binary option in hex form: "opt:xxxxxxxx", for example: "58:100E"
+
+ATTRIBUTE VasExperts-ARP-SourceIP 60 ipaddr # ARP source IP
+ATTRIBUTE VasExperts-ARP-TargetIP 61 ipaddr # ARP target IP
+
+# DHCPv6 -> Radius attributes
+ATTRIBUTE VasExperts-DHCPv6-Request 70 integer # DHCPv6 request type
+ATTRIBUTE VasExperts-DHCPv6-UserClass 71 octets # DHCPv6 User Class option
+ATTRIBUTE VasExperts-DHCPv6-VendorClass 72 octets # DHCPv6 Vendor Class option
+ATTRIBUTE VasExperts-DHCPv6-RemoteId 73 octets # DHCPv6 RemoteId option [RFC 4649]
+ATTRIBUTE VasExperts-DHCPv6-SubsId 74 octets # DHCPv6 SubscriberId option [RFC 4580]
+ATTRIBUTE VasExperts-DHCPv6-Delegated 75 integer # DHCPv6 flag: (1) - CPE requests delegated prefix, (0) - does not
+
+# Radius -> DHCPv6 attributes
+ATTRIBUTE VasExperts-DHCP-Option-IPv6 80 string # IPv6 option: "opt:2001:fde3::709", for example: "22:2001:fde3::709"
+ATTRIBUTE VasExperts-DHCP-Option-IPv6-Prefix 81 string # IPv6 prefix option: "opt:2001:fde3/64"
+ATTRIBUTE VasExperts-DHCP6-Option-Num 82 string # DHCPv6 numeric option: "opt:1500", for example: "58:3600"
+ATTRIBUTE VasExperts-DHCP6-Option-String 83 string # DHCPv6 string option: "opt:text", for example: "56:Hello from DHCP!"
+ATTRIBUTE VasExperts-DHCP6-Option-Bin 84 string # DHCPv6 binary option in hex form: "opt:xxxxxxxx", for example: "58:100E"
+
+VALUE VasExperts-DHCPv6-Request Solicit 1
+VALUE VasExperts-DHCPv6-Request Request 3
+VALUE VasExperts-DHCPv6-Request Renew 5
+VALUE VasExperts-DHCPv6-Request Rebind 6
+
+# Attributes 250 - 255 are dedicated to the customer's private use and are not used (ignored) by pcrf
+
+END-VENDOR VasExperts
diff --git a/share/dictionary.verizon b/share/dictionary.verizon
new file mode 100644
index 0000000..4bd8693
--- /dev/null
+++ b/share/dictionary.verizon
@@ -0,0 +1,26 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Verizon RADIUS Dictionary for Diameter Rf
+#
+##############################################################################
+
+VENDOR VerizonWireless 12951
+
+BEGIN-VENDOR VerizonWireless
+
+ATTRIBUTE Acct-Interim-Record-Number 200 integer
+ATTRIBUTE UE-Info-Type 201 integer
+ATTRIBUTE UE-Info-Value 202 string
+ATTRIBUTE Dynamic-Address-Flag 203 integer
+ATTRIBUTE Local-Seq-Number 204 integer
+ATTRIBUTE Time-First-Usage 205 date
+ATTRIBUTE Time-Last-Usage 206 date
+ATTRIBUTE Charging-Group-ID 207 string
+ATTRIBUTE Service-Data-Container-Bin 210 octets
+ATTRIBUTE Service-Data-Container 211 tlv
+
+END-VENDOR VerizonWireless
diff --git a/share/dictionary.versanet b/share/dictionary.versanet
new file mode 100644
index 0000000..e63c429
--- /dev/null
+++ b/share/dictionary.versanet
@@ -0,0 +1,56 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# dictionary.versanet Vendor specfic attributes for versanet
+#
+#
+# VersaNet Communications, Inc.
+# Http://www.versa-net.com
+#
+#
+#Versanet add Vendor specific terminal cause in our radius group.
+#You can follow this to set it in NAS box.
+#
+# >> gr radius
+# >> sh
+# >> set 34 23
+# >> co
+#
+#This will let our unit transfer every detail terminal cause
+#information to Redius server's accounting log file and
+#save as "Vendor Specific=Terminate Cause".
+#
+# Version: @(#)dictionary.versanet 1.00 22-Jul-1999 support@versanetcomm.com
+#
+
+VENDOR Versanet 2180
+
+BEGIN-VENDOR Versanet
+
+ATTRIBUTE Versanet-Termination-Cause 1 integer
+
+VALUE Versanet-Termination-Cause Normal-Hangup-No-Error-Occurred 0
+VALUE Versanet-Termination-Cause Call-Waiting-Caused-Disconnect 3
+VALUE Versanet-Termination-Cause Physical-Carrier-Loss 4
+VALUE Versanet-Termination-Cause No-err-correction-at-other-end 5
+VALUE Versanet-Termination-Cause No-resp-to-feature-negotiation 6
+VALUE Versanet-Termination-Cause 1st-modem-async-only-2nd-sync 7
+VALUE Versanet-Termination-Cause No-framing-technique-in-common 8
+VALUE Versanet-Termination-Cause No-protocol-in-common 9
+VALUE Versanet-Termination-Cause Bad-resp-to-feature-negotiation 10
+VALUE Versanet-Termination-Cause No-sync-info-from-remote-modem 11
+VALUE Versanet-Termination-Cause Normal-Hangup-by-Remote-modem 12
+VALUE Versanet-Termination-Cause Retransmission-limit-reached 13
+VALUE Versanet-Termination-Cause Protocol-violation-occurred 14
+VALUE Versanet-Termination-Cause Lost-DTR 15
+VALUE Versanet-Termination-Cause Received-GSTN-cleardown 16
+VALUE Versanet-Termination-Cause Inactivity-timeout 17
+VALUE Versanet-Termination-Cause Speed-not-supported 18
+VALUE Versanet-Termination-Cause Long-space-disconnect 19
+VALUE Versanet-Termination-Cause Key-abort-disconnect 20
+VALUE Versanet-Termination-Cause Clears-previous-disc-reason 21
+VALUE Versanet-Termination-Cause No-connection-established 22
+VALUE Versanet-Termination-Cause Disconnect-after-three-retrains 23
+
+END-VENDOR Versanet
diff --git a/share/dictionary.vqp b/share/dictionary.vqp
new file mode 100644
index 0000000..34650df
--- /dev/null
+++ b/share/dictionary.vqp
@@ -0,0 +1,112 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Cisco's VLAN Query Protocol
+#
+# This dictionary is NOT a RADIUS dictionary, but is used for a
+# similar purpose.
+#
+# The default destination port is 1589.
+#
+# $Id$
+#
+##############################################################################
+
+#
+# We've allocated "fake" attribute 0x2b00 ... 0x2cff for VQP.
+#
+#
+# 0x2b00..0x2bff are for the VQP packet headers.
+# 0x2c00..0x2cff are for the VQP attributes.
+#
+# Note that the VQP protocol specifies 0x0c01..0x0c08 as the
+# real numbers for the VQP attributes. We've added '0x2000'
+# to them to separate them from RADIUS attributes...
+#
+
+#
+# VQP Op codes
+#
+ATTRIBUTE VQP-Packet-Type 0x2b00 integer
+ATTRIBUTE VQP-Error-Code 0x2b01 integer
+ATTRIBUTE VQP-Sequence-Number 0x2b02 integer
+
+#
+# VQP Attributes
+#
+ATTRIBUTE VQP-Client-IP-Address 0x2c01 ipaddr
+ATTRIBUTE VQP-Port-Name 0x2c02 string
+ATTRIBUTE VQP-VLAN-Name 0x2c03 string
+
+# VTP domain
+ATTRIBUTE VQP-Domain-Name 0x2c04 string
+
+# Encapsulates an Ethernet frame...
+ATTRIBUTE VQP-Ethernet-Frame 0x2c05 octets
+ATTRIBUTE VQP-MAC 0x2c06 ether
+ATTRIBUTE VQP-Unknown 0x2c07 octets
+ATTRIBUTE VQP-Cookie 0x2c08 ether
+
+#
+# VQP integer mappings
+#
+
+VALUE VQP-Packet-Type VQP-Join-Request 1
+VALUE VQP-Packet-Type VQP-Join-Response 2
+VALUE VQP-Packet-Type VQP-Reconfirm-Request 3
+VALUE VQP-Packet-Type VQP-Reconfirm-Response 4
+
+VALUE VQP-Error-Code VQP-No-Error 0
+VALUE VQP-Error-Code VQP-Wrong-Version 1
+VALUE VQP-Error-Code VQP-Insufficient-Resources 2
+VALUE VQP-Error-Code VQP-Deny 3
+VALUE VQP-Error-Code VQP-Shutdown 4
+VALUE VQP-Error-Code VQP-Wrong-Mgmt-Domain 5
+
+######################################################################
+#
+# Duplicate names here, for simplicity
+#
+######################################################################
+
+#
+# VMPS Op codes
+#
+ATTRIBUTE VMPS-Packet-Type 0x2b00 integer
+ATTRIBUTE VMPS-Error-Code 0x2b01 integer
+ATTRIBUTE VMPS-Sequence-Number 0x2b02 integer
+
+#
+# VMPS Attributes
+#
+ATTRIBUTE VMPS-Client-IP-Address 0x2c01 ipaddr
+ATTRIBUTE VMPS-Port-Name 0x2c02 string
+ATTRIBUTE VMPS-VLAN-Name 0x2c03 string
+
+# VTP domain
+ATTRIBUTE VMPS-Domain-Name 0x2c04 string
+
+# Encapsulates an Ethernet frame...
+ATTRIBUTE VMPS-Ethernet-Frame 0x2c05 octets
+ATTRIBUTE VMPS-MAC 0x2c06 ether
+ATTRIBUTE VMPS-Unknown 0x2c07 octets
+ATTRIBUTE VMPS-Cookie 0x2c08 ether
+
+#
+# VMPS integer mappings
+#
+
+VALUE VMPS-Packet-Type VMPS-Join-Request 1
+VALUE VMPS-Packet-Type VMPS-Join-Response 2
+VALUE VMPS-Packet-Type VMPS-Reconfirm-Request 3
+VALUE VMPS-Packet-Type VMPS-Reconfirm-Response 4
+
+VALUE VMPS-Error-Code VMPS-No-Error 0
+VALUE VMPS-Error-Code VMPS-Wrong-Version 1
+VALUE VMPS-Error-Code VMPS-Insufficient-Resources 2
+VALUE VMPS-Error-Code VMPS-Deny 3
+VALUE VMPS-Error-Code VMPS-Shutdown 4
+VALUE VMPS-Error-Code VMPS-Wrong-Mgmt-Domain 5
diff --git a/share/dictionary.walabi b/share/dictionary.walabi
new file mode 100644
index 0000000..8f01673
--- /dev/null
+++ b/share/dictionary.walabi
@@ -0,0 +1,31 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Walabi Store & Forward FAX attributes.
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR Walabi 2004
+
+VALUE Acct-Status-Type WB-Login 217
+VALUE Acct-Status-Type WB-Logout 218
+VALUE Acct-Status-Type WB-WRitelog 219
+
+# Store and Forward Fax Attributes:
+BEGIN-VENDOR Walabi
+ATTRIBUTE WB-AUTH-Time-Left 1 integer
+ATTRIBUTE WB-Auth-Accum-BW 2 integer
+ATTRIBUTE WB-Auth-BW-Quota 3 integer
+ATTRIBUTE WB-Auth-BW-Count 4 integer
+ATTRIBUTE WB-Auth-Upload-Limit 5 integer
+ATTRIBUTE WB-Auth-Download-Limit 6 integer
+ATTRIBUTE WB-Auth-Login-Time 7 integer
+ATTRIBUTE WB-Auth-Logout-Time 8 integer
+ATTRIBUTE WB-Auth-Time-Diff 9 integer
+ATTRIBUTE WB-Auth-BW-Usage 10 integer
+END-VENDOR Walabi
diff --git a/share/dictionary.waverider b/share/dictionary.waverider
new file mode 100644
index 0000000..ddd1dfc
--- /dev/null
+++ b/share/dictionary.waverider
@@ -0,0 +1,58 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# http://www.waverider.com/
+# $Id$
+#
+
+VENDOR Waverider 2979
+
+BEGIN-VENDOR Waverider
+ATTRIBUTE Waverider-Grade-Of-Service 1 integer
+ATTRIBUTE Waverider-Priority-Enabled 2 integer
+ATTRIBUTE Waverider-Authentication-Key 3 string
+ATTRIBUTE Waverider-Current-Password 5 string
+ATTRIBUTE Waverider-New-Password 6 string
+ATTRIBUTE Waverider-Radio-Frequency 7 integer
+ATTRIBUTE Waverider-SNMP-Read-Community 8 string
+ATTRIBUTE Waverider-SNMP-Write-Community 9 string
+ATTRIBUTE Waverider-SNMP-Trap-Server 10 string
+ATTRIBUTE Waverider-SNMP-Contact 11 string
+ATTRIBUTE Waverider-SNMP-Location 12 string
+ATTRIBUTE Waverider-SNMP-Name 13 string
+ATTRIBUTE Waverider-Max-Customers 14 integer
+ATTRIBUTE Waverider-Rf-Power 15 integer
+
+VALUE Waverider-Grade-Of-Service be 1
+VALUE Waverider-Grade-Of-Service bronze 2
+VALUE Waverider-Grade-Of-Service silver 3
+VALUE Waverider-Grade-Of-Service gold 4
+
+VALUE Waverider-Priority-Enabled disabled 0
+VALUE Waverider-Priority-Enabled enabled 1
+
+VALUE Waverider-Radio-Frequency auto 1
+VALUE Waverider-Radio-Frequency nomadic 2
+VALUE Waverider-Radio-Frequency f_9050 3
+VALUE Waverider-Radio-Frequency f_9116 4
+VALUE Waverider-Radio-Frequency f_9184 5
+VALUE Waverider-Radio-Frequency f_9250 6
+VALUE Waverider-Radio-Frequency f_9084 7
+VALUE Waverider-Radio-Frequency f_9150 8
+VALUE Waverider-Radio-Frequency f_9216 9
+
+VALUE Waverider-Rf-Power p_15 1
+VALUE Waverider-Rf-Power p_16 2
+VALUE Waverider-Rf-Power p_17 3
+VALUE Waverider-Rf-Power p_18 4
+VALUE Waverider-Rf-Power p_19 5
+VALUE Waverider-Rf-Power p_20 6
+VALUE Waverider-Rf-Power p_21 7
+VALUE Waverider-Rf-Power p_22 8
+VALUE Waverider-Rf-Power p_23 9
+VALUE Waverider-Rf-Power p_24 10
+VALUE Waverider-Rf-Power p_25 11
+VALUE Waverider-Rf-Power p_26 12
+
+END-VENDOR Waverider
diff --git a/share/dictionary.wichorus b/share/dictionary.wichorus
new file mode 100644
index 0000000..9b3f599
--- /dev/null
+++ b/share/dictionary.wichorus
@@ -0,0 +1,26 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Dictionary for WiChorus Inc. VSA's.
+# http://www.wichorus.com/
+#
+# Version: $Id$
+#
+
+VENDOR Wichorus 27030
+
+BEGIN-VENDOR Wichorus
+
+ATTRIBUTE Wichorus-Policy-Name 1 string
+ATTRIBUTE Wichorus-User-Privilege 2 string
+
+#
+# Some versions of the Wichorus equipment use the following attribute.
+# instead of Wichorus-User-Privilege. This is considered to be
+# bad practice.
+#
+
+#ATTRIBUTE Wichorus-Host-IP 2 ipaddr
+
+END-VENDOR Wichorus
diff --git a/share/dictionary.wifialliance b/share/dictionary.wifialliance
new file mode 100644
index 0000000..a895561
--- /dev/null
+++ b/share/dictionary.wifialliance
@@ -0,0 +1,94 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# WiFi-Alliance attributes for Hotspot 2.0
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR WiFi-Alliance 40808
+
+BEGIN-VENDOR WiFi-Alliance
+
+# 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
+# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+# | Server Method | Subscription Remediation Server URL
+# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+#
+# Server Method
+#
+# 0 = OMA DM
+# 1 = Soap XML SPP
+# 2..255 reserved
+#
+ATTRIBUTE HS20-Subscription-Remediation-Needed 1 octets
+ATTRIBUTE HS20-AP-Version 2 byte
+
+# 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 | PPS MO UpdateIdentifier |
+# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+#
+# Version
+#
+# 0 = release 1
+# 1 = release 2
+#
+ATTRIBUTE HS20-Mobile-Device-Version 3 octets
+
+# 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 | Re-auth Delay | URL
+# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+#
+# Code
+#
+# 0 = User's subscription does not allow or no longer allows access at this BSS
+# 1 = User's subscription does not allow or no longer allows access at this ESS
+#
+#
+# Re-Auth delay = delay in seconds that a mobile device waits before attempting
+# reassociation.
+# 0 == delay is decided by the mobile device.
+#
+# URL = UTF-8 encoded URL.
+# Which provides a webpage explaining why the mobile device was
+# not authorized (or is no longer authorized)
+#
+ATTRIBUTE HS20-Deauthentication-Request 4 octets
+
+# 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
+# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+# | SWT | Session Information URL
+# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+#
+# SWT = Session Warning Time is the number of minutes of advance
+# notice an AP shall provide to the mobile device before terminating
+# its session. When SWT is set to the special value of 255, the AP
+# (802.1X authenticator) chooses the session warning time value.
+#
+# Session Information URL field: URL which is transmitted to a mobile
+# device in a BSS Transition Management Request frame SWT minutes
+# before the mobile device’s session is terminated. The URL provides
+# the location of a webpage with information for the user on how to
+# extend the session.
+#
+ATTRIBUTE HS20-Session-Information-URL 5 octets
+
+# Values are:
+#
+# 5A-03-BA-00-00 OpenRoaming for All Identities, settlement-free, no personal data requested, baseline QoS
+# 5A-03-BA-08-00 "OpenRoaming for Educational or Research Identities, settlement-free, no personal data requested, baseline QoS"
+ATTRIBUTE HS20-Roaming-Consortium 6 octets
+
+
+
+END-VENDOR WiFi-Alliance
diff --git a/share/dictionary.wimax b/share/dictionary.wimax
new file mode 100644
index 0000000..4d220ea
--- /dev/null
+++ b/share/dictionary.wimax
@@ -0,0 +1,619 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# WiMAX Forum
+#
+# Updated from NWG_R1_V1.2.1-Stage-3.pdf
+#
+# NWG_R1_V1.2-Stage-3.pdf
+# RADIUS discussion is on pp. 432-498
+# WiMAX VSA's are on p. 450 and following.
+#
+# DHCP && MIP keys are on p.48 and following.
+#
+# WiMAX VSA's have a non-standard format:
+#
+# type 1 octet
+# length 1 octet
+# continuation 1 octet 0bcrrrrrrr
+# value 1+ octets
+#
+# If the high bit of the "continuation" field is set, then
+# the next attribute of the same WiMAX type should have it's
+# value concatenated to this one.
+#
+# The C bit MUST be zero for all small types. e.g. integer,
+# ipaddr, ipv6addr, etc. It MAY be set for "string" and "octet"
+# types. The maximum attribute length for "string" and "octet"
+# types is still 253 bytes, even with continuations. The WiMAX
+# specifications do not specify a maximum length, so we have chosen
+# to keep the traditional RADIUS maximum length here.
+#
+# The C bit MAY be 1 for TLV types. There is no restriction on
+# TLV length other than maximum packet size (a bit less than 4K).
+#
+# The rest of the bits in the "continuation" octet are reserved,
+# and MUST be zero.
+#
+# Each WiMAX VSA is packed into one Vendor-Specific attribute
+# with Vendor-Id of WiMAX. Multiple WiMAX sub-TLV's ARE packed
+# into one VSA with an encapsulating TLV.
+#
+# The WiMAX forum adds the following (non-standard) data types:
+#
+# byte - one-octet unsigned integer
+# short - two-octet unsigned integer in network byte order
+# signed - 4-octet signed integer in network byte order.
+# combo-ip - if length 4, is the same as the "ipaddr" type.
+# if length 16, is the same as "ipv6addr" type.
+# tlv - encapsulated sub-attributes
+# i.e. Vendor-Specific -> WiMAX TLV -> WiMAX sub-tlv.
+#
+##############################################################################
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR WiMAX 24757 format=1,1,c
+
+BEGIN-VENDOR WiMAX
+
+ATTRIBUTE WiMAX-Capability 1 tlv
+ATTRIBUTE WiMAX-Release 1.1 string
+ATTRIBUTE WiMAX-Accounting-Capabilities 1.2 byte
+ATTRIBUTE WiMAX-Hotlining-Capabilities 1.3 byte
+ATTRIBUTE WiMAX-Idle-Mode-Notification-Cap 1.4 byte
+ATTRIBUTE WiMAX-ASN-IP-Service-Capabilities 1.5 byte
+ATTRIBUTE WiMAX-VCSN-IP-Service-Capabilities 1.6 byte
+ATTRIBUTE WiMAX-Authorized-IP-Services 1.7 byte
+ATTRIBUTE WiMAX-Authorized-Anchor-Locations 1.8 byte
+ATTRIBUTE WiMAX-ASN-Ethernet-Service-Capabilities 1.9 byte
+ATTRIBUTE WiMAX-VCSN-Ethernet-Service-Capabilities 1.10 byte
+ATTRIBUTE WiMAX-Authorized-Ethernet-Services 1.11 byte
+
+# This is really a bitmap
+VALUE WiMAX-Accounting-Capabilities No-Accounting 0
+VALUE WiMAX-Accounting-Capabilities IP-Session-Based 1
+VALUE WiMAX-Accounting-Capabilities Flow-Based 2
+
+# This is really a bitmap
+VALUE WiMAX-Hotlining-Capabilities Not-Supported 0
+VALUE WiMAX-Hotlining-Capabilities Hotline-Profile-Id 1
+VALUE WiMAX-Hotlining-Capabilities NAS-Filter-Rule 2
+VALUE WiMAX-Hotlining-Capabilities HTTP-Redirection 4
+VALUE WiMAX-Hotlining-Capabilities IP-Redirection 8
+
+VALUE WiMAX-Idle-Mode-Notification-Cap Not-Supported 0
+VALUE WiMAX-Idle-Mode-Notification-Cap Supported 1
+
+VALUE WiMAX-ASN-IP-Service-Capabilities DHCP-Relay 1
+VALUE WiMAX-ASN-IP-Service-Capabilities DHCP-Proxy 2
+VALUE WiMAX-ASN-IP-Service-Capabilities FA 4
+VALUE WiMAX-ASN-IP-Service-Capabilities PMIP-Client 8
+
+VALUE WiMAX-ASN-Ethernet-Service-Capabilities eAFF-IPv4-Transport 1
+VALUE WiMAX-ASN-Ethernet-Service-Capabilities eAFF-IPv6-Transport 2
+VALUE WiMAX-ASN-Ethernet-Service-Capabilities eFA 4
+
+VALUE WiMAX-VCSN-Ethernet-Service-Capabilities eCFF-IPv4-Transport 1
+VALUE WiMAX-VCSN-Ethernet-Service-Capabilities eCFF-IPv6-Transport 2
+VALUE WiMAX-VCSN-Ethernet-Service-Capabilities eHAv4 4
+VALUE WiMAX-VCSN-Ethernet-Service-Capabilities eHAv6 8
+
+ATTRIBUTE WiMAX-Device-Authentication-Indicator 2 byte
+ATTRIBUTE WiMAX-GMT-Timezone-offset 3 signed
+ATTRIBUTE WiMAX-AAA-Session-Id 4 octets
+
+# 32 octets in length
+ATTRIBUTE WiMAX-MSK 5 octets encrypt=2
+ATTRIBUTE WiMAX-hHA-IP-MIP4 6 ipaddr
+ATTRIBUTE WiMAX-hHA-IP-MIP6 7 ipv6addr
+ATTRIBUTE WiMAX-DHCPv4-Server 8 combo-ip
+ATTRIBUTE WiMAX-DHCPv6-Server 9 combo-ip
+
+# MN-HA-CMIP4 = H(MIP-RK, "CMIP4 MN HA" | HA-IPv4 | MN-NAI), or
+# MN-HA-PMIP4 = H(MIP-RK, "PMIP4 MN HA" | HA-IPv4 | MN-NAI)
+ATTRIBUTE WiMAX-MN-hHA-MIP4-Key 10 octets encrypt=2
+
+# MN-HA-CMIP4-SPI == MIP-SPI, or
+# MN-HA-PIMP4-SPI == MIP-SPI + 1
+ATTRIBUTE WiMAX-MN-hHA-MIP4-SPI 11 integer
+
+# MN-HA-CMIP6 = H(MIP-RK, "CMIP6 MN HA" | HA-IPv6 | MN-NAI)
+ATTRIBUTE WiMAX-MN-hHA-MIP6-Key 12 octets encrypt=2
+
+# MN-HA-CMIP6-SPI == MIP-SPI + 2
+ATTRIBUTE WiMAX-MN-hHA-MIP6-SPI 13 integer
+
+# FA-RK = H(MIP-RK, "FA-RK")
+ATTRIBUTE WiMAX-FA-RK-Key 14 octets encrypt=2
+
+# 160 bit random number
+ATTRIBUTE WiMAX-HA-RK-Key 15 octets encrypt=2
+# SPI-CMIP4
+ATTRIBUTE WiMAX-HA-RK-SPI 16 integer
+
+ATTRIBUTE WiMAX-HA-RK-Lifetime 17 integer
+
+# The same as MN-HA-CMIP4, etc. But in different packets.
+ATTRIBUTE WiMAX-RRQ-HA-IP 18 combo-ip
+ATTRIBUTE WiMAX-RRQ-MN-HA-Key 19 octets encrypt=2
+ATTRIBUTE WiMAX-RRQ-MN-HA-SPI 20 integer
+
+ATTRIBUTE WiMAX-Session-Continue 21 integer
+ATTRIBUTE WiMAX-Beginning-Of-Session 22 integer
+ATTRIBUTE WiMAX-IP-Technology 23 integer
+
+VALUE WiMAX-IP-Technology Reserved-0 0
+VALUE WiMAX-IP-Technology Reserved-1 1
+VALUE WiMAX-IP-Technology PMIP4 2
+VALUE WiMAX-IP-Technology CMIP4 3
+VALUE WiMAX-IP-Technology CMIP6 4
+VALUE WiMAX-IP-Technology Ethernet-CS 5
+
+ATTRIBUTE WiMAX-Hotline-Indicator 24 string
+ATTRIBUTE WiMAX-Prepaid-Indicator 25 byte
+ATTRIBUTE WiMAX-PDFID 26 short
+ATTRIBUTE WiMAX-SDFID 27 short
+
+ATTRIBUTE WiMAX-Packet-Flow-Descriptor 28 tlv
+ATTRIBUTE WiMAX-Packet-Data-Flow-Id 28.1 short
+ATTRIBUTE WiMAX-Service-Data-Flow-Id 28.2 short
+ATTRIBUTE WiMAX-Service-Profile-Id 28.3 integer
+ATTRIBUTE WiMAX-Direction 28.4 byte
+
+VALUE WiMAX-Direction Reserved-0 0
+VALUE WiMAX-Direction Uplink 1
+VALUE WiMAX-Direction Downlink 2
+VALUE WiMAX-Direction Bi-Directional 3
+
+ATTRIBUTE WiMAX-Activation-Trigger 28.5 byte # bitmap
+ATTRIBUTE WiMAX-Transport-Type 28.6 byte
+
+VALUE WiMAX-Transport-Type Reserved-0 0
+VALUE WiMAX-Transport-Type IPv4-CS 1
+VALUE WiMAX-Transport-Type IPv6-CS 2
+VALUE WiMAX-Transport-Type Ethernet 3
+
+ATTRIBUTE WiMAX-Uplink-QOS-Id 28.7 byte
+ATTRIBUTE WiMAX-Downlink-QOS-Id 28.8 byte
+ATTRIBUTE WiMAX-Uplink-Classifier 28.9 string
+ATTRIBUTE WiMAX-Downlink-Classifier 28.10 string
+ATTRIBUTE WiMAX-Classifier 28.11 tlv
+ATTRIBUTE WiMAX-ClassifierID 28.11.1 integer
+ATTRIBUTE WiMAX-Classifer-Priority 28.11.2 integer
+ATTRIBUTE WiMAX-Classifer-Protocol 28.11.3 integer
+ATTRIBUTE WiMAX-Classifer-Direction 28.11.4 byte
+
+VALUE WiMAX-Classifer-Direction Reserved-0 0
+VALUE WiMAX-Classifer-Direction IN 1
+VALUE WiMAX-Classifer-Direction OUT 2
+VALUE WiMAX-Classifer-Direction Bi-Directional 3
+VALUE WiMAX-Classifer-Direction FF 4
+
+ATTRIBUTE WiMAX-Source-Specification 28.11.5 tlv
+
+ATTRIBUTE WiMAX-Source-IPAddress 28.11.5.1 ipaddr
+ATTRIBUTE WiMAX-Source-IPAddressRange 28.11.5.2 octets # 2 of ipv4addr OR ipv6addr
+ATTRIBUTE WiMAX-Source-IPAddressMask 28.11.5.3 combo-ip
+ATTRIBUTE WiMAX-Source-Port 28.11.5.4 short
+ATTRIBUTE WiMAX-Source-Port-Range 28.11.5.5 integer # really 2 short
+ATTRIBUTE WiMAX-Source-Inverted 28.11.5.6 byte
+ATTRIBUTE WiMAX-Source-Assigned 28.11.5.7 byte
+
+ATTRIBUTE WiMAX-Destination-Specification 28.11.6 tlv
+
+ATTRIBUTE WiMAX-Destination-IPAddress 28.11.6.1 ipaddr
+ATTRIBUTE WiMAX-Destination-IPAddressRange 28.11.6.2 octets # 2 of ipv4addr OR ipv6addr
+ATTRIBUTE WiMAX-Destination-IPAddressMask 28.11.6.3 combo-ip
+ATTRIBUTE WiMAX-Destination-Port 28.11.6.4 short
+ATTRIBUTE WiMAX-Destination-Port-Range 28.11.6.5 integer # really 2 short
+ATTRIBUTE WiMAX-Destination-Inverted 28.11.6.6 byte
+ATTRIBUTE WiMAX-Destination-Assigned 28.11.6.7 byte
+
+ATTRIBUTE WiMAX-IP-TOS/DSCP-Range-and-Mask 28.11.7 octets
+ATTRIBUTE WiMAX-VLAN-ID 28.11.8 integer
+ATTRIBUTE WiMAX-802.1p 28.11.9 octets
+
+ATTRIBUTE WiMAX-QoS-Descriptor 29 tlv
+ATTRIBUTE WiMAX-QoS-Id 29.1 byte
+ATTRIBUTE WiMAX-Global-Service-Class-Name 29.2 string # 6 octets
+ATTRIBUTE WiMAX-Service-Class-Name 29.3 string
+ATTRIBUTE WiMAX-Schedule-Type 29.4 byte
+ATTRIBUTE WiMAX-Traffic-Priority 29.5 byte
+ATTRIBUTE WiMAX-Maximum-Sustained-Traffic-Rate 29.6 integer
+ATTRIBUTE WiMAX-Minimum-Reserved-Traffic-Rate 29.7 integer
+ATTRIBUTE WiMAX-Maximum-Traffic-Burst 29.8 integer
+ATTRIBUTE WiMAX-Tolerated-Jitter 29.9 integer
+ATTRIBUTE WiMAX-Maximum-Latency 29.10 integer
+ATTRIBUTE WiMAX-Reduced-Resources-Code 29.11 byte
+ATTRIBUTE WiMAX-Media-Flow-Type 29.12 byte
+ATTRIBUTE WiMAX-Unsolicited-Grant-Interval 29.13 short
+ATTRIBUTE WiMAX-SDU-Size 29.14 short
+ATTRIBUTE WiMAX-Unsolicited-Polling-Interval 29.15 short
+ATTRIBUTE WiMAX-Media-Flow-Description-SDP 29.16 string
+ATTRIBUTE WiMAX-R3-IF-Descriptor 29.17 tlv
+
+ATTRIBUTE WiMAX-R3-IF-Name 29.17.1 string
+ATTRIBUTE WiMAX-R3-IF-ID 29.17.2 octets
+# ATTRIBUTE WiMAX-PDFID 29.17.3 short
+ATTRIBUTE WiMAX-IPv4-addr 29.17.4 ipaddr
+ATTRIBUTE WiMAX-IPv4-Netmask 29.17.5 ipaddr
+ATTRIBUTE WiMAX-DGW-IPv4-addr 29.17.6 ipaddr
+
+ATTRIBUTE WiMAX-DHCP-Option 29.18 tlv
+
+ATTRIBUTE WiMAX-Ref-R3-IF-Name 29.18.1 string
+ATTRIBUTE WiMAX-DHCP-Option-Container 29.18.2 string
+
+VALUE WiMAX-Schedule-Type Best-Effort 2
+VALUE WiMAX-Schedule-Type nrtPS 3
+VALUE WiMAX-Schedule-Type rtPS 4
+VALUE WiMAX-Schedule-Type Extended-rtPS 5
+VALUE WiMAX-Schedule-Type UGS 6
+
+VALUE WiMAX-Media-Flow-Type VoIP 1
+VALUE WiMAX-Media-Flow-Type Robust-Browser 2
+VALUE WiMAX-Media-Flow-Type Secure-Browser-VPN 3
+VALUE WiMAX-Media-Flow-Type Streaming-Video 4
+VALUE WiMAX-Media-Flow-Type Streaming-Live-TV 5
+VALUE WiMAX-Media-Flow-Type Music-Photo-Download 6
+VALUE WiMAX-Media-Flow-Type Multi-Player-Gaming 7
+VALUE WiMAX-Media-Flow-Type Location-Based-Services 8
+VALUE WiMAX-Media-Flow-Type Text-Audio-Books 9
+VALUE WiMAX-Media-Flow-Type Video-Conversation 10
+VALUE WiMAX-Media-Flow-Type Message 11
+VALUE WiMAX-Media-Flow-Type Control 12
+VALUE WiMAX-Media-Flow-Type Data 13
+
+ATTRIBUTE WiMAX-Uplink-Granted-QoS 30 string
+ATTRIBUTE WiMAX-Control-Packets-In 31 integer
+ATTRIBUTE WiMAX-Control-Octets-In 32 integer
+ATTRIBUTE WiMAX-Control-Packets-Out 33 integer
+ATTRIBUTE WiMAX-Control-Octets-Out 34 integer
+ATTRIBUTE WiMAX-PPAC 35 tlv
+ATTRIBUTE WiMAX-Available-In-Client 35.1 integer
+
+# Really a bitmap
+VALUE WiMAX-Available-In-Client Volume-Metering 1
+VALUE WiMAX-Available-In-Client Duration-Metering 2
+VALUE WiMAX-Available-In-Client Resource-Metering 4
+VALUE WiMAX-Available-In-Client Pools 8
+VALUE WiMAX-Available-In-Client Rating-Groups 0x10
+VALUE WiMAX-Available-In-Client Multi-Services 0x20
+VALUE WiMAX-Available-In-Client Tariff-Switch 0x40
+
+ATTRIBUTE WiMAX-Session-Termination-Capability 36 integer
+
+# Really a bitmap
+VALUE WiMAX-Session-Termination-Capability Dynamic-Authorization 1
+
+ATTRIBUTE WiMAX-PPAQ 37 tlv
+ATTRIBUTE WiMAX-PPAQ-Quota-Identifier 37.1 octets
+ATTRIBUTE WiMAX-Volume-Quota 37.2 integer #kb
+ATTRIBUTE WiMAX-Volume-Threshold 37.3 integer #kb
+ATTRIBUTE WiMAX-Duration-Quota 37.4 integer #s
+ATTRIBUTE WiMAX-Duration-Threshold 37.5 integer #s
+ATTRIBUTE WiMAX-Resource-Quota 37.6 integer
+ATTRIBUTE WiMAX-Resource-Threshold 37.7 integer
+ATTRIBUTE WiMAX-Update-Reason 37.8 integer
+ATTRIBUTE WiMAX-Prepaid-Server 37.9 combo-ip
+ATTRIBUTE WiMAX-Service-Id 37.10 string
+ATTRIBUTE WiMAX-Rating-Group-Id 37.11 integer
+ATTRIBUTE WiMAX-Termination-Action 37.12 byte
+ATTRIBUTE WiMAX-Pool-Id 37.13 integer
+ATTRIBUTE WiMAX-Pool-Multiplier 37.14 integer
+ATTRIBUTE WiMAX-Requested-Action 37.15 byte
+ATTRIBUTE WiMAX-Check-Balance-Result 37.16 byte
+
+#
+# 4 octets - integer representing 1/10's of lowest currency (e.g. cents)
+# 4 octets - currency code as in ISO-4217
+# 1+ - UTF8 string containing text like "cost is $1 per minute"
+#
+ATTRIBUTE WiMAX-Cost-Information-AVP 37.17 octets
+
+VALUE WiMAX-Update-Reason Pre-Initialization 1
+VALUE WiMAX-Update-Reason Initial-Request 2
+VALUE WiMAX-Update-Reason Threshold-Reached 3
+VALUE WiMAX-Update-Reason Quota-Reached 4
+VALUE WiMAX-Update-Reason TITSU-Approaching 5
+VALUE WiMAX-Update-Reason Remote-Forced-Disconnect 6
+VALUE WiMAX-Update-Reason Client-Service-Termination 7
+VALUE WiMAX-Update-Reason Access-Service-Terminated 8
+VALUE WiMAX-Update-Reason Service-Not-Established 9
+VALUE WiMAX-Update-Reason One-Time-Charging 10
+
+VALUE WiMAX-Termination-Action Terminate 1
+VALUE WiMAX-Termination-Action Request-More-Quota 2
+VALUE WiMAX-Termination-Action Redirect-Or-Filter 3
+
+VALUE WiMAX-Requested-Action Balance-Check 1
+VALUE WiMAX-Requested-Action Price-Enquiry 2
+
+ATTRIBUTE WiMAX-Prepaid-Tariff-Switching 38 tlv
+ATTRIBUTE WiMAX-Prepaid-Quota-Identifier 38.1 string
+ATTRIBUTE WiMAX-Volume-Used-After 38.2 integer #1k
+ATTRIBUTE WiMAX-Tariff-Switch-Interval 38.3 integer #s
+ATTRIBUTE WiMAX-Time-Interval-After 38.4 integer #s
+
+ATTRIBUTE WiMAX-Active-Time-Duration 39 integer
+ATTRIBUTE WiMAX-DHCP-RK 40 octets encrypt=2
+ATTRIBUTE WiMAX-DHCP-RK-Key-Id 41 integer
+ATTRIBUTE WiMAX-DHCP-RK-Lifetime 42 integer
+ATTRIBUTE WiMAX-DHCP-Msg-Server-IP 43 ipaddr
+ATTRIBUTE WiMAX-Idle-Mode-Transition 44 byte
+ATTRIBUTE WiMAX-NAP-Id 45 octets
+
+# 3 octets of NAP Id
+# 3 octets of base-station Id
+ATTRIBUTE WiMAX-BS-Id 46 octets
+ATTRIBUTE WiMAX-Location 47 octets
+
+# Number of times Acct-Input-Packets rolled over 2^32.
+ATTRIBUTE WiMAX-Acct-Input-Packets-Gigaword 48 integer
+ATTRIBUTE WiMAX-Acct-Output-Packets-Gigaword 49 integer
+
+# Formatted as per IP Filter rule specification.
+ATTRIBUTE WiMAX-Uplink-Flow-Description 50 string
+
+ATTRIBUTE WiMAX-Blu-Coa-IPv6 51 ipv6addr
+ATTRIBUTE WiMAX-DNS-Server 52 combo-ip
+ATTRIBUTE WiMAX-Hotline-Profile-Id 53 string
+
+# Formatted as per IP Filter rule specification.
+ATTRIBUTE WiMAX-HTTP-Redirection-Rule 54 string
+
+# Formatted as per IP Filter rule specification.
+ATTRIBUTE WiMAX-IP-Redirection-Rule 55 string
+ATTRIBUTE WiMAX-Hotline-Session-Timer 56 integer
+
+# 3 octets
+ATTRIBUTE WiMAX-NSP-Id 57 octets
+ATTRIBUTE WiMAX-HA-RK-Key-Requested 58 integer
+
+VALUE WiMAX-HA-RK-Key-Requested No 0
+VALUE WiMAX-HA-RK-Key-Requested Yes 1
+
+ATTRIBUTE WiMAX-Count-Type 59 byte
+ATTRIBUTE WiMAX-DM-Action-Code 60 integer
+
+VALUE WiMAX-DM-Action-Code Deregister-MS 0
+VALUE WiMAX-DM-Action-Code Suspend-MS-Traffic 1
+VALUE WiMAX-DM-Action-Code Suspend-User-Traffic 2
+VALUE WiMAX-DM-Action-Code Resume-Traffic 3
+VALUE WiMAX-DM-Action-Code MS-Terminate 4
+VALUE WiMAX-DM-Action-Code MS-Idle 5
+VALUE WiMAX-DM-Action-Code MS-Completed-IPv6-Handover 6
+VALUE WiMAX-DM-Action-Code BS-Sends-RES-Cmd 0xffff
+
+# FA-RK-SPI = SPI-CMIP4 = MIP-SPI
+ATTRIBUTE WiMAX-FA-RK-SPI 61 integer
+
+# Formatted as per IP Filter rule specification.
+ATTRIBUTE WiMAX-Downlink-Flow-Description 62 string
+
+# Same as QoS-Descriptor... dang.
+ATTRIBUTE WiMAX-Downlink-Granted-QoS 63 tlv
+
+# More MIP keys, calculated as above... but in different packets.
+# Why, oh why?
+ATTRIBUTE WiMAX-vHA-IP-MIP4 64 ipaddr
+ATTRIBUTE WiMAX-vHA-IP-MIP6 65 ipv6addr
+ATTRIBUTE WiMAX-vHA-MIP4-Key 66 octets encrypt=2
+ATTRIBUTE WiMAX-vHA-RK-Key 67 octets encrypt=2
+ATTRIBUTE WiMAX-vHA-RK-SPI 68 integer
+ATTRIBUTE WiMAX-vHA-RK-Lifetime 69 integer
+
+ATTRIBUTE WiMAX-MN-vHA-MIP6-Key 70 octets encrypt=2
+ATTRIBUTE WiMAX-MN-vHA-MIP4-SPI 71 integer
+ATTRIBUTE WiMAX-MN-vHA-MIP6-SPI 72 integer
+ATTRIBUTE WiMAX-vDHCPv4-Server 73 ipaddr
+ATTRIBUTE WiMAX-vDHCPv6-Server 74 ipv6addr
+ATTRIBUTE WiMAX-vDHCP-RK 75 octets encrypt=2
+ATTRIBUTE WiMAX-vDHCP-RK-Key-ID 76 integer
+ATTRIBUTE WiMAX-vDHCP-RK-Lifetime 77 integer
+
+ATTRIBUTE WiMAX-PMIP-Authenticated-Network-Identity 78 string
+ATTRIBUTE WiMAX-Visited-Framed-IP-Address 79 ipaddr
+ATTRIBUTE WiMAX-Visited-Framed-IPv6-Prefix 80 ipv6prefix
+ATTRIBUTE WiMAX-Visited-Framed-Interface-Id 81 ifid
+ATTRIBUTE WiMAX-MIP-Authorization-Status 82 integer
+
+VALUE WiMAX-MIP-Authorization-Status False 0
+VALUE WiMAX-MIP-Authorization-Status True 1
+
+#
+# FIXME: See WiMAX-Src-Dst-Specification for TLVs
+#
+ATTRIBUTE WiMAX-Flow-Descriptor-v2 83 tlv
+
+ATTRIBUTE WiMAX-Packet-Flow-Descriptor-v2 84 tlv
+ATTRIBUTE WiMAX-PFDv2-Packet-Data-Flow-Id 84.1 short
+ATTRIBUTE WiMAX-PFDv2-Service-Data-Flow-Id 84.2 short
+ATTRIBUTE WiMAX-PFDv2-Service-Profile-Id 84.3 integer
+ATTRIBUTE WiMAX-PFDv2-Direction 84.4 byte
+ATTRIBUTE WiMAX-PFDv2-Activation-Trigger 84.5 byte
+ATTRIBUTE WiMAX-PFDv2-Transport-Type 84.6 byte
+ATTRIBUTE WiMAX-PFDv2-Uplink-QoS-Id 84.7 byte
+ATTRIBUTE WiMAX-PFDv2-Downlink-QoS-Id 84.8 byte
+
+#
+# Classifiers
+#
+ATTRIBUTE WiMAX-PFDv2-Classifier 84.9 tlv
+ATTRIBUTE WiMAX-PFDv2-Classifier-Id 84.9.1 byte
+ATTRIBUTE WiMAX-PFDv2-Classifier-Priority 84.9.2 byte
+ATTRIBUTE WiMAX-PFDv2-Classifier-Protocol 84.9.3 byte
+ATTRIBUTE WiMAX-PFDv2-Classifier-Direction 84.9.4 byte
+
+ATTRIBUTE WiMAX-PFDv2-Classifier-Source-Spec 84.9.5 tlv
+ATTRIBUTE WiMAX-PFDv2-Src-IP-Address 84.9.5.1 combo-ip
+ATTRIBUTE WiMAX-PFDv2-Src-IP-Address-Range 84.9.5.2 octets # 2 of ipv4addr OR ipv6addr
+ATTRIBUTE WiMAX-PFDv2-Src-IP-Address-Mask 84.9.5.3 combo-ip
+ATTRIBUTE WiMAX-PFDv2-Src-Port 84.9.5.4 short
+ATTRIBUTE WiMAX-PFDv2-Src-Port-Range 84.9.5.5 integer # really 2 short
+ATTRIBUTE WiMAX-PFDv2-Src-Inverted 84.9.5.6 byte
+ATTRIBUTE WiMAX-PFDv2-Src-Assigned 84.9.5.7 byte
+
+VALUE WiMAX-PFDv2-Src-Assigned Src-Assigned 1
+VALUE WiMAX-PFDv2-Src-Assigned Dst-Assigned 2
+VALUE WiMAX-PFDv2-Src-Assigned Src-Dst-Assigned 3
+
+ATTRIBUTE WiMAX-PFDv2-Src-MAC-Address 84.9.5.8 ether
+ATTRIBUTE WiMAX-PFDv2-Src-MAC-Mask 84.9.5.9 ether
+
+ATTRIBUTE WiMAX-PFDv2-Classifier-Dest-Spec 84.9.6 tlv
+ATTRIBUTE WiMAX-PFDv2-Classifier-IP-ToS-DSCP 84.9.7 byte
+ATTRIBUTE WiMAX-PFDv2-Classifier-Action 84.9.8 byte
+
+ATTRIBUTE WiMAX-PFDv2-Classifier-Eth-Option 84.9.9 tlv
+
+ATTRIBUTE WiMAX-PFDv2-Eth-Proto-Type 84.9.9.1 tlv
+ATTRIBUTE WiMAX-PFDv2-Eth-Proto-Type-Ethertype 84.9.9.1.1 short
+ATTRIBUTE WiMAX-PFDv2-Eth-Proto-Type-DSAP 84.9.9.1.2 byte
+
+ATTRIBUTE WiMAX-PFDv2-Eth-VLAN-Id 84.9.9.2 tlv
+ATTRIBUTE WiMAX-PFDv2-Eth-VLAN-Id-S-VID 84.9.9.2.1 integer
+ATTRIBUTE WiMAX-PFDv2-Eth-VLAN-Id-C-VID 84.9.9.2.2 integer
+
+ATTRIBUTE WiMAX-PFDv2-Eth-Priority-Range 84.9.9.3 tlv
+ATTRIBUTE WiMAX-PFDv2-Eth-Priority-Range-Low 84.9.9.3.1 byte
+ATTRIBUTE WiMAX-PFDv2-Eth-Priority-Range-High 84.9.9.3.2 byte
+
+ATTRIBUTE WiMAX-XXX 84.9.9.4 byte
+
+ATTRIBUTE WiMAX-PFDv2-Paging-Preference 84.9.10 byte
+ATTRIBUTE WiMAX-PFDv2-VLAN-Tag-Rule-Id 84.9.11 short
+
+VALUE WiMAX-PFDv2-Direction Uplink 1
+VALUE WiMAX-PFDv2-Direction Downlink 2
+VALUE WiMAX-PFDv2-Direction Bi-Directional 3
+
+VALUE WiMAX-PFDv2-Activation-Trigger Provisioned 1
+VALUE WiMAX-PFDv2-Activation-Trigger Admit 2
+VALUE WiMAX-PFDv2-Activation-Trigger Activate 4
+VALUE WiMAX-PFDv2-Activation-Trigger Dynamic 8
+
+VALUE WiMAX-PFDv2-Transport-Type IPv4-CS 1
+VALUE WiMAX-PFDv2-Transport-Type IPv6-CS 2
+VALUE WiMAX-PFDv2-Transport-Type Ethernet 3
+
+ATTRIBUTE WiMAX-VLAN-Tag-Processing-Descriptor 85 tlv
+ATTRIBUTE WiMAX-VLAN-Tag-Rule-Id 85.1 short
+ATTRIBUTE WiMAX-VLAN-Tag-C-VLAN-Priority 85.2 byte
+ATTRIBUTE WiMAX-VLAN-Tag-VLAN-Id-Assignment 85.3 short
+ATTRIBUTE WiMAX-VLAN-Tag-C-VLAN-Id 85.4 short
+ATTRIBUTE WiMAX-VLAN-Tag-S-VLAN-Id 85.5 short
+ATTRIBUTE WiMAX-VLAN-Tag-C-S-VLAN-Id-Mapping 85.6 integer
+ATTRIBUTE WiMAX-VLAN-Tag-Local-Config-Info 85.7 octets
+
+ATTRIBUTE WiMAX-hDHCP-Server-Parameters 86 tlv
+ATTRIBUTE WiMAX-hDHCP-DHCPv4-Address 86.1 ipaddr
+ATTRIBUTE WiMAX-hDHCP-DHCPv6-Address 86.2 ipv6addr
+ATTRIBUTE WiMAX-hDHCP-DHCP-RK 86.3 string encrypt=2
+ATTRIBUTE WiMAX-hDHCP-DHCP-RK-Key-Id 86.4 integer
+ATTRIBUTE WiMAX-hDHCP-DHCP-RK-Lifetime 86.5 integer
+
+ATTRIBUTE WiMAX-vDHCP-Server-Parameters 87 tlv
+ATTRIBUTE WiMAX-vDHCP-DHCPv4-Address 87.1 ipaddr
+ATTRIBUTE WiMAX-vDHCP-DHCPv6-Address 87.2 ipv6addr
+ATTRIBUTE WiMAX-vDHCP-DHCP-RK 87.3 string encrypt=2
+ATTRIBUTE WiMAX-vDHCP-DHCP-RK-Key-Id 87.4 integer
+ATTRIBUTE WiMAX-vDHCP-DHCP-RK-Lifetime 87.5 integer
+
+ATTRIBUTE WiMAX-BS-Location 88 octets
+ATTRIBUTE WiMAX-Visited-IPv4-HoA-PMIP6 89 byte
+
+VALUE WiMAX-Visited-IPv4-HoA-PMIP6 Fixed 1
+VALUE WiMAX-Visited-IPv4-HoA-PMIP6 Nomadic 2
+VALUE WiMAX-Visited-IPv4-HoA-PMIP6 Mobile 3
+
+ATTRIBUTE WiMAX-MS-Authenticated 90 byte
+
+VALUE WiMAX-MS-Authenticated No 0
+VALUE WiMAX-MS-Authenticated Yes 1
+
+ATTRIBUTE WiMAX-PMIP6-Service-Info 126 short
+
+ATTRIBUTE WiMAX-hLMA-IPv6-PMIP6 127 ipv6addr
+ATTRIBUTE WiMAX-hLMA-IPv4-PMIP6 128 ipaddr
+ATTRIBUTE WiMAX-vLMA-IPv6-PMIP6 129 ipv6addr
+ATTRIBUTE WiMAX-vLMA-IPv4-PMIP6 130 ipaddr
+ATTRIBUTE WiMAX-PMIP6-RK-Key 131 octets encrypt=2
+ATTRIBUTE WiMAX-PMIP6-RK-SPI 132 integer
+ATTRIBUTE WiMAX-Home-HNP-PMIP6 133 ipv6prefix
+ATTRIBUTE WiMAX-Home-Interface-Id-PMIP6 134 ifid
+ATTRIBUTE WiMAX-Home-IPv4-HoA-PMIP6 135 ipaddr
+ATTRIBUTE WiMAX-Visited-HNP-PMIP6 136 ipv6prefix
+ATTRIBUTE WiMAX-Visited-Interface-Id-PMIP6 137 ifid
+ATTRIBUTE WiMAX-Visited-IPv4-HoA-PMIP6-2 138 ipaddr
+
+ATTRIBUTE WiMAX-AE-Command-Code 143 byte
+
+VALUE WiMAX-AE-Command-Code Authentication-Information-Request 1
+VALUE WiMAX-AE-Command-Code Authentication-Information-Answer 2
+VALUE WiMAX-AE-Command-Code Update-Location-Request 3
+VALUE WiMAX-AE-Command-Code Update-Location-Answer 4
+VALUE WiMAX-AE-Command-Code Cancel-Location-Request 5
+VALUE WiMAX-AE-Command-Code Cancel-Location-Answer 6
+VALUE WiMAX-AE-Command-Code Purge-UE-Request 7
+VALUE WiMAX-AE-Command-Code Purge-UE-Answer 8
+VALUE WiMAX-AE-Command-Code Insert-Subscriber-Data-Request 9
+VALUE WiMAX-AE-Command-Code Insert-Subscriber-Data-Answer 10
+VALUE WiMAX-AE-Command-Code Delete-Subscriber-Data-Request 11
+VALUE WiMAX-AE-Command-Code Delete-Subscriber-Data-Answer 12
+VALUE WiMAX-AE-Command-Code Notification-Request 13
+VALUE WiMAX-AE-Command-Code Notification-Answer 14
+VALUE WiMAX-AE-Command-Code Accounting 15
+
+ATTRIBUTE WiMAX-Requested-EUTRAN-Authentication-Info 144 tlv
+ATTRIBUTE WiMAX-Number-Of-Requested-Vectors 144.1 integer
+ATTRIBUTE WiMAX-Immediate-Response-Preferred 144.2 integer
+ATTRIBUTE WiMAX-Re-synchronization-Info 144.3 octets
+
+VALUE WiMAX-Immediate-Response-Preferred Yes 0
+
+ATTRIBUTE WiMAX-Authentication-Info 145 tlv
+ATTRIBUTE WiMAX-E-UTRAN-Vector 145.1 tlv
+ATTRIBUTE WiMAX-E-UTRAN-Vector-Item-Number 145.1.1 integer
+ATTRIBUTE WiMAX-E-UTRAN-Vector-RAND 145.1.2 octets
+ATTRIBUTE WiMAX-E-UTRAN-Vector-XRES 145.1.3 octets
+ATTRIBUTE WiMAX-E-UTRAN-Vector-AUTN 145.1.4 octets
+ATTRIBUTE WiMAX-E-UTRAN-Vector-KASME 145.1.5 octets
+
+ATTRIBUTE WiMAX-Visited-PLMN-ID 146 octets
+
+ATTRIBUTE WiMAX-RAT-Type 150 integer
+
+ATTRIBUTE WiMAX-Terminal-Information 151 tlv
+ATTRIBUTE WiMAX-IMEI 151.2 string
+ATTRIBUTE WiMAX-Software-Version 151.2 string
+
+ATTRIBUTE WiMAX-Subscription-Data 154 tlv
+ATTRIBUTE WiMAX-UE-AMBR-DL 154.2 integer
+ATTRIBUTE WiMAX-UE-AMBR-UL 154.3 integer
+
+ATTRIBUTE WiMAX-Cancellation-Type 155 byte
+
+VALUE WiMAX-Cancellation-Type MME_UPDATE_PROCEDURE 0
+VALUE WiMAX-Cancellation-Type SUBSCRIPTION_WITHDRAWAL 2
+VALUE WiMAX-Cancellation-Type INITIAL_ATTACH_PROCEDURE 4
+
+ATTRIBUTE WiMAX-EPS-Location-Information 156 tlv
+ATTRIBUTE WiMAX-E-UTRAN-Cell-Global-Identity 156.1 octets
+ATTRIBUTE WiMAX-Tracking-Area-Identity 156.2 octets
+ATTRIBUTE WiMAX-Geographical-Information 156.3 octets
+ATTRIBUTE WiMAX-Geodetic-Information 156.4 octets
+ATTRIBUTE WiMAX-Current-Location-Retrieved 156.5 byte
+ATTRIBUTE WiMAX-Age-Of-Location-Information 156.6 integer
+
+VALUE WiMAX-Current-Location-Retrieved Active-Location-Retrieval 0
+
+ATTRIBUTE WiMAX-Service-Selection 166 string
+
+END-VENDOR WiMAX
diff --git a/share/dictionary.wimax.alvarion b/share/dictionary.wimax.alvarion
new file mode 100644
index 0000000..10c273f
--- /dev/null
+++ b/share/dictionary.wimax.alvarion
@@ -0,0 +1,516 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Alvarion has taken it on themselves to produce a WiMAX dictionary
+# which is NOT the same as the standard WiMAX dictionary. If you
+# want to use this file, edit the "dictionary" file, and change:
+#
+# $INCLUDE dictionary.wimax
+# to
+# $INCLUDE dictionary.wimax.alvarion
+#
+# You CANNOT use both dictionaries at the same time.
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR WiMAX 24757 format=1,1,c
+
+BEGIN-VENDOR WiMAX
+
+ATTRIBUTE WiMAX-Capability 1 tlv
+ATTRIBUTE WiMAX-Release 1.1 string
+ATTRIBUTE WiMAX-Accounting-Capabilities 1.2 byte
+ATTRIBUTE WiMAX-Hotlining-Capabilities 1.3 byte
+ATTRIBUTE WiMAX-Idle-Mode-Notification-Cap 1.4 byte
+
+# This is really a bitmap
+VALUE WiMAX-Accounting-Capabilities No-Accounting 0
+VALUE WiMAX-Accounting-Capabilities IP-Session-Based 1
+VALUE WiMAX-Accounting-Capabilities Flow-Based 2
+
+# This is really a bitmap
+VALUE WiMAX-Hotlining-Capabilities Not-Supported 0
+VALUE WiMAX-Hotlining-Capabilities Hotline-Profile-Id 1
+VALUE WiMAX-Hotlining-Capabilities NAS-Filter-Rule 2
+VALUE WiMAX-Hotlining-Capabilities HTTP-Redirection 4
+VALUE WiMAX-Hotlining-Capabilities IP-Redirection 8
+
+VALUE WiMAX-Idle-Mode-Notification-Cap Not-Supported 0
+VALUE WiMAX-Idle-Mode-Notification-Cap Supported 1
+
+ATTRIBUTE WiMAX-Device-Authentication-Indicator 2 byte
+ATTRIBUTE WiMAX-GMT-Timezone-offset 3 signed
+ATTRIBUTE WiMAX-AAA-Session-Id 4 octets
+
+# 32 octets in length
+ATTRIBUTE WiMAX-MSK 5 octets encrypt=2
+ATTRIBUTE WiMAX-hHA-IP-MIP4 6 ipaddr
+ATTRIBUTE WiMAX-hHA-IP-MIP6 7 ipv6addr
+ATTRIBUTE WiMAX-DHCPv4-Server 8 combo-ip
+ATTRIBUTE WiMAX-DHCPv6-Server 9 combo-ip
+
+# MN-HA-CMIP4 = H(MIP-RK, "CMIP4 MN HA" | HA-IPv4 | MN-NAI), or
+# MN-HA-PMIP4 = H(MIP-RK, "PMIP4 MN HA" | HA-IPv4 | MN-NAI)
+ATTRIBUTE WiMAX-MN-hHA-MIP4-Key 10 octets encrypt=2
+
+# MN-HA-CMIP4-SPI == MIP-SPI, or
+# MN-HA-PIMP4-SPI == MIP-SPI + 1
+ATTRIBUTE WiMAX-MN-hHA-MIP4-SPI 11 integer
+
+# MN-HA-CMIP6 = H(MIP-RK, "CMIP6 MN HA" | HA-IPv6 | MN-NAI)
+ATTRIBUTE WiMAX-MN-hHA-MIP6-Key 12 octets encrypt=2
+
+# MN-HA-CMIP6-SPI == MIP-SPI + 2
+ATTRIBUTE WiMAX-MN-hHA-MIP6-SPI 13 integer
+
+# FA-RK = H(MIP-RK, "FA-RK")
+ATTRIBUTE WiMAX-FA-RK-Key 14 octets encrypt=2
+
+# 160 bit random number
+ATTRIBUTE WiMAX-HA-RK-Key 15 octets encrypt=2
+# SPI-CMIP4
+ATTRIBUTE WiMAX-HA-RK-SPI 16 integer
+
+ATTRIBUTE WiMAX-HA-RK-Lifetime 17 integer
+
+# The same as MN-HA-CMIP4, etc. But in different packets.
+ATTRIBUTE WiMAX-RRQ-HA-IP 18 combo-ip
+ATTRIBUTE WiMAX-RRQ-MN-HA-Key 19 octets encrypt=2
+ATTRIBUTE WiMAX-RRQ-MN-HA-SPI 20 integer
+
+ATTRIBUTE WiMAX-Session-Continue 21 integer
+ATTRIBUTE WiMAX-Beginning-Of-Session 22 integer
+ATTRIBUTE WiMAX-IP-Technology 23 integer
+
+VALUE WiMAX-IP-Technology Reserved-0 0
+VALUE WiMAX-IP-Technology Reserved-1 1
+VALUE WiMAX-IP-Technology PMIP4 2
+VALUE WiMAX-IP-Technology CMIP4 3
+VALUE WiMAX-IP-Technology CMIP6 4
+VALUE WiMAX-IP-Technology Ethernet-CS 5
+
+ATTRIBUTE WiMAX-Hotline-Indicator 24 string
+ATTRIBUTE WiMAX-Prepaid-Indicator 25 byte
+ATTRIBUTE WiMAX-PDFID 26 short
+ATTRIBUTE WiMAX-SDFID 27 short
+
+# The WMF standard version of this attribute is deprecated in WMF 1.5
+# and shall no longer be used. Replaced by (26/84) Packet Flow Descriptor v2
+#
+# Alvarion uses a vendor specific version of this attribute that combines
+# some aspects of v1 (26/28) and v2 (26/84)
+# See their Radius Interoperability Spec documentation for additional details.
+ATTRIBUTE WiMAX-Packet-Flow-Descriptor 28 tlv
+ATTRIBUTE WiMAX-Packet-Data-Flow-Id 28.1 short
+ATTRIBUTE WiMAX-Service-Data-Flow-Id 28.2 short
+ATTRIBUTE WiMAX-Service-Profile-Id 28.3 integer
+ATTRIBUTE WiMAX-Direction 28.4 byte
+
+VALUE WiMAX-Direction Reserved-0 0
+VALUE WiMAX-Direction Uplink 1
+VALUE WiMAX-Direction Downlink 2
+VALUE WiMAX-Direction Bi-Directional 3
+
+ATTRIBUTE WiMAX-Activation-Trigger 28.5 byte # bitmap
+ATTRIBUTE WiMAX-Transport-Type 28.6 byte
+
+VALUE WiMAX-Transport-Type Reserved-0 0
+VALUE WiMAX-Transport-Type IPv4-CS 1
+VALUE WiMAX-Transport-Type IPv6-CS 2
+VALUE WiMAX-Transport-Type Ethernet 3
+
+ATTRIBUTE WiMAX-Uplink-QOS-Id 28.7 byte
+ATTRIBUTE WiMAX-Downlink-QOS-Id 28.8 byte
+# The following are not listed in Alvarion's Spec
+#ATTRIBUTE WiMAX-Uplink-Classifier 28.9 string
+#ATTRIBUTE WiMAX-Downlink-Classifier 28.10 string
+# Added by Alvarion
+ATTRIBUTE WiMAX-Classifier 28.11 tlv
+
+ATTRIBUTE WiMAX-ClassifierID 28.11.1 byte
+ATTRIBUTE WiMAX-Classifier-Priority 28.11.2 byte
+ATTRIBUTE WiMAX-Classifier-Protocol 28.11.3 byte
+ATTRIBUTE WiMAX-Classifier-Direction 28.11.4 byte
+
+VALUE WiMAX-Classifier-Direction Reserved-0 0
+VALUE WiMAX-Classifier-Direction IN 1
+VALUE WiMAX-Classifier-Direction OUT 2
+VALUE WiMAX-Classifier-Direction Bi-Directional 3
+VALUE WiMAX-Classifier-Direction FF 4
+
+ATTRIBUTE WiMAX-Source-Specification 28.11.5 tlv
+
+ATTRIBUTE WiMAX-Source-IPAddress 28.11.5.1 combo-ip
+# 2 IPv4 or IPv6 addresses
+ATTRIBUTE WiMAX-Source-IPAddressRange 28.11.5.2 octets
+# IPv4/IPv6 subnet mask plus bit-width mask
+ATTRIBUTE WiMAX-Source-IPAddressMask 28.11.5.3 octets
+ATTRIBUTE WiMAX-Source-Port 28.11.5.4 short
+# 4 bytes: first two indicate beginning of range, second two indicate end
+ATTRIBUTE WiMAX-Source-Port-Range 28.11.5.5 octets
+ATTRIBUTE WiMAX-Source-Inverted 28.11.5.6 byte
+
+VALUE WiMAX-Source-Inverted False 0
+VALUE WiMAX-Source-Inverted True 1
+
+# 8 bit unsigned enum
+ATTRIBUTE WiMAX-Source-Assigned 28.11.5.7 byte
+
+VALUE WiMAX-Source-Assigned Src-Assigned 1
+VALUE WiMAX-Source-Assigned Dst-Assigned 2
+VALUE WiMAX-Source-Assigned Src-Dst-Assigned 3
+
+ATTRIBUTE WiMAX-Destination-Specification 28.11.6 tlv
+
+ATTRIBUTE WiMAX-Destination-IPAddress 28.11.6.1 combo-ip
+# 2 IPv4 or IPv6 addresses to indicate beginning/end of range
+ATTRIBUTE WiMAX-Destination-IPAddressRange 28.11.6.2 octets
+# IPv4/IPv6 subnet mask plus bit-width mask
+ATTRIBUTE WiMAX-Destination-IPAddressMask 28.11.6.3 octets
+ATTRIBUTE WiMAX-Destination-Port 28.11.6.4 short
+# 4 bytes: first two indicate beginning of range, second two indicate end
+ATTRIBUTE WiMAX-Destination-Port-Range 28.11.6.5 octets
+ATTRIBUTE WiMAX-Destination-Inverted 28.11.6.6 byte
+
+VALUE WiMAX-Destination-Inverted False 0
+VALUE WiMAX-Destination-Inverted True 1
+
+ATTRIBUTE WiMAX-Destination-Assigned 28.11.6.7 byte
+
+VALUE WiMAX-Destination-Assigned Src-Assigned 1
+VALUE WiMAX-Destination-Assigned Dst-Assigned 2
+VALUE WiMAX-Destination-Assigned Src-Dst-Assigned 3
+
+ATTRIBUTE WiMAX-IP-TOS-DSCP-Range-and-Mask 28.11.7 octets
+ATTRIBUTE WiMAX-VLAN-ID 28.11.9 short
+ATTRIBUTE WiMAX-8021p 28.11.10 byte
+
+ATTRIBUTE WiMAX-QoS-Descriptor 29 tlv
+ATTRIBUTE WiMAX-QoS-Id 29.1 byte
+ATTRIBUTE WiMAX-Global-Service-Class-Name 29.2 string # 6 octets
+ATTRIBUTE WiMAX-Service-Class-Name 29.3 string
+ATTRIBUTE WiMAX-Schedule-Type 29.4 byte
+ATTRIBUTE WiMAX-Traffic-Priority 29.5 byte
+ATTRIBUTE WiMAX-Maximum-Sustained-Traffic-Rate 29.6 integer
+ATTRIBUTE WiMAX-Minimum-Reserved-Traffic-Rate 29.7 integer
+ATTRIBUTE WiMAX-Maximum-Traffic-Burst 29.8 integer
+ATTRIBUTE WiMAX-Tolerated-Jitter 29.9 integer
+ATTRIBUTE WiMAX-Maximum-Latency 29.10 integer
+ATTRIBUTE WiMAX-Reduced-Resources-Code 29.11 byte
+ATTRIBUTE WiMAX-Media-Flow-Type 29.12 byte
+ATTRIBUTE WiMAX-Unsolicited-Grant-Interval 29.13 short
+ATTRIBUTE WiMAX-SDU-Size 29.14 short
+ATTRIBUTE WiMAX-Unsolicited-Polling-Interval 29.15 short
+ATTRIBUTE WiMAX-Media-Flow-Description-SDP 29.16 string
+
+VALUE WiMAX-Schedule-Type Best-Effort 2
+VALUE WiMAX-Schedule-Type nrtPS 3
+VALUE WiMAX-Schedule-Type rtPS 4
+VALUE WiMAX-Schedule-Type Extended-rtPS 5
+VALUE WiMAX-Schedule-Type UGS 6
+
+VALUE WiMAX-Media-Flow-Type VoIP 1
+VALUE WiMAX-Media-Flow-Type Robust-Browser 2
+VALUE WiMAX-Media-Flow-Type Secure-Browser-VPN 3
+VALUE WiMAX-Media-Flow-Type Streaming-Video 4
+VALUE WiMAX-Media-Flow-Type Streaming-Live-TV 5
+VALUE WiMAX-Media-Flow-Type Music-Photo-Download 6
+VALUE WiMAX-Media-Flow-Type Multi-Player-Gaming 7
+VALUE WiMAX-Media-Flow-Type Location-Based-Services 8
+VALUE WiMAX-Media-Flow-Type Text-Audio-Books 9
+VALUE WiMAX-Media-Flow-Type Video-Conversation 10
+VALUE WiMAX-Media-Flow-Type Message 11
+VALUE WiMAX-Media-Flow-Type Control 12
+VALUE WiMAX-Media-Flow-Type Data 13
+
+ATTRIBUTE WiMAX-Uplink-Granted-QoS 30 string
+ATTRIBUTE WiMAX-Control-Packets-In 31 integer
+ATTRIBUTE WiMAX-Control-Octets-In 32 integer
+ATTRIBUTE WiMAX-Control-Packets-Out 33 integer
+ATTRIBUTE WiMAX-Control-Octets-Out 34 integer
+ATTRIBUTE WiMAX-PPAC 35 tlv
+ATTRIBUTE WiMAX-Available-In-Client 35.1 integer
+
+# Really a bitmap
+VALUE WiMAX-Available-In-Client Volume-Metering 1
+VALUE WiMAX-Available-In-Client Duration-Metering 2
+VALUE WiMAX-Available-In-Client Resource-Metering 4
+VALUE WiMAX-Available-In-Client Pools 8
+VALUE WiMAX-Available-In-Client Rating-Groups 0x10
+VALUE WiMAX-Available-In-Client Multi-Services 0x20
+VALUE WiMAX-Available-In-Client Tariff-Switch 0x40
+
+ATTRIBUTE WiMAX-Session-Termination-Capability 36 integer
+
+# Really a bitmap
+VALUE WiMAX-Session-Termination-Capability Dynamic-Authorization 1
+
+ATTRIBUTE WiMAX-PPAQ 37 tlv
+ATTRIBUTE WiMAX-PPAQ-Quota-Identifier 37.1 octets
+ATTRIBUTE WiMAX-Volume-Quota 37.2 integer #kb
+ATTRIBUTE WiMAX-Volume-Threshold 37.3 integer #kb
+ATTRIBUTE WiMAX-Duration-Quota 37.4 integer #s
+ATTRIBUTE WiMAX-Duration-Threshold 37.5 integer #s
+ATTRIBUTE WiMAX-Resource-Quota 37.6 integer
+ATTRIBUTE WiMAX-Resource-Threshold 37.7 integer
+ATTRIBUTE WiMAX-Update-Reason 37.8 integer
+ATTRIBUTE WiMAX-Prepaid-Server 37.9 combo-ip
+ATTRIBUTE WiMAX-Service-Id 37.10 string
+ATTRIBUTE WiMAX-Rating-Group-Id 37.11 integer
+ATTRIBUTE WiMAX-Termination-Action 37.12 byte
+ATTRIBUTE WiMAX-Pool-Id 37.13 integer
+ATTRIBUTE WiMAX-Pool-Multiplier 37.14 integer
+ATTRIBUTE WiMAX-Requested-Action 37.15 byte
+ATTRIBUTE WiMAX-Check-Balance-Result 37.16 byte
+
+#
+# 4 octets - integer representing 1/10's of lowest currency (e.g. cents)
+# 4 octets - currency code as in ISO-4217
+# 1+ - UTF8 string containing text like "cost is $1 per minute"
+#
+ATTRIBUTE WiMAX-Cost-Information-AVP 37.17 octets
+
+VALUE WiMAX-Update-Reason Pre-Initialization 1
+VALUE WiMAX-Update-Reason Initial-Request 2
+VALUE WiMAX-Update-Reason Threshold-Reached 3
+VALUE WiMAX-Update-Reason Quota-Reached 4
+VALUE WiMAX-Update-Reason TITSU-Approaching 5
+VALUE WiMAX-Update-Reason Remote-Forced-Disconnect 6
+VALUE WiMAX-Update-Reason Client-Service-Termination 7
+VALUE WiMAX-Update-Reason Access-Service-Terminated 8
+VALUE WiMAX-Update-Reason Service-Not-Established 9
+VALUE WiMAX-Update-Reason One-Time-Charging 10
+
+VALUE WiMAX-Termination-Action Terminate 1
+VALUE WiMAX-Termination-Action Request-More-Quota 2
+VALUE WiMAX-Termination-Action Redirect-Or-Filter 3
+
+VALUE WiMAX-Requested-Action Balance-Check 1
+VALUE WiMAX-Requested-Action Price-Enquiry 2
+
+ATTRIBUTE WiMAX-Prepaid-Tariff-Switching 38 tlv
+ATTRIBUTE WiMAX-Prepaid-Quota-Identifier 38.1 string
+ATTRIBUTE WiMAX-Volume-Used-After 38.2 integer #1k
+ATTRIBUTE WiMAX-Tariff-Switch-Interval 38.3 integer #s
+ATTRIBUTE WiMAX-Time-Interval-After 38.4 integer #s
+
+ATTRIBUTE WiMAX-Active-Time-Duration 39 integer
+ATTRIBUTE WiMAX-DHCP-RK 40 octets encrypt=2
+ATTRIBUTE WiMAX-DHCP-RK-Key-Id 41 integer
+ATTRIBUTE WiMAX-DHCP-RK-Lifetime 42 integer
+ATTRIBUTE WiMAX-DHCP-Msg-Server-IP 43 ipaddr
+ATTRIBUTE WiMAX-Idle-Mode-Transition 44 byte
+ATTRIBUTE WiMAX-NAP-Id 45 octets
+
+# 3 octets of NAP Id
+# 3 octets of base-station Id
+ATTRIBUTE WiMAX-BS-Id 46 octets
+ATTRIBUTE WiMAX-Location 47 octets
+
+# Number of times Acct-Input-Packets rolled over 2^32.
+ATTRIBUTE WiMAX-Acct-Input-Packets-Gigaword 48 integer
+ATTRIBUTE WiMAX-Acct-Output-Packets-Gigaword 49 integer
+
+# Formatted as per IP Filter rule specification.
+ATTRIBUTE WiMAX-Uplink-Flow-Description 50 string
+
+ATTRIBUTE WiMAX-Blu-Coa-IPv6 51 ipv6addr
+ATTRIBUTE WiMAX-DNS-Server 52 combo-ip
+ATTRIBUTE WiMAX-Hotline-Profile-Id 53 string
+
+# Formatted as per IP Filter rule specification.
+ATTRIBUTE WiMAX-HTTP-Redirection-Rule 54 string
+
+# Formatted as per IP Filter rule specification.
+ATTRIBUTE WiMAX-IP-Redirection-Rule 55 string
+ATTRIBUTE WiMAX-Hotline-Session-Timer 56 integer
+
+# 3 octets
+ATTRIBUTE WiMAX-NSP-Id 57 octets
+ATTRIBUTE WiMAX-HA-RK-Key-Requested 58 integer
+
+VALUE WiMAX-HA-RK-Key-Requested No 0
+VALUE WiMAX-HA-RK-Key-Requested Yes 1
+
+ATTRIBUTE WiMAX-Count-Type 59 byte
+ATTRIBUTE WiMAX-DM-Action-Code 60 integer
+
+VALUE WiMAX-DM-Action-Code Deregister-MS 0
+VALUE WiMAX-DM-Action-Code Suspend-MS-Traffic 1
+VALUE WiMAX-DM-Action-Code Suspend-User-Traffic 2
+VALUE WiMAX-DM-Action-Code Resume-Traffic 3
+VALUE WiMAX-DM-Action-Code MS-Terminate 4
+VALUE WiMAX-DM-Action-Code MS-Idle 5
+VALUE WiMAX-DM-Action-Code MS-Completed-IPv6-Handover 6
+VALUE WiMAX-DM-Action-Code BS-Sends-RES-Cmd 0xffff
+
+# FA-RK-SPI = SPI-CMIP4 = MIP-SPI
+ATTRIBUTE WiMAX-FA-RK-SPI 61 integer
+
+# Formatted as per IP Filter rule specification.
+ATTRIBUTE WiMAX-Downlink-Flow-Description 62 string
+
+# Same as QoS-Descriptor... dang.
+ATTRIBUTE WiMAX-Downlink-Granted-QoS 63 tlv
+
+# More MIP keys, calculated as above... but in different packets.
+# Why, oh why?
+ATTRIBUTE WiMAX-vHA-IP-MIP4 64 ipaddr
+ATTRIBUTE WiMAX-vHA-IP-MIP6 65 ipv6addr
+ATTRIBUTE WiMAX-vHA-MIP4-Key 66 octets encrypt=2
+ATTRIBUTE WiMAX-vHA-RK-Key 67 octets encrypt=2
+ATTRIBUTE WiMAX-vHA-RK-SPI 68 integer
+ATTRIBUTE WiMAX-vHA-RK-Lifetime 69 integer
+
+ATTRIBUTE WiMAX-MN-vHA-MIP6-Key 70 octets encrypt=2
+ATTRIBUTE WiMAX-MN-vHA-MIP4-SPI 71 integer
+ATTRIBUTE WiMAX-MN-vHA-MIP6-SPI 72 integer
+ATTRIBUTE WiMAX-vDHCPv4-Server 73 ipaddr
+ATTRIBUTE WiMAX-vDHCPv6-Server 74 ipv6addr
+ATTRIBUTE WiMAX-vDHCP-RK 75 octets encrypt=2
+ATTRIBUTE WiMAX-vDHCP-RK-Key-ID 76 integer
+ATTRIBUTE WiMAX-vDHCP-RK-Lifetime 77 integer
+
+ATTRIBUTE WiMAX-PMIP-Authenticated-Network-Identity 78 string
+ATTRIBUTE WiMAX-Visited-Framed-IP-Address 79 ipaddr
+ATTRIBUTE WiMAX-Visited-Framed-IPv6-Prefix 80 ipv6prefix
+ATTRIBUTE WiMAX-Visited-Framed-Interface-Id 81 ifid
+ATTRIBUTE WiMAX-MIP-Authorization-Status 82 integer
+
+VALUE WiMAX-MIP-Authorization-Status False 0
+VALUE WiMAX-MIP-Authorization-Status True 1
+
+#
+# FIXME: See WiMAX-Src-Dst-Specification for TLVs
+#
+ATTRIBUTE WiMAX-Flow-Descriptor-v2 83 tlv
+
+ATTRIBUTE WiMAX-Packet-Flow-Descriptor-v2 84 tlv
+ATTRIBUTE WiMAX-PFDv2-Packet-Data-Flow-Id 84.1 short
+ATTRIBUTE WiMAX-PFDv2-Service-Data-Flow-Id 84.2 short
+ATTRIBUTE WiMAX-PFDv2-Service-Profile-Id 84.3 integer
+ATTRIBUTE WiMAX-PFDv2-Direction 84.4 byte
+ATTRIBUTE WiMAX-PFDv2-Activation-Trigger 84.5 byte
+ATTRIBUTE WiMAX-PFDv2-Transport-Type 84.6 byte
+ATTRIBUTE WiMAX-PFDv2-Uplink-QoS-Id 84.7 byte
+ATTRIBUTE WiMAX-PFDv2-Downlink-QoS-Id 84.8 byte
+
+#
+# Classifiers
+#
+ATTRIBUTE WiMAX-PFDv2-Classifier 84.9 tlv
+ATTRIBUTE WiMAX-PFDv2-Classifier-Id 84.9.1 byte
+ATTRIBUTE WiMAX-PFDv2-Classifier-Priority 84.9.2 byte
+ATTRIBUTE WiMAX-PFDv2-Classifier-Protocol 84.9.3 byte
+ATTRIBUTE WiMAX-PFDv2-Classifier-Direction 84.9.4 byte
+
+ATTRIBUTE WiMAX-PFDv2-Classifier-Source-Spec 84.9.5 tlv
+ATTRIBUTE WiMAX-PFDv2-Src-IP-Address 84.9.5.1 combo-ip
+# really two IPv4 OR IPv6 addresses
+ATTRIBUTE WiMAX-PFDv2-Src-IP-Address-Range 84.9.5.2 octets
+ATTRIBUTE WiMAX-PFDv2-Src-IP-Address-Mask 84.9.5.3 combo-ip
+ATTRIBUTE WiMAX-PFDv2-Src-Port 84.9.5.4 short
+# 2 shorts
+ATTRIBUTE WiMAX-PFDv2-Src-Port-Range 84.9.5.5 integer
+ATTRIBUTE WiMAX-PFDv2-Src-Inverted 84.9.5.6 byte
+ATTRIBUTE WiMAX-PFDv2-Src-Assigned 84.9.5.7 byte
+
+VALUE WiMAX-PFDv2-Src-Assigned Src-Assigned 1
+VALUE WiMAX-PFDv2-Src-Assigned Dst-Assigned 2
+VALUE WiMAX-PFDv2-Src-Assigned Src-Dst-Assigned 3
+
+ATTRIBUTE WiMAX-PFDv2-Src-MAC-Address 84.9.5.8 ether
+ATTRIBUTE WiMAX-PFDv2-Src-MAC-Mask 84.9.5.9 ether
+
+ATTRIBUTE WiMAX-PFDv2-Classifier-Dest-Spec 84.9.6 tlv
+ATTRIBUTE WiMAX-PFDv2-Classifier-IP-ToS-DSCP 84.9.7 byte
+ATTRIBUTE WiMAX-PFDv2-Classifier-Action 84.9.8 byte
+
+ATTRIBUTE WiMAX-PFDv2-Classifier-Eth-Option 84.9.9 tlv
+
+ATTRIBUTE WiMAX-PFDv2-Eth-Proto-Type 84.9.9.1 tlv
+ATTRIBUTE WiMAX-PFDv2-Eth-Proto-Type-Ethertype 84.9.9.1.1 short
+ATTRIBUTE WiMAX-PFDv2-Eth-Proto-Type-DSAP 84.9.9.1.2 byte
+
+ATTRIBUTE WiMAX-PFDv2-Eth-VLAN-Id 84.9.9.2 tlv
+ATTRIBUTE WiMAX-PFDv2-Eth-VLAN-Id-S-VID 84.9.9.2.1 integer
+ATTRIBUTE WiMAX-PFDv2-Eth-VLAN-Id-C-VID 84.9.9.2.2 integer
+
+ATTRIBUTE WiMAX-PFDv2-Eth-Priority-Range 84.9.9.3 tlv
+ATTRIBUTE WiMAX-PFDv2-Eth-Priority-Range-Low 84.9.9.3.1 byte
+ATTRIBUTE WiMAX-PFDv2-Eth-Priority-Range-High 84.9.9.3.2 byte
+
+ATTRIBUTE WiMAX-XXX 84.9.9.4 byte
+
+ATTRIBUTE WiMAX-PFDv2-Paging-Preference 84.9.10 byte
+ATTRIBUTE WiMAX-PFDv2-VLAN-Tag-Rule-Id 84.9.11 short
+
+VALUE WiMAX-PFDv2-Direction Uplink 1
+VALUE WiMAX-PFDv2-Direction Downlink 2
+VALUE WiMAX-PFDv2-Direction Bi-Directional 3
+
+VALUE WiMAX-PFDv2-Activation-Trigger Provisioned 1
+VALUE WiMAX-PFDv2-Activation-Trigger Admit 2
+VALUE WiMAX-PFDv2-Activation-Trigger Activate 4
+VALUE WiMAX-PFDv2-Activation-Trigger Dynamic 8
+
+VALUE WiMAX-PFDv2-Transport-Type IPv4-CS 1
+VALUE WiMAX-PFDv2-Transport-Type IPv6-CS 2
+VALUE WiMAX-PFDv2-Transport-Type Ethernet 3
+
+ATTRIBUTE WiMAX-VLAN-Tag-Processing-Descriptor 85 tlv
+ATTRIBUTE WiMAX-VLAN-Tag-Rule-Id 85.1 short
+ATTRIBUTE WiMAX-VLAN-Tag-C-VLAN-Priority 85.2 byte
+ATTRIBUTE WiMAX-VLAN-Tag-VLAN-Id-Assignment 85.3 short
+ATTRIBUTE WiMAX-VLAN-Tag-C-VLAN-Id 85.4 short
+ATTRIBUTE WiMAX-VLAN-Tag-S-VLAN-Id 85.5 short
+ATTRIBUTE WiMAX-VLAN-Tag-C-S-VLAN-Id-Mapping 85.6 integer
+ATTRIBUTE WiMAX-VLAN-Tag-Local-Config-Info 85.7 octets
+
+ATTRIBUTE WiMAX-hDHCP-Server-Parameters 86 tlv
+ATTRIBUTE WiMAX-hDHCP-DHCPv4-Address 86.1 ipaddr
+ATTRIBUTE WiMAX-hDHCP-DHCPv6-Address 86.2 ipv6addr
+ATTRIBUTE WiMAX-hDHCP-DHCP-RK 86.3 string encrypt=2
+ATTRIBUTE WiMAX-hDHCP-DHCP-RK-Key-Id 86.4 integer
+ATTRIBUTE WiMAX-hDHCP-DHCP-RK-Lifetime 86.5 integer
+
+ATTRIBUTE WiMAX-vDHCP-Server-Parameters 87 tlv
+ATTRIBUTE WiMAX-vDHCP-DHCPv4-Address 87.1 ipaddr
+ATTRIBUTE WiMAX-vDHCP-DHCPv6-Address 87.2 ipv6addr
+ATTRIBUTE WiMAX-vDHCP-DHCP-RK 87.3 string encrypt=2
+ATTRIBUTE WiMAX-vDHCP-DHCP-RK-Key-Id 87.4 integer
+ATTRIBUTE WiMAX-vDHCP-DHCP-RK-Lifetime 87.5 integer
+
+ATTRIBUTE WiMAX-BS-Location 88 octets
+ATTRIBUTE WiMAX-Visited-IPv4-HoA-PMIP6 89 byte
+
+VALUE WiMAX-Visited-IPv4-HoA-PMIP6 Fixed 1
+VALUE WiMAX-Visited-IPv4-HoA-PMIP6 Nomadic 2
+VALUE WiMAX-Visited-IPv4-HoA-PMIP6 Mobile 3
+
+ATTRIBUTE WiMAX-MS-Authenticated 90 byte
+
+VALUE WiMAX-MS-Authenticated No 0
+VALUE WiMAX-MS-Authenticated Yes 1
+
+ATTRIBUTE WiMAX-PMIP6-Service-Info 126 short
+
+ATTRIBUTE WiMAX-hLMA-IPv6-PMIP6 127 ipv6addr
+ATTRIBUTE WiMAX-hLMA-IPv4-PMIP6 128 ipaddr
+ATTRIBUTE WiMAX-vLMA-IPv6-PMIP6 129 ipv6addr
+ATTRIBUTE WiMAX-vLMA-IPv4-PMIP6 130 ipaddr
+ATTRIBUTE WiMAX-PMIP6-RK-Key 131 octets encrypt=2
+ATTRIBUTE WiMAX-PMIP6-RK-SPI 132 integer
+ATTRIBUTE WiMAX-Home-HNP-PMIP6 133 ipv6prefix
+ATTRIBUTE WiMAX-Home-Interface-Id-PMIP6 134 ifid
+ATTRIBUTE WiMAX-Home-IPv4-HoA-PMIP6 135 ipaddr
+ATTRIBUTE WiMAX-Visited-HNP-PMIP6 136 ipv6prefix
+ATTRIBUTE WiMAX-Visited-Interface-Id-PMIP6 137 ifid
+ATTRIBUTE WiMAX-Visited-IPv4-HoA-PMIP6-2 138 ipaddr
+
+END-VENDOR WiMAX
diff --git a/share/dictionary.wimax.wichorus b/share/dictionary.wimax.wichorus
new file mode 100644
index 0000000..aa2e3d3
--- /dev/null
+++ b/share/dictionary.wimax.wichorus
@@ -0,0 +1,409 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# This is a WiMAX dictionary for the WiChorus line of products.
+# It is NOT compatible with the normal WiMAX dictionary.
+# It CANNOT be used at the same time as the normal WiMAX dictionary.
+#
+##############################################################################
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR WiMAX 24757 format=1,1,c
+
+BEGIN-VENDOR WiMAX
+
+ATTRIBUTE WiMAX-Capability 1 tlv
+
+BEGIN-TLV WiMAX-Capability
+ATTRIBUTE WiMAX-Release 1 string
+ATTRIBUTE WiMAX-Accounting-Capabilities 2 byte
+ATTRIBUTE WiMAX-Hotlining-Capabilities 3 byte
+ATTRIBUTE WiMAX-Idle-Mode-Notification-Cap 4 byte
+ATTRIBUTE WiMAX-Packet-Flow-Descriptor-Capabilities 5 byte
+# Role of 6/7 swapped vs definition in WMF R015v01
+ATTRIBUTE WiMAX-ASN-Network-Service-Capabilities 6 integer
+ATTRIBUTE WiMAX-Authorized-IP-Services 7 integer
+
+# This is really a bitmap
+VALUE WiMAX-Accounting-Capabilities No-Accounting 0
+VALUE WiMAX-Accounting-Capabilities IP-Session-Based 1
+VALUE WiMAX-Accounting-Capabilities Flow-Based 2
+
+# This is really a bitmap
+VALUE WiMAX-Hotlining-Capabilities Not-Supported 0
+VALUE WiMAX-Hotlining-Capabilities Hotline-Profile-Id 1
+VALUE WiMAX-Hotlining-Capabilities NAS-Filter-Rule 2
+VALUE WiMAX-Hotlining-Capabilities HTTP-Redirection 4
+VALUE WiMAX-Hotlining-Capabilities IP-Redirection 8
+
+VALUE WiMAX-Idle-Mode-Notification-Cap Not-Supported 0
+VALUE WiMAX-Idle-Mode-Notification-Cap Supported 1
+
+# v2 also implies support for v1
+VALUE WiMAX-Packet-Flow-Descriptor-Capabilities v1 1
+VALUE WiMAX-Packet-Flow-Descriptor-Capabilities v2 2
+
+# This is really a bitmap.
+# For Wichorus gateway this is used to
+# indicate functionality supported by the ASN-GW. In WMF R015V01
+# this is sub-tlv 7 with the same functionality. Sub-tlv 6 is a
+# similar and used to indicate services the ASN is authorized to
+# support for the subscriber (see sub-tlv 7 for Wichorus' version)
+# Wichorus' implementation is also shifted left one bit...
+VALUE WiMAX-ASN-Network-Service-Capabilities DHCPv4-Relay 2
+VALUE WiMAX-ASN-Network-Service-Capabilities DHCPv6-Relay 4
+VALUE WiMAX-ASN-Network-Service-Capabilities DHCPv4-Proxy 8
+VALUE WiMAX-ASN-Network-Service-Capabilities DHCPv6-Proxy 16
+VALUE WiMAX-ASN-Network-Service-Capabilities FA 32
+VALUE WiMAX-ASN-Network-Service-Capabilities PMIP-Client 64
+# ... plus additional, but these are the only relevant ones for now
+
+# This is really a bitmap
+# Proprietary definition of supported services. Used by the AAA to
+# indicate which services the ASN is allowed to support for the MS
+VALUE WiMAX-Authorized-IP-Services CMIPv4 1
+VALUE WiMAX-Authorized-IP-Services PMIPv4 2
+VALUE WiMAX-Authorized-IP-Services SimpleIPv4 4
+
+END-TLV WiMAX-Capability
+
+ATTRIBUTE WiMAX-Device-Authentication-Indicator 2 byte
+ATTRIBUTE WiMAX-GMT-Timezone-offset 3 signed
+ATTRIBUTE WiMAX-AAA-Session-Id 4 octets
+
+# 32 octets in length
+ATTRIBUTE WiMAX-MSK 5 octets encrypt=2
+ATTRIBUTE WiMAX-hHA-IP-MIP4 6 ipaddr
+ATTRIBUTE WiMAX-hHA-IP-MIP6 7 ipv6addr
+ATTRIBUTE WiMAX-DHCPv4-Server 8 combo-ip
+ATTRIBUTE WiMAX-DHCPv6-Server 9 combo-ip
+
+# MN-HA-CMIP4 = H(MIP-RK, "CMIP4 MN HA" | HA-IPv4 | MN-NAI), or
+# MN-HA-PMIP4 = H(MIP-RK, "PMIP4 MN HA" | HA-IPv4 | MN-NAI)
+ATTRIBUTE WiMAX-MN-hHA-MIP4-Key 10 octets encrypt=2
+
+# MN-HA-CMIP4-SPI == MIP-SPI, or
+# MN-HA-PIMP4-SPI == MIP-SPI + 1
+ATTRIBUTE WiMAX-MN-hHA-MIP4-SPI 11 integer
+
+# MN-HA-CMIP6 = H(MIP-RK, "CMIP6 MN HA" | HA-IPv6 | MN-NAI)
+ATTRIBUTE WiMAX-MN-hHA-MIP6-Key 12 octets encrypt=2
+
+# MN-HA-CMIP6-SPI == MIP-SPI + 2
+ATTRIBUTE WiMAX-MN-hHA-MIP6-SPI 13 integer
+
+# FA-RK = H(MIP-RK, "FA-RK")
+ATTRIBUTE WiMAX-FA-RK-Key 14 octets encrypt=2
+
+# 160 bit random number
+ATTRIBUTE WiMAX-HA-RK-Key 15 octets encrypt=2
+# SPI-CMIP4
+ATTRIBUTE WiMAX-HA-RK-SPI 16 integer
+
+ATTRIBUTE WiMAX-HA-RK-Lifetime 17 integer
+
+# Calculation is the same as MN-HA-CMIP4, etc.
+# With CMIP the MN may not know the appropriate HA IP address when calculating
+# the MIP RRQ AE (IPv4) or during a BU (IPv6). In this case it must either use an
+# old known HA IP address or can indicate whether dynamic HA assignment from the
+# hCSN is preferred to the vCSN, or if there is no preference by providing
+# ALL-ZERO-ONE-ADDR (255.255.255.255/0.0.0.0 respectively) in the MIP RRQ sent
+# to the FA. The RRQ-MN-HA key is calculated using this RRQ-HA-IP address and is
+# required by the HA to validate the MIP RRQ received from the MS as it does
+# not contain the actual HA IP address.
+ATTRIBUTE WiMAX-RRQ-HA-IP 18 combo-ip
+ATTRIBUTE WiMAX-RRQ-MN-HA-Key 19 octets encrypt=2
+
+ATTRIBUTE WiMAX-Time-Of-Day-Time 20 tlv
+
+BEGIN-TLV WiMAX-Time-Of-Day-Time
+ATTRIBUTE WiMAX-Hour 1 byte
+ATTRIBUTE WiMAX-Minute 2 byte
+ATTRIBUTE WiMAX-UTC-Offset 3 integer
+END-TLV WiMAX-Time-Of-Day-Time
+
+ATTRIBUTE WiMAX-Session-Continue 21 integer
+
+VALUE WiMAX-Session-Continue False 0
+VALUE WiMAX-Session-Continue True 1
+
+ATTRIBUTE WiMAX-Beginning-Of-Session 22 integer
+
+VALUE WiMAX-Beginning-Of-Session False 0
+VALUE WiMAX-Beginning-Of-Session True 1
+
+# This is pulled from WMF R015v01 - because our ASN-GW supports Simple IP and a
+# simple way to denote this was needed without building in a lot of private
+# logic that would one day simply be replaced by this logic anyway.
+# Note: Attribute renamed in Release 1.5 to Network-Technology. Maintain the
+# old name here to allow for better backwards compatibility.
+ATTRIBUTE WiMAX-IP-Technology 23 integer
+
+VALUE WiMAX-IP-Technology Simple-IPv4 0
+VALUE WiMAX-IP-Technology Simple-IPv6 1
+VALUE WiMAX-IP-Technology PMIP4 2
+VALUE WiMAX-IP-Technology CMIP4 3
+VALUE WiMAX-IP-Technology CMIP6 4
+VALUE WiMAX-IP-Technology Ethernet-CS 5
+VALUE WiMAX-IP-Technology Simple-ETH 6
+VALUE WiMAX-IP-Technology MIP-Based-ETH 7
+VALUE WiMAX-IP-Technology PMIP6 8
+
+ATTRIBUTE WiMAX-Hotline-Indicator 24 string
+ATTRIBUTE WiMAX-Prepaid-Indicator 25 byte
+ATTRIBUTE WiMAX-PDFID 26 short
+ATTRIBUTE WiMAX-SDFID 27 short
+ATTRIBUTE WiMAX-Packet-Flow-Descriptor 28 tlv
+
+BEGIN-TLV WiMAX-Packet-Flow-Descriptor
+ATTRIBUTE WiMAX-Packet-Data-Flow-Id 1 short
+ATTRIBUTE WiMAX-Service-Data-Flow-Id 2 short
+ATTRIBUTE WiMAX-Service-Profile-Id 3 integer
+ATTRIBUTE WiMAX-Direction 4 byte
+
+VALUE WiMAX-Direction Reserved-0 0
+VALUE WiMAX-Direction Uplink 1
+VALUE WiMAX-Direction Downlink 2
+VALUE WiMAX-Direction Bi-Directional 3
+
+ATTRIBUTE WiMAX-Activation-Trigger 5 byte
+
+# This is really a bitmap
+VALUE WiMAX-Activation-Trigger Reserved-0 0
+VALUE WiMAX-Activation-Trigger Provisioned 1
+VALUE WiMAX-Activation-Trigger Admit 2
+VALUE WiMAX-Activation-Trigger Activate 4
+VALUE WiMAX-Activation-Trigger Dynamically-Changeable 8
+
+ATTRIBUTE WiMAX-Transport-Type 6 byte
+
+VALUE WiMAX-Transport-Type Reserved-0 0
+VALUE WiMAX-Transport-Type IPv4-CS 1
+VALUE WiMAX-Transport-Type IPv6-CS 2
+VALUE WiMAX-Transport-Type Ethernet 3
+
+ATTRIBUTE WiMAX-Uplink-QOS-Id 7 byte
+ATTRIBUTE WiMAX-Downlink-QOS-Id 8 byte
+ATTRIBUTE WiMAX-Uplink-Classifier 9 string
+ATTRIBUTE WiMAX-Downlink-Classifier 10 string
+#ATTRIBUTE WiMAX-Paging-Preference 11 byte # Single bit, value => refer to 802.16e section 11.13.30
+END-TLV WiMAX-Packet-Flow-Descriptor
+
+ATTRIBUTE WiMAX-QoS-Descriptor 29 tlv
+
+BEGIN-TLV WiMAX-QoS-Descriptor
+ATTRIBUTE WiMAX-QoS-Id 1 byte
+ATTRIBUTE WiMAX-Global-Service-Class-Name 2 string # 6 octets
+ATTRIBUTE WiMAX-Service-Class-Name 3 string
+ATTRIBUTE WiMAX-Schedule-Type 4 byte
+ATTRIBUTE WiMAX-Traffic-Priority 5 byte
+ATTRIBUTE WiMAX-Maximum-Sustained-Traffic-Rate 6 integer
+ATTRIBUTE WiMAX-Minimum-Reserved-Traffic-Rate 7 integer
+ATTRIBUTE WiMAX-Maximum-Traffic-Burst 8 integer
+ATTRIBUTE WiMAX-Tolerated-Jitter 9 integer
+ATTRIBUTE WiMAX-Maximum-Latency 10 integer
+ATTRIBUTE WiMAX-Reduced-Resources-Code 11 byte
+ATTRIBUTE WiMAX-Media-Flow-Type 12 byte
+ATTRIBUTE WiMAX-Unsolicited-Grant-Interval 13 short
+ATTRIBUTE WiMAX-SDU-Size 14 short
+ATTRIBUTE WiMAX-Unsolicited-Polling-Interval 15 short
+ATTRIBUTE WiMAX-Media-Flow-Description-SDP 16 string
+
+VALUE WiMAX-Schedule-Type Best-Effort 2
+VALUE WiMAX-Schedule-Type nrtPS 3
+VALUE WiMAX-Schedule-Type rtPS 4
+VALUE WiMAX-Schedule-Type Extended-rtPS 5
+VALUE WiMAX-Schedule-Type UGS 6
+
+VALUE WiMAX-Media-Flow-Type VoIP 1
+VALUE WiMAX-Media-Flow-Type Robust-Browser 2
+VALUE WiMAX-Media-Flow-Type Secure-Browser-VPN 3
+VALUE WiMAX-Media-Flow-Type Streaming-Video 4
+VALUE WiMAX-Media-Flow-Type Streaming-Live-TV 5
+VALUE WiMAX-Media-Flow-Type Music-Photo-Download 6
+VALUE WiMAX-Media-Flow-Type Multi-Player-Gaming 7
+VALUE WiMAX-Media-Flow-Type Location-Based-Services 8
+VALUE WiMAX-Media-Flow-Type Text-Audio-Books 9
+VALUE WiMAX-Media-Flow-Type Video-Conversation 10
+VALUE WiMAX-Media-Flow-Type Message 11
+VALUE WiMAX-Media-Flow-Type Control 12
+VALUE WiMAX-Media-Flow-Type Data 13
+
+END-TLV WiMAX-QoS-Descriptor
+
+# Same as QoS-Descriptor... used only in interim and stop records for
+# flow based accounting.
+ATTRIBUTE WiMAX-Uplink-Granted-QoS 30 tlv # UPDATED - WAS STRING...
+ATTRIBUTE WiMAX-Control-Packets-In 31 integer
+ATTRIBUTE WiMAX-Control-Octets-In 32 integer
+ATTRIBUTE WiMAX-Control-Packets-Out 33 integer
+ATTRIBUTE WiMAX-Control-Octets-Out 34 integer
+ATTRIBUTE WiMAX-PPAC 35 tlv
+
+BEGIN-TLV WiMAX-PPAC
+ATTRIBUTE WiMAX-Available-In-Client 1 integer
+
+# Really a bitmap
+VALUE WiMAX-Available-In-Client Volume-Metering 1
+VALUE WiMAX-Available-In-Client Duration-Metering 2
+VALUE WiMAX-Available-In-Client Resource-Metering 4
+VALUE WiMAX-Available-In-Client Pools 8
+VALUE WiMAX-Available-In-Client Rating-Groups 0x10
+VALUE WiMAX-Available-In-Client Multi-Services 0x20
+VALUE WiMAX-Available-In-Client Tariff-Switch 0x40
+END-TLV WiMAX-PPAC
+
+ATTRIBUTE WiMAX-Session-Termination-Capability 36 integer
+
+# Really a bitmap
+VALUE WiMAX-Session-Termination-Capability Dynamic-Authorization 1
+
+ATTRIBUTE WiMAX-PPAQ 37 tlv
+
+BEGIN-TLV WiMAX-PPAQ
+ATTRIBUTE WiMAX-PPAQ-Quota-Identifier 1 octets
+ATTRIBUTE WiMAX-Volume-Quota 2 integer #kb
+ATTRIBUTE WiMAX-Volume-Threshold 3 integer #kb
+ATTRIBUTE WiMAX-Duration-Quota 4 integer #s
+ATTRIBUTE WiMAX-Duration-Threshold 5 integer #s
+ATTRIBUTE WiMAX-Resource-Quota 6 integer
+ATTRIBUTE WiMAX-Resource-Threshold 7 integer
+ATTRIBUTE WiMAX-Update-Reason 8 integer
+ATTRIBUTE WiMAX-Prepaid-Server 9 combo-ip
+ATTRIBUTE WiMAX-Service-Id 10 string
+ATTRIBUTE WiMAX-Rating-Group-Id 11 integer
+ATTRIBUTE WiMAX-Termination-Action 12 byte
+ATTRIBUTE WiMAX-Pool-Id 13 integer
+ATTRIBUTE WiMAX-Pool-Multiplier 14 integer
+ATTRIBUTE WiMAX-Requested-Action 15 byte
+ATTRIBUTE WiMAX-Check-Balance-Result 16 byte
+
+#
+# 4 octets - integer representing 1/10's of lowest currency (e.g. cents)
+# 4 octets - currency code as in ISO-4217
+# 1+ - UTF8 string containing text like "cost is $1 per minute"
+#
+ATTRIBUTE WiMAX-Cost-Information-AVP 17 octets
+
+VALUE WiMAX-Update-Reason Pre-Initialization 1
+VALUE WiMAX-Update-Reason Initial-Request 2
+VALUE WiMAX-Update-Reason Threshold-Reached 3
+VALUE WiMAX-Update-Reason Quota-Reached 4
+VALUE WiMAX-Update-Reason TITSU-Approaching 5
+VALUE WiMAX-Update-Reason Remote-Forced-Disconnect 6
+VALUE WiMAX-Update-Reason Client-Service-Termination 7
+VALUE WiMAX-Update-Reason Access-Service-Terminated 8
+VALUE WiMAX-Update-Reason Service-Not-Established 9
+VALUE WiMAX-Update-Reason One-Time-Charging 10
+
+VALUE WiMAX-Termination-Action Terminate 1
+VALUE WiMAX-Termination-Action Request-More-Quota 2
+VALUE WiMAX-Termination-Action Redirect-Or-Filter 3
+
+VALUE WiMAX-Requested-Action Balance-Check 1
+VALUE WiMAX-Requested-Action Price-Enquiry 2
+
+END-TLV WiMAX-PPAQ
+
+ATTRIBUTE WiMAX-Prepaid-Tariff-Switching 38 tlv
+
+BEGIN-TLV WiMAX-Prepaid-Tariff-Switching
+ATTRIBUTE WiMAX-Prepaid-Quota-Identifier 1 string
+ATTRIBUTE WiMAX-Volume-Used-After 2 integer #1k
+ATTRIBUTE WiMAX-Tariff-Switch-Interval 3 integer #s
+ATTRIBUTE WiMAX-Time-Interval-After 4 integer #s
+END-TLV WiMAX-Prepaid-Tariff-Switching
+
+ATTRIBUTE WiMAX-Active-Time-Duration 39 integer
+ATTRIBUTE WiMAX-DHCP-RK 40 octets encrypt=2
+ATTRIBUTE WiMAX-DHCP-RK-Key-Id 41 integer
+ATTRIBUTE WiMAX-DHCP-RK-Lifetime 42 integer
+ATTRIBUTE WiMAX-DHCP-Msg-Server-IP 43 ipaddr
+ATTRIBUTE WiMAX-Idle-Mode-Transition 44 byte
+ATTRIBUTE WiMAX-NAP-Id 45 octets
+
+# 3 octets of NAP Id
+# 3 octets of base-station Id
+ATTRIBUTE WiMAX-BS-Id 46 octets
+ATTRIBUTE WiMAX-Location 47 octets
+
+# Number of times Acct-Input-Packets rolled over 2^32.
+ATTRIBUTE WiMAX-Acct-Input-Packets-Gigaword 48 integer
+ATTRIBUTE WiMAX-Acct-Output-Packets-Gigaword 49 integer
+
+# Formatted as per IP Filter rule specification.
+ATTRIBUTE WiMAX-Uplink-Flow-Description 50 string
+
+ATTRIBUTE WiMAX-BU-CoA-IPv6 51 ipv6addr # Updated
+ATTRIBUTE WiMAX-DNS-Server 52 combo-ip
+ATTRIBUTE WiMAX-Hotline-Profile-Id 53 string
+
+# Formatted as per IP Filter rule specification.
+ATTRIBUTE WiMAX-HTTP-Redirection-Rule 54 string
+
+# Formatted as per IP Filter rule specification.
+ATTRIBUTE WiMAX-IP-Redirection-Rule 55 string
+ATTRIBUTE WiMAX-Hotline-Session-Timer 56 integer
+
+# 3 octets
+ATTRIBUTE WiMAX-NSP-Id 57 octets
+
+# WiMAX-HA-RK-Requested has been removed from WMF Release 1.3 and later.
+# However the attribute has not been replaced so this is left to preserve
+# backward compatibility. This attribute is deprecated and will be removed.
+ATTRIBUTE WiMAX-HA-RK-Key-Requested 58 integer
+
+VALUE WiMAX-HA-RK-Key-Requested No 0
+VALUE WiMAX-HA-RK-Key-Requested Yes 1
+
+ATTRIBUTE WiMAX-Count-Type 59 byte
+ATTRIBUTE WiMAX-DM-Action-Code 60 integer
+
+VALUE WiMAX-DM-Action-Code Deregister-MS 0
+VALUE WiMAX-DM-Action-Code Suspend-MS-Traffic 1
+VALUE WiMAX-DM-Action-Code Suspend-User-Traffic 2
+VALUE WiMAX-DM-Action-Code Resume-Traffic 3
+VALUE WiMAX-DM-Action-Code MS-Terminate 4
+VALUE WiMAX-DM-Action-Code MS-Idle 5
+VALUE WiMAX-DM-Action-Code MS-Completed-IPv6-Handover 6
+VALUE WiMAX-DM-Action-Code BS-Sends-RES-Cmd 0xffff
+
+# FA-RK-SPI = SPI-CMIP4 = MIP-SPI
+ATTRIBUTE WiMAX-FA-RK-SPI 61 integer
+
+# Formatted as per IP Filter rule specification.
+ATTRIBUTE WiMAX-Downlink-Flow-Description 62 string
+
+# Same as QoS-Descriptor... used only in flow based accounting.
+ATTRIBUTE WiMAX-Downlink-Granted-QoS 63 tlv
+
+# More MIP keys, calculated as above... but in different packets.
+# In a roaming scenario both the vAAA and the hAAA can provide a HA
+# and related key context, as well as DHCP server information to the ASN-GW.
+# These attributes are used by the vCSN.
+ATTRIBUTE WiMAX-vHA-IP-MIP4 64 ipaddr
+ATTRIBUTE WiMAX-vHA-IP-MIP6 65 ipv6addr
+ATTRIBUTE WiMAX-vHA-MIP4-Key 66 octets encrypt=2
+ATTRIBUTE WiMAX-vHA-RK-Key 67 octets encrypt=2
+ATTRIBUTE WiMAX-vHA-RK-SPI 68 integer
+ATTRIBUTE WiMAX-vHA-RK-Lifetime 69 integer
+
+ATTRIBUTE WiMAX-MN-vHA-MIP6-Key 70 octets encrypt=2
+ATTRIBUTE WiMAX-MN-vHA-MIP4-SPI 71 integer
+ATTRIBUTE WiMAX-MN-vHA-MIP6-SPI 72 integer
+
+ATTRIBUTE WiMAX-vDHCPv4-Server 73 ipaddr
+ATTRIBUTE WiMAX-vDHCPv6-Server 74 ipv6addr
+ATTRIBUTE WiMAX-vDHCP-RK 75 octets encrypt=2
+ATTRIBUTE WiMAX-vDHCP-RK-Key-ID 76 integer
+ATTRIBUTE WiMAX-vDHCP-RK-Lifetime 77 integer
+
+# About 10 more attributes in 1.3
+
+END-VENDOR WiMAX
diff --git a/share/dictionary.wispr b/share/dictionary.wispr
new file mode 100644
index 0000000..42f3707
--- /dev/null
+++ b/share/dictionary.wispr
@@ -0,0 +1,41 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# dictionary.wispr
+#
+# Attributes from the Wireless Broadband Alliance (used to be Wispr)
+#
+# Updated attributes are at
+#
+# https://github.com/wireless-broadband-alliance/RADIUS-VSA
+#
+# Version: $Id$
+#
+
+VENDOR WISPr 14122
+
+#
+# Standard attribute
+#
+BEGIN-VENDOR WISPr
+
+ATTRIBUTE WISPr-Location-ID 1 string
+ATTRIBUTE WISPr-Location-Name 2 string
+ATTRIBUTE WISPr-Logoff-URL 3 string
+ATTRIBUTE WISPr-Redirection-URL 4 string
+ATTRIBUTE WISPr-Bandwidth-Min-Up 5 integer
+ATTRIBUTE WISPr-Bandwidth-Min-Down 6 integer
+ATTRIBUTE WISPr-Bandwidth-Max-Up 7 integer
+ATTRIBUTE WISPr-Bandwidth-Max-Down 8 integer
+ATTRIBUTE WISPr-Session-Terminate-Time 9 string
+ATTRIBUTE WISPr-Session-Terminate-End-Of-Day 10 string
+ATTRIBUTE WISPr-Billing-Class-Of-Service 11 string
+
+ATTRIBUTE WBA-Offered-Service 12 string
+ATTRIBUTE WBA-Financial-Clearing-Provider 13 string
+ATTRIBUTE WBA-Data-Clearing-Provider 14 string
+ATTRIBUTE WBA-Linear-Volume-Rate 15 octets
+ATTRIBUTE WBA-Identity-Provider 16 string
+
+END-VENDOR WISPr
diff --git a/share/dictionary.xedia b/share/dictionary.xedia
new file mode 100644
index 0000000..d125e4e
--- /dev/null
+++ b/share/dictionary.xedia
@@ -0,0 +1,26 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# XEDIA, AP series routers
+# From Yard RADIUS, and Piotr Orlewicz, porlewicz@teleton.pl www.real-data.pl
+#
+# $Id$
+#
+#############################################################################
+VENDOR Xedia 838
+
+BEGIN-VENDOR Xedia
+
+ATTRIBUTE Xedia-DNS-Server 1 ipaddr
+ATTRIBUTE Xedia-NetBios-Server 2 ipaddr
+ATTRIBUTE Xedia-Address-Pool 3 string
+ATTRIBUTE Xedia-PPP-Echo-Interval 4 integer
+ATTRIBUTE Xedia-SSH-Privileges 5 integer
+ATTRIBUTE Xedia-Client-Access-Network 6 string
+ATTRIBUTE Xedia-Client-Firewall-Setting 7 integer
+ATTRIBUTE Xedia-Save-Password 8 integer
+
+END-VENDOR Xedia
diff --git a/share/dictionary.xylan b/share/dictionary.xylan
new file mode 100644
index 0000000..506bf04
--- /dev/null
+++ b/share/dictionary.xylan
@@ -0,0 +1,56 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Xylan dictionary
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR Xylan 800
+
+BEGIN-VENDOR Xylan
+
+ATTRIBUTE Xylan-Auth-Group 1 integer
+ATTRIBUTE Xylan-Slot-Port 2 string
+ATTRIBUTE Xylan-Time-of-Day 3 string
+ATTRIBUTE Xylan-Client-IP-Addr 4 ipaddr
+ATTRIBUTE Xylan-Group-Desc 5 string
+ATTRIBUTE Xylan-Port-Desc 6 string
+ATTRIBUTE Xylan-Profil-Numb 7 integer
+ATTRIBUTE Xylan-Auth-Group-Protocol 8 string
+ATTRIBUTE Xylan-Asa-Access 9 string
+ATTRIBUTE Xylan-End-User-Profile 10 integer
+ATTRIBUTE Xylan-Primary-Home-Agent 12 string
+ATTRIBUTE Xylan-Secondary-Home-Agent 13 string
+ATTRIBUTE Xylan-Home-Agent-Password 14 string
+ATTRIBUTE Xylan-Home-Network-Name 15 string
+ATTRIBUTE Xylan-Access-Priv 16 integer
+ATTRIBUTE Xylan-Nms-Group 20 string
+ATTRIBUTE Xylan-Nms-First-Name 21 string
+ATTRIBUTE Xylan-Nms-Last-Name 22 string
+ATTRIBUTE Xylan-Nms-Description 23 string
+ATTRIBUTE Xylan-Acce-Priv-R1 33 octets
+ATTRIBUTE Xylan-Acce-Priv-R2 34 octets
+ATTRIBUTE Xylan-Acce-Priv-W1 35 octets
+ATTRIBUTE Xylan-Acce-Priv-W2 36 octets
+ATTRIBUTE Xylan-Acce-Priv-G1 37 octets
+ATTRIBUTE Xylan-Acce-Priv-G2 38 octets
+ATTRIBUTE Xylan-Acce-Priv-F-R1 39 octets
+ATTRIBUTE Xylan-Acce-Priv-F-R2 40 octets
+ATTRIBUTE Xylan-Acce-Priv-F-W1 41 octets
+ATTRIBUTE Xylan-Acce-Priv-F-W2 42 octets
+
+ATTRIBUTE Xylan-Policy-List 100 string
+ATTRIBUTE Xylan-Redirect-Url 101 string
+ATTRIBUTE Xylan-Device-Name 152 string
+ATTRIBUTE Xylan-Device-Location 153 string
+
+VALUE Xylan-Access-Priv Xylan-Read-Priv 1
+VALUE Xylan-Access-Priv Xylan-Write-Priv 2
+VALUE Xylan-Access-Priv Xylan-Admin-Priv 3
+
+END-VENDOR Xylan
diff --git a/share/dictionary.yubico b/share/dictionary.yubico
new file mode 100644
index 0000000..a40ea55
--- /dev/null
+++ b/share/dictionary.yubico
@@ -0,0 +1,25 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Yubico VSA's
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR Yubico 41482
+
+BEGIN-VENDOR Yubico
+
+ATTRIBUTE Yubikey-Key 1 octets
+ATTRIBUTE Yubikey-Public-ID 2 string
+ATTRIBUTE Yubikey-Private-ID 3 octets
+ATTRIBUTE Yubikey-Counter 4 integer
+ATTRIBUTE Yubikey-Timestamp 5 integer
+ATTRIBUTE Yubikey-Random 6 integer
+ATTRIBUTE Yubikey-OTP 7 string
+
+END-VENDOR Yubico
diff --git a/share/dictionary.zeus b/share/dictionary.zeus
new file mode 100644
index 0000000..d3f5bbc
--- /dev/null
+++ b/share/dictionary.zeus
@@ -0,0 +1,18 @@
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# Zeus Packet RADIUS Dictionary
+#
+# http://www.zeus.com
+#
+#
+
+VENDOR Zeus 7146
+BEGIN-VENDOR Zeus
+
+#
+# ZXTM Group Attributes
+#
+ATTRIBUTE Zeus-ZXTM-Group 1 string
+
+END-VENDOR Zeus
diff --git a/share/dictionary.zte b/share/dictionary.zte
new file mode 100644
index 0000000..d7352c0
--- /dev/null
+++ b/share/dictionary.zte
@@ -0,0 +1,73 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+# For ZTE.
+#
+# $Id$
+#
+# QoS attributes Mostly derived from:
+# http://wwwen.zte.com.cn/en/products/bearer/201308/P020130828522349526032.pdf
+#
+VENDOR ZTE 3902
+BEGIN-VENDOR ZTE
+
+ATTRIBUTE ZTE-Client-DNS-Pri 1 string
+ATTRIBUTE ZTE-Client-DNS-Sec 2 string
+ATTRIBUTE ZTE-Context-Name 4 string
+ATTRIBUTE ZTE-Tunnel-Max-Sessions 21 integer
+ATTRIBUTE ZTE-Tunnel-Max-Tunnels 22 integer
+ATTRIBUTE ZTE-Tunnel-Window 24 integer
+ATTRIBUTE ZTE-Tunnel-Retransmit 25 integer
+ATTRIBUTE ZTE-Tunnel-Cmd-Timeout 26 integer
+ATTRIBUTE ZTE-PPPOE-URL 27 string
+ATTRIBUTE ZTE-PPPOE-MOTM 28 string
+ATTRIBUTE ZTE-Tunnel-Algorithm 31 integer
+ATTRIBUTE ZTE-Tunnel-Deadtime 32 integer
+ATTRIBUTE ZTE-Mcast-Send 33 integer
+ATTRIBUTE ZTE-Mcast-Receive 34 integer
+ATTRIBUTE ZTE-Mcast-MaxGroups 35 integer
+ATTRIBUTE ZTE-Access-Type 74 integer
+
+ATTRIBUTE ZTE-QoS-Type 81 integer
+ATTRIBUTE ZTE-QoS-Profile-Down 82 string
+ATTRIBUTE ZTE-Rate-Ctrl-SCR-Down 83 integer
+ATTRIBUTE ZTE-Rate-Ctrl-Burst-Down 84 integer
+ATTRIBUTE ZTE-Rate-Ctrl-PCR 86 integer
+ATTRIBUTE ZTE-TCP-Syn-Rate 88 integer
+ATTRIBUTE ZTE-Rate-Ctrl-SCR-Up 89 integer
+ATTRIBUTE ZTE-Priority-Level 90 integer
+ATTRIBUTE ZTE-Rate-Ctrl-Burst-Up 91 integer
+ATTRIBUTE ZTE-Rate-Ctrl-Burst-Max-Down 92 integer
+ATTRIBUTE ZTE-Rate-Ctrl-Burst-Max-Up 93 integer
+ATTRIBUTE ZTE-QOS-Profile-Up 94 string
+
+ATTRIBUTE ZTE-TCP-Limit-Num 95 integer
+ATTRIBUTE ZTE-TCP-Limit-Mode 96 integer
+ATTRIBUTE ZTE-IGMP-Service-Profile-Num 97 integer
+ATTRIBUTE ZTE-PPP-Sservice-Type 101 integer
+ATTRIBUTE ZTE-SW-Privilege 104 integer
+ATTRIBUTE ZTE-Access-Domain 151 string
+ATTRIBUTE ZTE-VPN-ID 190 string
+
+# 0 (lowest) - 15 (highest) privilege level
+#ATTRIBUTE ZTE-SW-Privilege 191 integer
+
+ATTRIBUTE ZTE_Rate-Bust-DPIR 191 integer
+ATTRIBUTE ZTE_Rate-Bust-UPIR 192 integer
+
+ATTRIBUTE ZTE-Rate-Ctrl-PBS-Down 202 integer
+ATTRIBUTE ZTE-Rate-Ctrl-PBS-Up 203 integer
+ATTRIBUTE ZTE-Rate-Ctrl-SCR-Up-v6 228 integer
+ATTRIBUTE ZTE-Rate-Ctrl-Burst-Up-v6 229 integer
+ATTRIBUTE ZTE-Rate-Ctrl-Burst-Max-Up-v6 230 integer
+ATTRIBUTE ZTE-Rate-Ctrl-PBS-Up-v6 231 integer
+ATTRIBUTE ZTE-QoS-Profile-Up-v6 232 string
+
+ATTRIBUTE ZTE-Rate-Ctrl-SCR-Down-v6 233 integer
+ATTRIBUTE ZTE-Rate-Ctrl-Burst-Down-v6 234 integer
+ATTRIBUTE ZTE-Rate-Ctrl-Burst-Max-Down-v6 235 integer
+ATTRIBUTE ZTE-Rate-Ctrl-PBS-Down-v6 236 integer
+ATTRIBUTE ZTE-QoS-Profile-Down-v6 237 string
+
+END-VENDOR ZTE
diff --git a/share/dictionary.zyxel b/share/dictionary.zyxel
new file mode 100644
index 0000000..3b60bb8
--- /dev/null
+++ b/share/dictionary.zyxel
@@ -0,0 +1,27 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+#
+##############################################################################
+#
+# Zyxel attributes, of course in the RFC space...
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR Zyxel 890
+BEGIN-VENDOR Zyxel
+
+ATTRIBUTE Zyxel-Privilege-AVPair 3 string
+ATTRIBUTE Zyxel-Callback-Option 192 integer
+ATTRIBUTE Zyxel-Callback-Phone-Source 193 integer
+
+VALUE Zyxel-Callback-Phone-Source Preconfigured 0
+VALUE Zyxel-Callback-Phone-Source User 1
+
+VALUE Zyxel-Callback-Option None 0
+VALUE Zyxel-Callback-Option Optional 1
+VALUE Zyxel-Callback-Option Mandatory 2
+
+END-VENDOR Zyxel
diff --git a/share/format.pl b/share/format.pl
new file mode 100755
index 0000000..10ef0ab
--- /dev/null
+++ b/share/format.pl
@@ -0,0 +1,235 @@
+#!/usr/bin/env perl
+#
+# Format the dictionaries according to a standard scheme.
+#
+# Usage: ./format.pl dictionary.foo
+#
+# We don't over-write the dictionaries in place, so that the process
+# can be double-checked by hand.
+#
+# This is a bit of a hack.
+#
+# FIXME: get lengths from variables, rather than hard-coding.
+#
+######################################################################
+#
+# 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) 2010 Alan DeKok <aland@freeradius.org>
+#
+######################################################################
+#
+# $Id$
+#
+
+$begin_vendor = 0;
+$blank = 0;
+
+while (@ARGV) {
+ $filename = shift;
+
+ open FILE, "<$filename" or die "Failed to open $filename: $!\n";
+
+ @output = ();
+
+ while (<FILE>) {
+ #
+ # Clear out trailing whitespace
+ #
+ s/[ \t]+$//;
+
+ #
+ # And CR's
+ #
+ s/\r//g;
+
+ #
+ # Suppress multiple blank lines
+ #
+ if (/^\s+$/) {
+ next if ($blank == 1);
+ $blank = 1;
+ push @output, "\n";
+ next;
+ }
+ $blank = 0;
+
+ s/\s*$/\n/;
+
+ #
+ # Suppress leading whitespace, so long as it's
+ # not followed by a comment..
+ #
+ s/^\s*([^#])/$1/;
+
+ #
+ # Remember the vendor
+ #
+ if (/^VENDOR\s+([-\w]+)\s+(\w+)(.*)/) {
+ $name=$1;
+ $len = length $name;
+ if ($len < 32) {
+ $lenx = 32 - $len;
+ $lenx += 7; # round up
+ $lenx /= 8;
+ $lenx = int $lenx;
+ $tabs = "\t" x $lenx;
+ } else {
+ $tabs = " ";
+ }
+ push @output, "VENDOR\t\t$name$tabs$2$3\n";
+ $vendor = $name;
+ next;
+ }
+
+ #
+ # Remember if we did begin-vendor.
+ #
+ if (/^BEGIN-VENDOR\s+([-\w]+)\s+([-=\w]+)/) {
+ $begin_vendor = 1;
+ if (!defined $vendor) {
+ $vendor = $1;
+ } elsif ($vendor ne $1) {
+ # do something smart
+ }
+
+ if (! $2) {
+ push @output, "BEGIN-VENDOR\t$vendor\n";
+ } else {
+ push @output, "BEGIN-VENDOR\t$vendor\t$2\n";
+ }
+ next;
+ }
+
+ #
+ # Get attribute.
+ #
+ if (/^ATTRIBUTE\s+([-\w]+)\s+([\w.]+)\s+(\w+)(.*)/) {
+ $name=$1;
+ $len = length $name;
+ if ($len < 40) {
+ $lenx = 40 - $len;
+ $lenx += 7; # round up
+ $lenx /= 8;
+ $lenx = int $lenx;
+ $tabs = "\t" x $lenx;
+ if ($tabs eq "") {
+ $tabs = " ";
+ }
+ } else {
+ $tabs = " ";
+ }
+
+ $value = $2;
+ $type = $3;
+ $stuff = $4;
+
+ #
+ # See if it's old format, with the vendor at the end of
+ # the line. If so, make it the new format.
+ #
+ if ($stuff =~ /$vendor/) {
+ if ($begin_vendor == 0) {
+ push @output, "BEGIN-VENDOR\t$vendor\n\n";
+ $begin_vendor = 1;
+ }
+ $stuff =~ s/$vendor//;
+ $stuff =~ s/\s+$//;
+ }
+
+ push @output, "ATTRIBUTE\t$name$tabs$value\t$type$stuff\n";
+ next;
+ }
+
+ #
+ # Values.
+ #
+ if (/^VALUE\s+([-\w]+)\s+([-\w\/,.]+)\s+(\w+)(.*)/) {
+ $attr=$1;
+ $len = length $attr;
+ if ($len < 32) {
+ $lenx = 32 - $len;
+ $lenx += 7; # round up
+ $lenx /= 8;
+ $lenx = int $lenx;
+ $tabsa = "\t" x $lenx;
+ if ($tabsa eq "") {
+ $tabsa = " ";
+ $len += 1;
+ } else {
+ $len -= $len % 8;
+ $len += 8 * length $tabsa;
+ }
+ } else {
+ $tabsa = " ";
+ $len += 1;
+ }
+
+ #
+ # For the code below, we assume that the attribute lengths
+ #
+ if ($len < 32) {
+ $lena = 0;
+ } else {
+ $lena = $len - 32;
+ }
+
+ $name = $2;
+ $len = length $name;
+ if ($len < 24) {
+ $lenx = 24 - $lena - $len;
+ $lenx += 7; # round up
+ $lenx /= 8;
+ $lenx = int $lenx;
+ $tabsn = "\t" x $lenx;
+ if ($tabsn eq "") {
+ $tabsn = " ";
+ }
+ } else {
+ $tabsn = " ";
+ }
+
+ push @output, "VALUE\t$attr$tabsa$name$tabsn$3$4\n";
+ next;
+ }
+
+ #
+ # Remember if we did this.
+ #
+ if (/^END-VENDOR/) {
+ $begin_vendor = 0;
+ }
+
+ #
+ # Everything else gets dumped out as-is.
+ #
+ push @output, $_;
+ }
+
+#
+# If we changed the format, print the end vendor, too.
+#
+ if ($begin_vendor) {
+ push @output, "\nEND-VENDOR\t$vendor\n";
+ }
+
+ close FILE;
+
+ open FILE, ">$filename" or die "Failed to open $filename: $!\n";
+
+ print FILE @output;
+
+ close FILE;
+}
diff --git a/site.yml b/site.yml
new file mode 100644
index 0000000..68ef72e
--- /dev/null
+++ b/site.yml
@@ -0,0 +1,17 @@
+site:
+ title: The FreeRADIUS project - Documentation
+content:
+ sources:
+ - url: .
+ branches: v3.2.x
+ start_path: doc/antora
+asciidoc:
+ attributes:
+ attribute-missing: skip
+ui:
+ bundle:
+ url: https://github.com/FreeRADIUS/freeradius-docs-ui/blob/master-releases/ui-bundle.zip?raw=true
+ snapshot: true
+output:
+ clean: true
+ dir: ./build/docsite
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
+ }
+}
diff --git a/suse/README.SuSE b/suse/README.SuSE
new file mode 100644
index 0000000..4aab7bd
--- /dev/null
+++ b/suse/README.SuSE
@@ -0,0 +1,14 @@
+
+Please note that the radiusd does run as user 'radiusd' and
+group 'radiusd' per default after installation.
+(/etc/raddb/radiusd.conf)
+This was done because of security reasons and is possible with many
+authentication types (users, LDAP, SQL ...)
+
+If you would like to use unix (shadow) authentication (Auth-Type = System)
+or PAM (Auth-Type = Pam) you have to change the values to run the daemon
+as user/group root:
+
+user = root
+group = root
+
diff --git a/suse/freeradius-server-rpmlintrc b/suse/freeradius-server-rpmlintrc
new file mode 100644
index 0000000..2fe82c7
--- /dev/null
+++ b/suse/freeradius-server-rpmlintrc
@@ -0,0 +1,7 @@
+#freeradius-server.x86_64: E: dir-or-file-in-var-run (Badness: 900) /var/run/radiusd
+#A file or directory in the package is located in /var/run. It's not permitted
+#for packages to install files in this directory as it might be created as
+#tmpfs during boot. Modify your package to create the necessary files during
+#runtime.
+
+addFilter("dir-or-file-in-var-run")
diff --git a/suse/freeradius-server-tmpfiles.conf b/suse/freeradius-server-tmpfiles.conf
new file mode 100644
index 0000000..ead7a2f
--- /dev/null
+++ b/suse/freeradius-server-tmpfiles.conf
@@ -0,0 +1 @@
+D /var/run/radiusd 0710 radiusd radiusd -
diff --git a/suse/freeradius.spec b/suse/freeradius.spec
new file mode 100644
index 0000000..893d4fe
--- /dev/null
+++ b/suse/freeradius.spec
@@ -0,0 +1,260 @@
+Name: freeradius-server
+Version: 3.2.3
+Release: 0
+License: GPLv2 ; LGPLv2.1
+Group: Productivity/Networking/Radius/Servers
+Provides: radiusd
+Provides: freeradius = %{version}
+Obsoletes: freeradius < %{version}
+Conflicts: radiusd-livingston radiusd-cistron icradius
+Url: http://www.freeradius.org/
+Summary: Very Highly Configurable Radius Server
+Source: ftp://ftp.freeradius.org/pub/freeradius/%{name}-%{version}.tar.bz2
+Source90: %{name}-rpmlintrc
+Source104: %{name}-tmpfiles.conf
+PreReq: %{_sbindir}/useradd %{_sbindir}/groupadd
+PreReq: perl
+PreReq: %insserv_prereq %fillup_prereq
+BuildRoot: %{_tmppath}/%{name}-%{version}-build
+%define _oracle_support 0
+Requires: %{name}-libs = %{version}
+Requires: python
+Recommends: logrotate
+BuildRequires: db-devel
+BuildRequires: gcc-c++
+BuildRequires: gdbm-devel
+BuildRequires: glibc-devel
+BuildRequires: libtalloc-devel
+BuildRequires: openldap2-devel
+BuildRequires: openssl
+BuildRequires: openssl-devel
+BuildRequires: pam-devel
+BuildRequires: perl
+BuildRequires: postgresql-devel
+BuildRequires: python-devel
+BuildRequires: sed
+BuildRequires: unixODBC-devel
+
+
+%if 0%{?suse_version} > 910
+BuildRequires: krb5-devel
+%endif
+%if 0%{?suse_version} > 930
+BuildRequires: libcom_err
+%endif
+%if 0%{?suse_version} > 1000
+BuildRequires: libapr1-devel
+%endif
+%if 0%{?suse_version} > 1020
+BuildRequires: libmysqlclient-devel
+%endif
+%if 0%{?suse_version} > 1100
+BuildRequires: libpcap-devel
+BuildRequires: sqlite3-devel
+%endif
+
+
+%description
+The FreeRADIUS server has a number of features found in other servers,
+and additional features not found in any other server. Rather than
+doing a feature by feature comparison, we will simply list the features
+of the server, and let you decide if they satisfy your needs.
+
+Support for RFC and VSA Attributes Additional server configuration
+attributes Selecting a particular configuration Authentication methods
+Accounting methods
+
+Authors:
+--------
+See http://wiki.freeradius.org/project/Acknowledgements
+
+%package libs
+License: GPLv2 ; LGPLv2.1
+Group: Productivity/Networking/Radius/Servers
+Summary: FreeRADIUS shared library
+
+%description libs
+The FreeRADIUS shared library
+
+Authors:
+--------
+See http://wiki.freeradius.org/project/Acknowledgements
+
+%package utils
+License: GPLv2 ; LGPLv2.1
+Group: Productivity/Networking/Radius/Clients
+Summary: FreeRADIUS Clients
+Requires: %{name}-libs = %{version}
+
+%description utils
+The FreeRADIUS server has a number of features found in other servers
+and additional features not found in any other server. Rather than
+doing a feature by feature comparison, we will simply list the features
+of the server, and let you decide if they satisfy your needs.
+
+Support for RFC and VSA Attributes Additional server configuration
+attributes Selecting a particular configuration Authentication methods
+
+%package devel
+License: GPLv2 ; LGPLv2.1
+Group: Development/Libraries/C and C++
+Summary: FreeRADIUS Development Files (static libs)
+Requires: %{name}-libs = %{version}
+
+%description devel
+These are the static libraries for the FreeRADIUS package.
+
+Authors:
+--------
+See http://wiki.freeradius.org/project/Acknowledgements
+
+%package doc
+License: GPLv2 ; LGPLv2.1
+Group: Productivity/Networking/Radius/Servers
+Summary: FreeRADIUS Documentation
+Requires: %{name}
+
+%description doc
+This package contains FreeRADIUS Documentation
+
+Authors:
+--------
+See http://wiki.freeradius.org/project/Acknowledgements
+
+%prep
+%setup -q
+
+%build
+# This package failed when testing with -Wl,-as-needed being default.
+# So we disable it here, if you want to retest, just delete this comment and the line below.
+export SUSE_ASNEEDED=0
+export CFLAGS="$RPM_OPT_FLAGS"
+%ifarch x86_64 ppc ppc64 s390 s390x
+export CFLAGS="$CFLAGS -fPIC -DPIC"
+%endif
+export LDFLAGS="-pie"
+%configure \
+ --libdir=%{_libdir}/freeradius \
+ --disable-developer \
+ --with-experimental-modules \
+ --with-udpfromto \
+%if 0%{?suse_version} <= 920
+ --without-rlm_sql_mysql \
+ --without-rlm_krb5 \
+%endif
+%if %{_oracle_support} == 1
+ --with-rlm_sql_oracle \
+ --with-oracle-lib-dir=%{_libdir}/oracle/10.1.0.3/client/lib/
+%else
+ --without-rlm_sql_oracle
+%endif
+make %{?_smp_mflags}
+
+%install
+rm -rf $RPM_BUILD_ROOT
+mkdir -p $RPM_BUILD_ROOT%{_localstatedir}/lib/radiusd
+make install R=$RPM_BUILD_ROOT
+# modify default configuration
+RADDB=$RPM_BUILD_ROOT%{_sysconfdir}/raddb
+perl -i -pe 's/^#user =.*$/user = radiusd/' $RADDB/radiusd.conf
+perl -i -pe 's/^#group =.*$/group = radiusd/' $RADDB/radiusd.conf
+/sbin/ldconfig -n $RPM_BUILD_ROOT%{_libdir}/freeradius
+# logs
+touch $RPM_BUILD_ROOT%{_localstatedir}/log/radius/radutmp
+touch $RPM_BUILD_ROOT%{_localstatedir}/log/radius/radius.log
+# SuSE
+install -d $RPM_BUILD_ROOT%{_sysconfdir}/pam.d
+install -d $RPM_BUILD_ROOT%{_sysconfdir}/logrotate.d
+install -m 644 suse/radiusd-pam $RPM_BUILD_ROOT%{_sysconfdir}/pam.d/radiusd
+install -m 644 suse/radiusd-logrotate $RPM_BUILD_ROOT%{_sysconfdir}/logrotate.d/freeradius-server
+install -d -m 755 $RPM_BUILD_ROOT%{_sysconfdir}/init.d
+install -m 744 suse/rcradiusd $RPM_BUILD_ROOT%{_sysconfdir}/init.d/freeradius
+ln -sf ../..%{_sysconfdir}/init.d/freeradius $RPM_BUILD_ROOT%{_sbindir}/rcfreeradius
+install -d %{buildroot}%{_sysconfdir}/tmpfiles.d
+install -m 0644 %{SOURCE104} %{buildroot}%{_sysconfdir}/tmpfiles.d/radiusd.conf
+# remove unneeded stuff
+rm -rf doc/00-OLD
+rm -f $RPM_BUILD_ROOT%{_sbindir}/rc.radiusd
+rm -rf $RPM_BUILD_ROOT/usr/share/doc/freeradius*
+rm -rf $RPM_BUILD_ROOT/%{_libdir}/freeradius/*.*a
+
+%pre
+%{_sbindir}/groupadd -r radiusd 2> /dev/null || :
+%{_sbindir}/useradd -r -g radiusd -s /bin/false -c "Radius daemon" -d \
+ %{_localstatedir}/lib/radiusd radiusd 2> /dev/null || :
+
+%post
+%ifarch x86_64
+# Modify old installs to look for /usr/lib64/freeradius
+/usr/bin/perl -i -pe "s:/usr/lib/freeradius:/usr/lib64/freeradius:" /etc/raddb/radiusd.conf
+%endif
+
+# Generate default certificates
+/etc/raddb/certs/bootstrap
+
+%{fillup_and_insserv freeradius}
+%if 0%{?suse_version} > 820
+
+%preun
+%stop_on_removal freeradius
+%endif
+
+%postun
+%if 0%{?suse_version} > 820
+%restart_on_update freeradius
+%endif
+%{insserv_cleanup}
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%files
+%defattr(-,root,root)
+# doc
+%doc suse/README.SuSE
+%doc doc/* LICENSE COPYRIGHT CREDITS README.rst
+# SuSE
+%{_sysconfdir}/init.d/freeradius
+%config %{_sysconfdir}/pam.d/radiusd
+%config %{_sysconfdir}/logrotate.d/freeradius-server
+%dir %{_sysconfdir}/tmpfiles.d
+%config %{_sysconfdir}/tmpfiles.d/radiusd.conf
+%dir %attr(755,radiusd,radiusd) %{_localstatedir}/lib/radiusd
+# configs
+%defattr(-,root,radiusd)
+%dir %attr(750,root,radiusd) %{_sysconfdir}/raddb
+%config(noreplace) %{_sysconfdir}/raddb/*
+%attr(700,radiusd,radiusd) %dir %{_localstatedir}/run/radiusd/
+# binaries
+%defattr(-,root,root)
+%{_sbindir}/*
+# man-pages
+%doc %{_mandir}/man1/*
+%doc %{_mandir}/man5/*
+%doc %{_mandir}/man8/*
+# dictionaries
+%attr(755,root,root) %dir /usr/share/freeradius
+/usr/share/freeradius/*
+# logs
+%attr(700,radiusd,radiusd) %dir %{_localstatedir}/log/radius/
+%attr(700,radiusd,radiusd) %dir %{_localstatedir}/log/radius/radacct/
+%attr(644,radiusd,radiusd) %{_localstatedir}/log/radius/radutmp
+%config(noreplace) %attr(600,radiusd,radiusd) %{_localstatedir}/log/radius/radius.log
+# RADIUS Loadable Modules
+%attr(755,root,root) %dir %{_libdir}/freeradius
+%attr(755,root,root) %{_libdir}/freeradius/rlm_*.so*
+
+%files utils
+%defattr(-,root,root)
+/usr/bin/*
+
+%files libs
+# RADIUS shared libs
+%attr(755,root,root) %dir %{_libdir}/freeradius
+%attr(755,root,root) %{_libdir}/freeradius/lib*.so*
+%attr(755,root,root) %{_libdir}/freeradius/proto*.so*
+
+%files devel
+%defattr(-,root,root)
+%dir /usr/include/freeradius
+%attr(644,root,root) /usr/include/freeradius/*.h
diff --git a/suse/radiusd-logrotate b/suse/radiusd-logrotate
new file mode 100644
index 0000000..5ebfcf3
--- /dev/null
+++ b/suse/radiusd-logrotate
@@ -0,0 +1,68 @@
+#
+# You can use this to rotate the /var/log/radius/* files, simply copy
+# it to /etc/logrotate.d/radiusd
+#
+
+#
+# The main server log
+#
+/var/log/radius/radius.log {
+ # Common options
+ dateext
+ maxage 365
+ rotate 99
+ missingok
+ compress
+ delaycompress
+ notifempty
+ su radiusd radiusd
+
+ copytruncate
+}
+
+
+#
+# Session monitoring utilities and SQL log files (in order)
+#
+/var/log/radius/checkrad.log /var/log/radius/radwatch.log
+/var/log/radius/sqllog.sql
+{
+ # Common options
+ dateext
+ maxage 365
+ rotate 99
+ missingok
+ compress
+ delaycompress
+ notifempty
+ su radiusd radiusd
+
+ nocreate
+ size=+2048k
+}
+
+
+#
+# There are different detail-rotating strategies you can use. One is
+# to write to a single detail file per IP and use the rotate config
+# below. Another is to write to a daily detail file per IP with:
+#
+# detailfile = ${radacctdir}/%{Client-IP-Address}/%Y%m%d-detail
+#
+# (or similar) in radiusd.conf, without rotation. If you go with the
+# second technique, you will need another cron job that removes old
+# detail files. You do not need to comment out the below for method #2.
+#
+/var/log/radius/radacct/*/detail {
+ # Common options
+ dateext
+ maxage 365
+ rotate 99
+ missingok
+ compress
+ delaycompress
+ notifempty
+ su radiusd radiusd
+
+ nocreate
+}
diff --git a/suse/radiusd-pam b/suse/radiusd-pam
new file mode 100644
index 0000000..6b70db4
--- /dev/null
+++ b/suse/radiusd-pam
@@ -0,0 +1,6 @@
+#%PAM-1.0
+auth requisite pam_nologin.so
+auth include common-auth
+account include common-account
+password include common-password
+session include common-session
diff --git a/suse/rcradiusd b/suse/rcradiusd
new file mode 100644
index 0000000..cb73614
--- /dev/null
+++ b/suse/rcradiusd
@@ -0,0 +1,138 @@
+#! /bin/sh
+# Copyright (c) 2001 SuSE GmbH Nuernberg, Germany.
+# 2002, 2003 SuSE Linux AG, Nuernberg, Germany.
+#
+# Author: Wolfgang Rosenauer, 2000-2003
+#
+# /etc/init.d/radiusd
+#
+# and symbolic its link
+#
+# /usr/bin/rcradiusd
+#
+### BEGIN INIT INFO
+# Provides: radiusd
+# Required-Start: $network $syslog $remotefs
+# Should-Start: $time ypbind smtp
+# Required-Stop: $syslog $remote_fs
+# Should-Stop: ypbind smtp
+# Default-Start: 3 5
+# Default-Stop: 0 1 2 6
+# Short-Description: RADIUS-Server
+# Description: Remote Authentication Dialin User Server
+### END INIT INFO
+
+. /etc/init.d/functions
+
+prog=radiusd
+
+[ -e /etc/sysconfig/$prog ] && . /etc/sysconfig/$prog
+
+exec=${exec:=/usr/sbin/$prog}
+config_dir=${config_dir:=/etc/raddb}
+
+test -x "$exec" || { echo "$exec not installed"; \
+ if [ "$1" = "stop" ]; then exit 0;
+ else exit 5; fi; }
+
+configtest() {
+ echo -n "Checking $prog configuration "
+ out=`$exec -Cxl stdout -d $config_dir`; retval=$?
+ out=`echo "${out}" | tail -n 1 | sed 's/^\s*ERROR:\s*\(.*\)\s*$/\1/'`
+
+ [ $retval -ne 0 ] && echo "$out" 1>&2
+
+ return $retval
+}
+
+rc_reset
+case "$1" in
+ start)
+ configtest || { rc_failed 150; rc_exit; }
+ echo -n "Starting RADIUS daemon "
+ startproc $exec >/dev/null
+ rc_status -v
+ ;;
+
+ stop)
+ echo -n "Shutting down RADIUS daemon "
+ killproc -TERM $exec
+ rc_status -v
+ ;;
+
+ try-restart|condrestart)
+ # If first returns OK call the second, if first or second command fails, set echo return value.
+ if test "$1" = "condrestart"; then
+ echo "${attn} Use try-restart ${done}(LSB)${attn} rather than condrestart ${warn}(RH)${norm}"
+ fi
+ $0 status
+ if [ $? = 0 ] ; then
+ $0 restart
+ else
+ rc_reset # Not running is not a failure.
+ fi
+ rc_status
+ ;;
+
+ restart)
+ # Stop the service and regardless of whether it was running or not, start it again.
+ configtest || { rc_failed 150; rc_exit; }
+ $0 stop
+ $0 start
+ rc_status
+ ;;
+
+ force-reload)
+ # Signal the daemon to reload its config. Most daemons o this on signal 1 (SIGHUP).
+ # If it does not support it, restart.
+ configtest || { rc_failed 150; rc_exit; }
+ echo -n "Reload RADIUS daemon "
+ killproc -HUP $exec
+ rc_status -v
+ ;;
+
+ reload)
+ # Like force-reload, but if daemon does not support signalling, do nothing (!)
+ configtest || { rc_failed 150; rc_exit; }
+ echo -n "Reload RADIUS daemon "
+ killproc -HUP $exec
+ rc_status -v
+ ;;
+
+ status)
+ echo -n "Checking for service radiusd "
+ checkproc $exec
+ rc_status -v
+ ;;
+
+ configtest|testconfig)
+ configtest
+ rc_status -v
+ ;;
+
+ debug)
+ $0 status
+ if [ $? -eq 0 ]; then
+ echo -n "$prog already running; for live debugging see raddebug(8)"
+ exit 151
+ fi
+ $exec -X -d "$config_dir" || exit $?
+ exit 0
+ ;;
+
+ debug-threaded)
+ $0 status
+ if [ $? -eq 0 ]; then
+ echo -n "$prog already running; for live debugging see raddebug(8)"
+ exit 151
+ fi
+ $exec -f -xx -l stdout -d "$config_dir" || exit $?
+ exit 0
+ ;;
+
+ *)
+ echo "Usage: $0 {start|stop|status|try-restart|restart|force-reload|reload|configtest|debug|debug-threaded}"
+ exit 1
+ ;;
+esac
+rc_exit