From a85df854d233e10954c6dcb2ec8b26e6f2612732 Mon Sep 17 00:00:00 2001 From: eabdullin Date: Tue, 11 Nov 2025 08:52:30 +0000 Subject: [PATCH] import CS freeradius-3.2.5-5.el10 --- .freeradius.metadata | 1 - .gitignore | 2 +- ...eradius-FIPS-exit-if-md5-not-allowed.patch | 39 - ...radius-Fix-resource-hard-limit-error.patch | 32 - ...ix-segfault-when-home_server-is-null.patch | 51 - ...-unterminated-strings-in-SQL-queries.patch | 41 - SOURCES/freeradius-blastradius-fix.patch | 1502 --- .../freeradius-bootstrap-fixed-dhparam.patch | 52 - .../freeradius-bootstrap-run-only-once.patch | 72 - ...us-fix-crash-on-invalid-abinary-data.patch | 47 - ...freeradius-fix-crash-unknown-eap-sim.patch | 115 - .../freeradius-fix-info-leakage-eap-pwd.patch | 76 - ...ixes-to-python3-module-since-v3.0.20.patch | 1955 ---- SOURCES/freeradius-man-Fix-some-typos.patch | 93 - .../freeradius-no-dh-param-load-FIPS.patch | 45 - SOURCES/rfc3526-group-18-8192.pem | 24 - ...nfiguration-to-fit-Red-Hat-specifics.patch | 0 ...-Use-system-crypto-policy-by-default.patch | 35 +- ... => freeradius-bootstrap-create-only.patch | 22 +- ...reeradius-bootstrap-make-permissions.patch | 0 freeradius-configure-c99.patch | 35 + freeradius-disable-openssl-engine.patch | 55 + freeradius-disable-perl-script.patch | 22 + freeradius-ease-openssl-version-check.patch | 35 + ...us-ldap-infinite-timeout-on-starttls.patch | 31 + ...eeradius-logrotate => freeradius-logrotate | 1 - freeradius-no-antora-docs.patch | 9267 +++++++++++++++++ ... => freeradius-no-buildtime-cert-gen.patch | 50 +- freeradius-no-sql-scripts.patch | 31 + ...freeradius-pam-conf => freeradius-pam-conf | 0 ...-tmpfiles.conf => freeradius-tmpfiles.conf | 0 SPECS/freeradius.spec => freeradius.spec | 547 +- freeradius.sysusers | 3 + SOURCES/radiusd.service => radiusd.service | 1 - sources | 1 + 35 files changed, 9891 insertions(+), 4392 deletions(-) delete mode 100644 .freeradius.metadata delete mode 100644 SOURCES/freeradius-FIPS-exit-if-md5-not-allowed.patch delete mode 100644 SOURCES/freeradius-Fix-resource-hard-limit-error.patch delete mode 100644 SOURCES/freeradius-Fix-segfault-when-home_server-is-null.patch delete mode 100644 SOURCES/freeradius-Fix-unterminated-strings-in-SQL-queries.patch delete mode 100644 SOURCES/freeradius-blastradius-fix.patch delete mode 100644 SOURCES/freeradius-bootstrap-fixed-dhparam.patch delete mode 100644 SOURCES/freeradius-bootstrap-run-only-once.patch delete mode 100644 SOURCES/freeradius-fix-crash-on-invalid-abinary-data.patch delete mode 100644 SOURCES/freeradius-fix-crash-unknown-eap-sim.patch delete mode 100644 SOURCES/freeradius-fix-info-leakage-eap-pwd.patch delete mode 100644 SOURCES/freeradius-fixes-to-python3-module-since-v3.0.20.patch delete mode 100644 SOURCES/freeradius-man-Fix-some-typos.patch delete mode 100644 SOURCES/freeradius-no-dh-param-load-FIPS.patch delete mode 100644 SOURCES/rfc3526-group-18-8192.pem rename SOURCES/freeradius-Adjust-configuration-to-fit-Red-Hat-specifics.patch => freeradius-Adjust-configuration-to-fit-Red-Hat-specifics.patch (100%) rename SOURCES/freeradius-Use-system-crypto-policy-by-default.patch => freeradius-Use-system-crypto-policy-by-default.patch (76%) rename SOURCES/freeradius-bootstrap-create-only.patch => freeradius-bootstrap-create-only.patch (87%) rename SOURCES/freeradius-bootstrap-make-permissions.patch => freeradius-bootstrap-make-permissions.patch (100%) create mode 100644 freeradius-configure-c99.patch create mode 100644 freeradius-disable-openssl-engine.patch create mode 100644 freeradius-disable-perl-script.patch create mode 100644 freeradius-ease-openssl-version-check.patch create mode 100644 freeradius-ldap-infinite-timeout-on-starttls.patch rename SOURCES/freeradius-logrotate => freeradius-logrotate (99%) create mode 100644 freeradius-no-antora-docs.patch rename SOURCES/freeradius-no-buildtime-cert-gen.patch => freeradius-no-buildtime-cert-gen.patch (75%) create mode 100644 freeradius-no-sql-scripts.patch rename SOURCES/freeradius-pam-conf => freeradius-pam-conf (100%) rename SOURCES/freeradius-tmpfiles.conf => freeradius-tmpfiles.conf (100%) rename SPECS/freeradius.spec => freeradius.spec (86%) create mode 100644 freeradius.sysusers rename SOURCES/radiusd.service => radiusd.service (91%) create mode 100644 sources diff --git a/.freeradius.metadata b/.freeradius.metadata deleted file mode 100644 index 69b8b0b..0000000 --- a/.freeradius.metadata +++ /dev/null @@ -1 +0,0 @@ -3dd0e18fa04aff410876309e4322313b700db2b7 SOURCES/freeradius-server-3.0.20.tar.bz2 diff --git a/.gitignore b/.gitignore index 87a728a..b647e7f 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/freeradius-server-3.0.20.tar.bz2 +freeradius-server-3.2.5.tar.bz2 diff --git a/SOURCES/freeradius-FIPS-exit-if-md5-not-allowed.patch b/SOURCES/freeradius-FIPS-exit-if-md5-not-allowed.patch deleted file mode 100644 index 6c677b9..0000000 --- a/SOURCES/freeradius-FIPS-exit-if-md5-not-allowed.patch +++ /dev/null @@ -1,39 +0,0 @@ -Author: Antonio Torres -Date: Fri Jul 2 07:12:48 2021 -0400 -Subject: [PATCH] exit if host in FIPS mode and MD5 not explicitly allowed - - FIPS does not allow MD5, which FreeRADIUS needs to work. The user should - explicitly allow MD5 usage by setting the RADIUS_MD5_FIPS_OVERRIDE environment - variable to 1 or else FR should exit at start. - - Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1958979 - Signed-off-by: Antonio Torres antorres@redhat.com ---- - src/main/radiusd.c | 14 ++++++++++++++ - 1 file changed, 14 insertions(+) - -diff --git a/src/main/radiusd.c b/src/main/radiusd.c -index 9739514509..58a48895e6 100644 ---- a/src/main/radiusd.c -+++ b/src/main/radiusd.c -@@ -298,6 +298,20 @@ int main(int argc, char *argv[]) - exit(EXIT_FAILURE); - } - -+ /* -+ * If host is in FIPS mode, we need the user to explicitly allow MD5 usage. -+ */ -+ char *fips_md5_override = getenv("RADIUS_MD5_FIPS_OVERRIDE"); -+ FILE *fips_file = fopen("/proc/sys/crypto/fips_enabled", "r"); -+ if (fips_file != NULL) { -+ int fips_enabled = fgetc(fips_file) - '0'; -+ fclose(fips_file); -+ if (fips_enabled == 1 && (fips_md5_override == NULL || atoi(fips_md5_override) != 1)) { -+ fprintf(stderr, "Cannot run FreeRADIUS in FIPS mode because it uses MD5. To allow MD5 usage, set RADIUS_MD5_FIPS_OVERRIDE=1 before starting FreeRADIUS.\n"); -+ 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. diff --git a/SOURCES/freeradius-Fix-resource-hard-limit-error.patch b/SOURCES/freeradius-Fix-resource-hard-limit-error.patch deleted file mode 100644 index 800c06c..0000000 --- a/SOURCES/freeradius-Fix-resource-hard-limit-error.patch +++ /dev/null @@ -1,32 +0,0 @@ -commit 1ce4508c92493cf03ea1b3c42e83540b387884fa -Author: Antonio Torres -Date: Fri Jul 2 07:12:48 2021 -0400 -Subject: [PATCH] debug: don't set resource hard limit to zero - - Setting the resource hard limit to zero is irreversible, meaning if it - is set to zero then there is no way to set it higher. This means - enabling core dump is not possible, since setting a new resource limit - for RLIMIT_CORE would fail. By only setting the soft limit to zero, we - can disable and enable core dumps without failures. - - This fix is present in both main and 3.0.x upstream branches. - - Ticket in RHEL Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1977572 - Signed-off-by: Antonio Torres antorres@redhat.com ---- - src/lib/debug.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/lib/debug.c b/src/lib/debug.c -index 576bcb2a65..6330c9cb66 100644 ---- a/src/lib/debug.c -+++ b/src/lib/debug.c -@@ -599,7 +599,7 @@ int fr_set_dumpable(bool allow_core_dumps) - struct rlimit no_core; - - no_core.rlim_cur = 0; -- no_core.rlim_max = 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)); diff --git a/SOURCES/freeradius-Fix-segfault-when-home_server-is-null.patch b/SOURCES/freeradius-Fix-segfault-when-home_server-is-null.patch deleted file mode 100644 index bd482f7..0000000 --- a/SOURCES/freeradius-Fix-segfault-when-home_server-is-null.patch +++ /dev/null @@ -1,51 +0,0 @@ -From e2de6fab148e800380f1929fe4ea88a38de42053 Mon Sep 17 00:00:00 2001 -From: "Alan T. DeKok" -Date: Wed, 20 Nov 2019 13:59:54 -0500 -Subject: [PATCH] a better fix for commit 30ffd21 - -Which still runs post-proxy-type fail if all of the home servers -are dead - -[antorres@redhat.com: solved in FR 3.0.21, resolves bz#2030173] -[antorres@redhat.com: removed first hunk of commit, already present] ---- - src/main/process.c | 9 +++------ - 1 file changed, 3 insertions(+), 6 deletions(-) - -diff --git a/src/main/process.c b/src/main/process.c -index c8b3af24e2..1a48517d43 100644 ---- a/src/main/process.c -+++ b/src/main/process.c -@@ -2475,13 +2474,12 @@ static int process_proxy_reply(REQUEST *request, RADIUS_PACKET *reply) - } - - old_server = request->server; -- rad_assert(request->home_server != NULL); - - /* - * If the home server is virtual, just run pre_proxy from - * that section. - */ -- if (request->home_server->server) { -+ if (request->home_server && request->home_server->server) { - request->server = request->home_server->server; - - } else { -@@ -3182,13 +3180,12 @@ do_home: - } - - old_server = request->server; -- rad_assert(request->home_server != NULL); - - /* - * If the home server is virtual, just run pre_proxy from - * that section. - */ -- if (request->home_server->server) { -+ if (request->home_server && request->home_server->server) { - request->server = request->home_server->server; - - } else { --- -2.31.1 - diff --git a/SOURCES/freeradius-Fix-unterminated-strings-in-SQL-queries.patch b/SOURCES/freeradius-Fix-unterminated-strings-in-SQL-queries.patch deleted file mode 100644 index 76b0a59..0000000 --- a/SOURCES/freeradius-Fix-unterminated-strings-in-SQL-queries.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 3fd832baf898fe6d6f974cd2d36d1c5206bc2209 Mon Sep 17 00:00:00 2001 -From: Antonio Torres -Date: Fri, 12 Nov 2021 16:23:05 +0100 -Subject: [PATCH] Fix unterminated strings in SQL queries - -Resolves: bz#2021247 -Signed-off-by: Antonio Torres ---- - raddb/mods-config/sql/ippool/mysql/queries.conf | 2 +- - raddb/mods-config/sql/ippool/sqlite/queries.conf | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) - -diff --git a/raddb/mods-config/sql/ippool/mysql/queries.conf b/raddb/mods-config/sql/ippool/mysql/queries.conf -index 2dfc6574dd..444812a047 100644 ---- a/raddb/mods-config/sql/ippool/mysql/queries.conf -+++ b/raddb/mods-config/sql/ippool/mysql/queries.conf -@@ -114,7 +114,7 @@ allocate_update = "\ - 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' -+ WHERE framedipaddress = '%I'" - - # - # Use a stored procedure to find AND allocate the address. Read and customise -diff --git a/raddb/mods-config/sql/ippool/sqlite/queries.conf b/raddb/mods-config/sql/ippool/sqlite/queries.conf -index 31a5df3659..e92466108b 100644 ---- a/raddb/mods-config/sql/ippool/sqlite/queries.conf -+++ b/raddb/mods-config/sql/ippool/sqlite/queries.conf -@@ -89,7 +89,7 @@ allocate_update = "\ - callingstationid = '%{Calling-Station-Id}', \ - username = '%{User-Name}', \ - expiry_time = datetime(strftime('%%s', 'now') + ${lease_duration}, 'unixepoch') \ -- WHERE framedipaddress = '%I' -+ WHERE framedipaddress = '%I'" - - # - # This series of queries frees an IP number when an accounting START record arrives --- -2.31.1 - diff --git a/SOURCES/freeradius-blastradius-fix.patch b/SOURCES/freeradius-blastradius-fix.patch deleted file mode 100644 index 9b64838..0000000 --- a/SOURCES/freeradius-blastradius-fix.patch +++ /dev/null @@ -1,1502 +0,0 @@ -From: Antonio Torres -Date: Thu, 11 Jul, 2024 -Subject: Backport fix for BlastRADIUS - -Manual backport from v3.0.x branch, commit range 3a00a6ecc188629b0441fd45ad61ca8986de156e..da643f1edc267ce95260dc36069e6f1a7a4d66f8 - -Resolves: RHEL-46572 -Signed-off-by: Antonio Torres ---- - man/man1/radclient.1 | 10 ++- - man/man1/radtest.1 | 11 ++- - raddb/clients.conf | 47 +++++++++--- - raddb/proxy.conf | 19 +++++ - raddb/radiusd.conf.in | 185 ++++++++++++++++++++++++++++++++++++++++++++++++ - src/include/clients.h | 6 +- - src/include/conffile.h | 1 + - src/include/libradius.h | 19 ++++- - src/include/radius.h | 1 + - src/include/radiusd.h | 6 ++ - src/include/realms.h | 1 + - src/lib/radius.c | 87 ++++++++++++++++++++--- - src/main/client.c | 45 ++++++++++-- - src/main/conffile.c | 4 +- - src/main/listen.c | 141 +++++++++++++++++++++++++++++++++++- - src/main/mainconfig.c | 70 ++++++++++++++++++ - src/main/process.c | 65 +++++++++++++++++ - src/main/radclient.c | 147 +++++++++++++++++++++++++++++++++++++- - src/main/radtest.in | 6 +- - src/main/realms.c | 11 +++ - src/main/tls_listen.c | 5 ++ - 21 files changed, 855 insertions(+), 32 deletions(-) - -diff --git a/man/man1/radclient.1 b/man/man1/radclient.1 -index 229dcae0c7..b83bee931a 100644 ---- a/man/man1/radclient.1 -+++ b/man/man1/radclient.1 -@@ -1,10 +1,11 @@ --.TH RADCLIENT 1 "22 March 2019" "" "FreeRADIUS Daemon" -+.TH RADCLIENT 1 "21 May 2024" "" "FreeRADIUS Daemon" - .SH NAME - radclient - send packets to a RADIUS server, show reply - .SH SYNOPSIS - .B radclient - .RB [ \-4 ] - .RB [ \-6 ] -+.RB [ \-b ] - .RB [ \-c - .IR count ] - .RB [ \-d -@@ -52,6 +53,13 @@ automatically encrypted before the packet is sent to the server. - Use IPv4 (default) - .IP \-6 - Use IPv6 -+.IP \-b -+Enforce the Blast RADIUS checks. All replies to an Access-Request packet -+must contain a Message-Authenticator as the first attribute. -+ -+For compatibility with old servers, this flag is not set by default. -+However, radclient still checks for the Blast RADIUS signature, and -+discards packets which match the attack. - .IP \-c\ \fIcount\fP - Send each packet \fIcount\fP times. - .IP \-d\ \fIraddb_directory\fP -diff --git a/man/man1/radtest.1 b/man/man1/radtest.1 -index b3184779c0..db32e7f68d 100644 ---- a/man/man1/radtest.1 -+++ b/man/man1/radtest.1 -@@ -1,4 +1,4 @@ --.TH RADTEST 1 "5 April 2010" "" "FreeRADIUS Daemon" -+.TH RADTEST 1 "21 May 2024" "" "FreeRADIUS Daemon" - .SH NAME - radtest - send packets to a RADIUS server, show reply - .SH SYNOPSIS -@@ -15,6 +15,8 @@ radtest - send packets to a RADIUS server, show reply - .IR ] - .RB [ \-6 - .IR ] -+.RB [ \-b -+.IR ] - .I user password radius-server nas-port-number secret - .RB [ ppphint ] - .RB [ nasname ] -@@ -26,6 +28,13 @@ way to test a radius server. - - .SH OPTIONS - -+.IP \-b -+Enforce the Blast RADIUS checks. All replies to an Access-Request packet -+must contain a Message-Authenticator as the first attribute. -+ -+For compatibility with old servers, this flag is not set by default. -+However, radclient still checks for the Blast RADIUS signature, and -+discards packets which match the attack. - .IP "\-d \fIraddb_directory\fP" - The directory that contains the RADIUS dictionary files. Defaults to - \fI/etc/raddb\fP. -diff --git a/raddb/clients.conf b/raddb/clients.conf -index 76b300d3c5..d55414b7d2 100644 ---- a/raddb/clients.conf -+++ b/raddb/clients.conf -@@ -100,15 +100,44 @@ client localhost { - 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 global configuration "security.require_message_authenticator" -+ # flag sets the default for all clients. That default can be -+ # over-ridden here, by setting it to a value. If no value is set, -+ # then the default from the "radiusd.conf" file is used. -+ # -+ # See that file for full documentation on the flag, along -+ # with allowed values and meanings. -+ # -+ # This flag exists solely for legacy clients which do not send -+ # Message-Authenticator in all Access-Request packets. We do not -+ # recommend setting it to "no". -+ # -+ # The number one way to protect yourself from the BlastRADIUS -+ # attack is to update all RADIUS servers, and then set this -+ # flag to "yes". If all RADIUS servers are updated, and if -+ # all of them have this flag set to "yes" for all clients, -+ # then your network is safe. You can then upgrade the -+ # clients when it is convenient, instead of rushing the -+ # upgrades. -+ # -+ # allowed values: yes, no, auto -+# require_message_authenticator = no -+ -+ # -+ # The global configuration "security.limit_proxy_state" -+ # flag sets the default for all clients. That default can be -+ # over-ridden here, by setting it to "no". -+ # -+ # See that file for full documentation on the flag, along -+ # with allowed values,and meanings. -+ # -+ # This flag exists solely for legacy clients which do not send -+ # Message-Authenticator in all Access-Request packets. We do not -+ # recommend setting it to "no". -+ # -+ # allowed values: yes, no, auto -+ # -+# limit_proxy_state = yes - - # - # The short name is used as an alias for the fully qualified -diff --git a/raddb/proxy.conf b/raddb/proxy.conf -index 91b4b37930..fa362b8a74 100644 ---- a/raddb/proxy.conf -+++ b/raddb/proxy.conf -@@ -204,6 +204,25 @@ home_server localhost { - # - secret = testing123 - -+ -+ # -+ # The global configuration "security.require_message_authenticator" -+ # flag sets the default for all home servers. That default can be -+ # over-ridden here, by setting it to a value. If no value is set, -+ # then the default from the "radiusd.conf" file is used. -+ # -+ # See that file for full documentation on the flag, along -+ # with allowed values and meanings. -+ # -+ # This flag exists solely for legacy home servers which do -+ # not send Message-Authenticator in all Access-Accept, -+ # Access-Reject, or Access-Challenge packets. We do not -+ # recommend setting it to "no". -+ # -+ # allowed values: yes, no, auto -+ # -+# require_message_authenticator = no -+ - ############################################################ - # - # The rest of the configuration items listed here are optional, -diff --git a/raddb/radiusd.conf.in b/raddb/radiusd.conf.in -index e8aee3c001..6fa9ded0f9 100644 ---- a/raddb/radiusd.conf.in -+++ b/raddb/radiusd.conf.in -@@ -564,6 +564,191 @@ security { - # - status_server = yes - -+ # -+ # Global configuration for requiring Message-Authenticator in -+ # all Access-* packets sent over UDP or TCP. This flag is -+ # ignored for TLS. -+ # -+ # The number one way to protect yourself from the BlastRADIUS -+ # attack is to update all RADIUS servers, and then set this -+ # flag to "yes". If all RADIUS servers are updated, and if -+ # all of them have this flag set to "yes" for all clients, -+ # then your network is safe. You can then upgrade the -+ # clients when it is convenient, instead of rushing the -+ # upgrades. -+ # -+ # This flag sets the global default for all clients and home -+ # servers. It can be over-ridden in an individual client or -+# home_server definition by adding the same flag to that -+ # section with an appropriate value. -+ # -+ # All upgraded RADIUS implementations should send -+ # Message-Authenticator in all Access-Request, Access-Accept, -+ # Access-Reject, and Access-Challenge packets. Once all -+ # systems are upgraded, setting this flag to "yes" is the -+ # best protection from the attack. -+ # -+ # The possible values and meanings for -+ # "require_message_authenticator" are; -+ # -+ # * "no" - allow Access-* packet which do not contain -+ # Message-Authenticator -+ # -+ # For a client, if this flag is set to "no", then the -+ # "limit_proxy_state" flag, below, is also checked. -+ # -+ # For a home_server, if this flag is set to "no", then the -+ # Access-Accept, Access-Reject, and Access-Challenge -+ # packets do not need to contain Message-Authenticator. -+ # -+ # The only reason to set this flag to "no" is when the -+ # RADIUS client or home server has not been updated. It is -+ # always safer to set this flag "no" in the individual -+ # client or home_server definition. The global flag SHOULD -+ # still be set to a safe value: "yes". -+ # -+ # WARNING: Setting this flag and the "limit_proxy_state" -+ # flag to "no" will allow MITM attackers to create fake -+ # Access-Accept packets to the NAS! At least one of them -+ # MUST be set to "yes" for the system to have any -+ # protection against the attack. -+ # -+ # * "yes" - Require that all Access-* packets (client and -+ # home_server) contain Message-Authenticator. If a packet -+ # does not contain Message-Authenticator, then it is -+ # discarded. -+ # -+ # * "auto" - Automatically determine the value of the flag, -+ # based on the first packet received from that client or -+ # home_server. -+ # -+ # If the packet does not contain Message-Authenticator, -+ # then the value of the flag is automatically switched to -+ # "no". -+ # -+ # If the packet contains Message-Authenticator but not -+ # EAP-Message, then the value of the flag is automatically -+ # switched to "yes". The server has to check for -+ # EAP-Message, because the previous RFCs require that the -+ # packet contains Message-Authenticator when it also -+ # contains EAP-Message. So having a Message-Authenticator -+ # in those packets doesn't give the server enough -+ # information to determined if the client or home_server -+ # has been updated. -+ # -+ # If the packet contains Message-Authenticator and -+ # EAP-Message, then the flag is left at the "auto" value. -+ # -+ # WARNING: This switch is done for the first packet -+ # received from that client or home server. The change -+ # does NOT persist across server restarts. You MUST change -+ # the to "yes" manually, in order to make a permanent -+ # change to the configuration. -+ # -+ # WARNING: If there are multiple NASes with the same source -+ # IP and client definitions, BUT the NASes have different -+ # behavior, then this flag WILL LIKELY BREAK YOUR NETWORK. -+ # -+ # That is, when there are multiple different RADIUS clients -+ # behind one NATed IP address, then these security settings -+ # have to be set to allow the MOST INSECURE packets to be -+ # processed. This is a terrible idea, and will leave your -+ # network vulnerable to the attack. Please upgrade all -+ # clients immediately. -+ # -+ # The only solution to that rare configuration is to set -+ # this flag to "no", in which case the network will work, -+ # but will be vulnerable to the attack. -+ # -+ require_message_authenticator = auto -+ -+ # -+ # Global configuration for limiting the combination of -+ # Proxy-State and Message-Authenticator. This flag only -+ # applies to packets sent over UDP or TCP. This flag is -+ # ignored for TLS. -+ # -+ # This flag sets the global default for all clients. It can -+ # be over-ridden in an individual client definition by adding -+ # the same flag to that section with an appropriate value. -+ # -+ # If "require_message_authenticator" is set to "yes", this -+ # configuration item is ignored. -+ # -+ # If "require_message_authenticator" is set to "no", this -+ # configuration item is checked. -+ # -+# The possible values and meanings for "limit_proxy_state" are; -+ # -+ # * "no" - allow any packets from the client, even packets -+ # which contain the BlastRADIUS attack. Please be aware -+ # that in this configuration the server will complain for -+ # EVERY packet which it receives. -+ # -+ # The only reason to set this flag to "no" is when the -+ # client is a proxy, AND the proxy does not send -+ # Message-Authenticator in Access-Request packets. Even -+ # then, the best approach to fix the issue is to (1) update -+ # the proxy to send Message-Authenticator, and if that -+ # can't be done, then (2) set this flag to "no", but ONLY -+ # for that one client. The global flag SHOULD still be set -+ # to a safe value: "yes". -+ # -+ # WARNING: Setting both this flag and the -+ # "require_message_authenticator" flag to "no" will allow -+ # MITM attackers to create fake Access-Accept packets to the -+ # NAS! At least one of them MUST be set to "yes" for the -+ # system to have any protection against the attack. -+ # -+ # * "yes" - Allow packets without Message-Authenticator, -+ # but only when they do not contain Proxy-State. -+ # packets which contain Proxy-State MUST also contain -+ # Message-Authenticator, otherwise they are discarded. -+ # -+ # This setting is safe for most NASes, GGSNs, BRAS, etc. -+ # Most regular RADIUS clients do not send Proxy-State -+ # attributes for Access-Request packets that they originate. -+ # However some aggregators (e.g. Wireless LAN Controllers) -+ # may act as a RADIUS proxy for requests from their cohort -+ # of managed devices, and in such cases will provide a -+ # Proxy-State attribute. For those systems, you _must_ look -+ # at the actual packets to determine what to do. It may be -+ # that the only way to fix the vulnerability is to upgrade -+ # the WLC, and set "require_message_authenticator" to "yes". -+ # -+ # * "auto" - Automatically determine the value of the flag, -+ # based on the first packet received from that client. -+ # -+ # If the packet contains Proxy-State but no -+ # Message-Authenticator, then the value of the flag is -+ # automatically switched to "no". -+ # -+ # For all other situations, the value of the flag is -+ # automatically switched to "yes". -+ # -+ # WARNING: This switch is done for the first packet -+ # received from that client. The change does NOT persist -+ # across server restarts. You MUST change the to "yes" -+ # manually, in order to make a permanent change to the -+ # configuration. -+ # -+ # WARNING: If there are multiple NASes with the same source -+ # IP and client definitions, BUT the NASes have different -+ # behavior, then this flag WILL LIKELY BREAK YOUR NETWORK. -+ # -+ # That is, when there are multiple different RADIUS clients -+ # behind one NATed IP address, then these security settings -+ # have to be set to allow the MOST INSECURE packets to be -+ # processed. This is a terrible idea, and will leave your -+ # network vulnerable to the attack. Please upgrade all -+ # clients immediately. -+ # -+ # The only solution to that rare configuration is to set -+ # this flag to "no", in which case the network will work, -+ # but will be vulnerable to the attack. -+ # -+ limit_proxy_state = auto -+ - @openssl_version_check_config@ - } - -diff --git a/src/include/clients.h b/src/include/clients.h -index 560211557f..2cde3a2e37 100644 ---- a/src/include/clients.h -+++ b/src/include/clients.h -@@ -39,7 +39,11 @@ typedef struct radclient { - - char const *secret; //!< Secret PSK. - -- bool message_authenticator; //!< Require RADIUS message authenticator in requests. -+ fr_bool_auto_t require_ma; //!< Require RADIUS message authenticator in requests. -+ -+ bool dynamic_require_ma; //!< for dynamic clients -+ -+ fr_bool_auto_t limit_proxy_state; //!< Limit Proxy-State in requests - - char const *nas_type; //!< Type of client (arbitrary). - -diff --git a/src/include/conffile.h b/src/include/conffile.h -index 8cb045c946..ddbcae4e4f 100644 ---- a/src/include/conffile.h -+++ b/src/include/conffile.h -@@ -140,6 +140,7 @@ typedef struct timeval _timeval_t; - #define PW_TYPE_MULTI (1 << 18) //!< CONF_PAIR can have multiple copies. - #define PW_TYPE_NOT_EMPTY (1 << 19) //!< CONF_PAIR is required to have a non zero length value. - #define PW_TYPE_FILE_EXISTS ((1 << 20) | PW_TYPE_STRING) //!< File matching value must exist -+#define PW_TYPE_IGNORE_DEFAULT (1 << 21) //!< don't set from .dflt if the CONF_PAIR is missing - /* @} **/ - - #define FR_INTEGER_COND_CHECK(_name, _var, _cond, _new)\ -diff --git a/src/include/libradius.h b/src/include/libradius.h -index ce2f713de1..2efef8b1d3 100644 ---- a/src/include/libradius.h -+++ b/src/include/libradius.h -@@ -402,6 +402,10 @@ typedef struct radius_packet { - size_t partial; - int proto; - #endif -+ bool tls; //!< uses secure transport -+ bool message_authenticator; -+ bool proxy_state; -+ bool eap_message; - } RADIUS_PACKET; - - typedef enum { -@@ -507,6 +511,13 @@ DICT_VENDOR *dict_vendorbyvalue(int vendor); - /* 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); -+ -+/* -+ * 1 == require_ma -+ * 2 == msg_peek -+ * 4 == limit_proxy_state -+ * 8 == require_ma for Access-* replies and Protocol-Error -+ */ - 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); -@@ -694,7 +705,7 @@ 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) -+#define FR_MAX_PACKET_CODE (53) - 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; -@@ -932,6 +943,12 @@ int fr_socket_wait_for_connect(int sockfd, struct timeval *timeout); - } - #endif - -+typedef enum { -+ FR_BOOL_FALSE = 0, -+ FR_BOOL_TRUE, -+ FR_BOOL_AUTO, -+} fr_bool_auto_t; -+ - #include - - #ifdef WITH_TCP -diff --git a/src/include/radius.h b/src/include/radius.h -index 473528d65d..147d674eed 100644 ---- a/src/include/radius.h -+++ b/src/include/radius.h -@@ -61,6 +61,7 @@ typedef enum { - 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_PROTOCOL_ERROR = 52, //!< RFC7930 - Protocol layer issue - PW_CODE_MAX = 255, //!< Maximum possible code - } PW_CODE; - -diff --git a/src/include/radiusd.h b/src/include/radiusd.h -index 0af3f51458..bd0aa668d0 100644 ---- a/src/include/radiusd.h -+++ b/src/include/radiusd.h -@@ -171,6 +171,10 @@ typedef struct main_config { - - bool exiting; //!< are we exiting? - -+ fr_bool_auto_t require_ma; //!< global configuration for all clients and home servers -+ -+ fr_bool_auto_t limit_proxy_state; //!< global configuration for all clients -+ - - #ifdef ENABLE_OPENSSL_VERSION_CHECK - char const *allow_vulnerable_openssl; //!< The CVE number of the last security issue acknowledged. -@@ -557,6 +561,8 @@ int main_config_free(void); - void main_config_hup(void); - void hup_logfile(void); - -+int fr_bool_auto_parse(CONF_PAIR *cp, fr_bool_auto_t *out, char const *str); -+ - /* listen.c */ - void listen_free(rad_listen_t **head); - int listen_init(CONF_SECTION *cs, rad_listen_t **head, bool spawn_flag); -diff --git a/src/include/realms.h b/src/include/realms.h -index 6dae8b4f85..ea5665c56c 100644 ---- a/src/include/realms.h -+++ b/src/include/realms.h -@@ -59,6 +59,7 @@ typedef struct home_server { - //!< stats or when specifying home servers for a pool. - - bool dual; //!< One of a pair of homeservers on consecutive ports. -+ fr_bool_auto_t require_ma; //!< for all replies to Access-Request and Status-Server - char const *server; //!< For internal proxying - char const *parent_server; - -diff --git a/src/lib/radius.c b/src/lib/radius.c -index 3881111f7d..556f3b961e 100644 ---- a/src/lib/radius.c -+++ b/src/lib/radius.c -@@ -142,8 +142,9 @@ char const *fr_packet_codes[FR_MAX_PACKET_CODE] = { - "47", - "48", - "49", -- "IP-Address-Allocate", -- "IP-Address-Release", //!< 50 -+ "IP-Address-Allocate", //!< 50 -+ "IP-Address-Release", -+ "Protocol-Error", - }; - - -@@ -1700,6 +1701,15 @@ int rad_vp2attr(RADIUS_PACKET const *packet, RADIUS_PACKET const *original, - return rad_vp2vsa(packet, original, secret, pvp, start, room); - } - -+static const bool code2ma[FR_MAX_PACKET_CODE] = { -+ [ PW_CODE_ACCESS_REQUEST ] = true, -+ [ PW_CODE_ACCESS_ACCEPT ] = true, -+ [ PW_CODE_ACCESS_REJECT ] = true, -+ [ PW_CODE_ACCESS_CHALLENGE ] = true, -+ [ PW_CODE_STATUS_SERVER ] = true, -+ [ PW_CODE_PROTOCOL_ERROR ] = true, -+}; -+ - - /** Encode a packet - * -@@ -1712,6 +1722,7 @@ int rad_encode(RADIUS_PACKET *packet, RADIUS_PACKET const *original, - uint16_t total_length; - int len; - VALUE_PAIR const *reply; -+ bool seen_ma = false; - - /* - * A 4K packet, aligned on 64-bits. -@@ -1775,6 +1786,27 @@ int rad_encode(RADIUS_PACKET *packet, RADIUS_PACKET const *original, - * memcpy. - */ - -+ /* -+ * Always add Message-Authenticator for replies to -+ * Access-Request packets, and for all Access-Accept, -+ * Access-Reject, Access-Challenge. -+ * -+ * It must be the FIRST attribute in the packet. -+ */ -+ if (!packet->tls && -+ ((code2ma[packet->code]) || (original && code2ma[original->code]))) { -+ seen_ma = true; -+ -+ packet->offset = RADIUS_HDR_LEN; -+ -+ ptr[0] = PW_MESSAGE_AUTHENTICATOR; -+ ptr[1] = 18; -+ memset(ptr + 2, 0, 16); -+ -+ ptr += 18; -+ total_length += 18; -+ } -+ - /* - * Loop over the reply attributes for the packet. - */ -@@ -1832,6 +1864,13 @@ int rad_encode(RADIUS_PACKET *packet, RADIUS_PACKET const *original, - * length and initial value. - */ - if (!reply->da->vendor && (reply->da->attr == PW_MESSAGE_AUTHENTICATOR)) { -+ /* -+ * We have already encoded the Message-Authenticator, don't do it again. -+ */ -+ if (seen_ma) { -+ reply = reply->next; -+ continue; -+ } - if (room < 18) break; - - /* -@@ -2323,6 +2362,8 @@ bool rad_packet_ok(RADIUS_PACKET *packet, int flags, decode_fail_t *reason) - radius_packet_t *hdr; - char host_ipaddr[128]; - bool require_ma = false; -+ bool limit_proxy_state = false; -+ bool seen_proxy_state = false; - bool seen_ma = false; - uint32_t num_attributes; - decode_fail_t failure = DECODE_FAIL_NONE; -@@ -2371,15 +2412,26 @@ bool rad_packet_ok(RADIUS_PACKET *packet, int flags, decode_fail_t *reason) - } - - /* -- * Message-Authenticator is required in Status-Server -- * packets, otherwise they can be trivially forged. -+ * If the caller requires Message-Authenticator, then set -+ * the flag. - */ -- if (hdr->code == PW_CODE_STATUS_SERVER) require_ma = true; - - /* -- * It's also required if the caller asks for it. -+ * We also require Message-Authenticator if the packet -+ * code is Status-Server. -+ * -+ * If we're receiving packets from a proxy socket, then -+ * require Message-Authenticator for Access-* replies, -+ * and for Protocol-Error. - */ -- if (flags) require_ma = true; -+ require_ma = ((flags & 0x01) != 0) || (hdr->code == PW_CODE_STATUS_SERVER) || (((flags & 0x08) != 0) && code2ma[hdr->code]); -+ -+ /* -+ * -+ * We only limit Proxy-State if we're not requiring -+ * Message-Authenticator. -+ */ -+ limit_proxy_state = ((flags & 0x04) != 0) && !require_ma; - - /* - * Repeat the length checks. This time, instead of -@@ -2534,6 +2586,7 @@ bool rad_packet_ok(RADIUS_PACKET *packet, int flags, decode_fail_t *reason) - case PW_EAP_MESSAGE: - require_ma = true; - eap = true; -+ packet->eap_message = true; - break; - - case PW_USER_PASSWORD: -@@ -2542,6 +2595,11 @@ bool rad_packet_ok(RADIUS_PACKET *packet, int flags, decode_fail_t *reason) - non_eap = true; - break; - -+ case PW_PROXY_STATE: -+ seen_proxy_state = true; -+ packet->proxy_state = true; -+ break; -+ - case PW_MESSAGE_AUTHENTICATOR: - if (attr[1] != 2 + AUTH_VECTOR_LEN) { - FR_DEBUG_STRERROR_PRINTF("Malformed RADIUS packet from host %s: Message-Authenticator has invalid length %d", -@@ -2553,6 +2611,7 @@ bool rad_packet_ok(RADIUS_PACKET *packet, int flags, decode_fail_t *reason) - goto finish; - } - seen_ma = true; -+ packet->message_authenticator = true; - break; - } - -@@ -2609,7 +2668,19 @@ bool rad_packet_ok(RADIUS_PACKET *packet, int flags, decode_fail_t *reason) - * Message-Authenticator attributes. - */ - if (require_ma && !seen_ma) { -- FR_DEBUG_STRERROR_PRINTF("Insecure packet from host %s: Packet does not contain required Message-Authenticator attribute", -+ FR_DEBUG_STRERROR_PRINTF("Insecure packet from host %s: Packet does not contain required Message-Authenticator attribute. You may need to set \"require_message_authenticator = no\" in the configuration.", -+ inet_ntop(packet->src_ipaddr.af, -+ &packet->src_ipaddr.ipaddr, -+ host_ipaddr, sizeof(host_ipaddr))); -+ failure = DECODE_FAIL_MA_MISSING; -+ goto finish; -+ } -+ -+ /* -+ * The client is a NAS which shouldn't send Proxy-State, but it did! -+ */ -+ if (limit_proxy_state && seen_proxy_state && !seen_ma) { -+ FR_DEBUG_STRERROR_PRINTF("Insecure packet from host %s: Packet does not contain required Message-Authenticator attribute, but still has one or more Proxy-State attributes", - inet_ntop(packet->src_ipaddr.af, - &packet->src_ipaddr.ipaddr, - host_ipaddr, sizeof(host_ipaddr))); -diff --git a/src/main/client.c b/src/main/client.c -index abcc15d225..af5b122af5 100644 ---- a/src/main/client.c -+++ b/src/main/client.c -@@ -279,7 +279,8 @@ bool client_add(RADCLIENT_LIST *clients, RADCLIENT *client) - (old->coa_server == client->coa_server) && - (old->coa_pool == client->coa_pool) && - #endif -- (old->message_authenticator == client->message_authenticator)) { -+ (old->require_ma == client->require_ma) && -+ (old->limit_proxy_state == client->limit_proxy_state)) { - WARN("Ignoring duplicate client %s", client->longname); - client_free(client); - return true; -@@ -443,6 +444,8 @@ static fr_ipaddr_t cl_ipaddr; - static uint32_t cl_netmask; - static char const *cl_srcipaddr = NULL; - static char const *hs_proto = NULL; -+static char const *require_message_authenticator = NULL; -+static char const *limit_proxy_state = NULL; - - #ifdef WITH_TCP - static CONF_PARSER limit_config[] = { -@@ -465,7 +468,8 @@ static const CONF_PARSER client_config[] = { - - { "src_ipaddr", FR_CONF_POINTER(PW_TYPE_STRING, &cl_srcipaddr), NULL }, - -- { "require_message_authenticator", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, RADCLIENT, message_authenticator), "no" }, -+ { "require_message_authenticator", FR_CONF_POINTER(PW_TYPE_STRING| PW_TYPE_IGNORE_DEFAULT, &require_message_authenticator), NULL }, -+ { "limit_proxy_state", FR_CONF_POINTER(PW_TYPE_STRING| PW_TYPE_IGNORE_DEFAULT, &limit_proxy_state), NULL }, - - { "secret", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_SECRET, RADCLIENT, secret), NULL }, - { "shortname", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, shortname), NULL }, -@@ -661,7 +665,7 @@ static const CONF_PARSER dynamic_config[] = { - { "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-Require-MA", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, RADCLIENT, dynamic_require_ma), NULL }, - - { "FreeRADIUS-Client-Secret", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, secret), "" }, - { "FreeRADIUS-Client-Shortname", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, shortname), "" }, -@@ -843,8 +847,19 @@ RADCLIENT *client_afrom_cs(TALLOC_CTX *ctx, CONF_SECTION *cs, bool in_server, bo - c = talloc_zero(ctx, RADCLIENT); - c->cs = cs; - -+ /* -+ * Set the "require message authenticator" and "limit -+ * proxy state" flags from the global default. If the -+ * configuration item exists, AND is set, it will -+ * over-ride the flag. -+ */ -+ c->require_ma = main_config.require_ma; -+ c->limit_proxy_state = main_config.limit_proxy_state; -+ - memset(&cl_ipaddr, 0, sizeof(cl_ipaddr)); - cl_netmask = 255; -+ require_message_authenticator = NULL; -+ limit_proxy_state = NULL; - - if (cf_section_parse(cs, c, client_config) < 0) { - cf_log_err_cs(cs, "Error parsing client section"); -@@ -855,6 +870,9 @@ RADCLIENT *client_afrom_cs(TALLOC_CTX *ctx, CONF_SECTION *cs, bool in_server, bo - cl_srcipaddr = NULL; - #endif - -+ require_message_authenticator = NULL; -+ limit_proxy_state = NULL; -+ - return NULL; - } - -@@ -1112,6 +1130,16 @@ done_coa: - } - #endif - -+ if (fr_bool_auto_parse(cf_pair_find(cs, "require_message_authenticator"), &c->require_ma, require_message_authenticator) < 0) { -+ goto error; -+ } -+ -+ if (c->require_ma != FR_BOOL_TRUE) { -+ if (fr_bool_auto_parse(cf_pair_find(cs, "limit_proxy_state"), &c->limit_proxy_state, limit_proxy_state) < 0) { -+ goto error; -+ } -+ } -+ - return c; - } - -@@ -1156,7 +1184,7 @@ RADCLIENT *client_afrom_query(TALLOC_CTX *ctx, char const *identifier, char cons - 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; -+ c->require_ma = require_ma; - - return c; - } -@@ -1342,10 +1370,10 @@ RADCLIENT *client_afrom_request(RADCLIENT_LIST *clients, REQUEST *request) - *pi = vp->vp_integer; - - /* -- * Same nastiness as above. -+ * Same nastiness as above, but hard-coded for require Message-Authenticator. - */ - for (parse = client_config; parse->name; parse++) { -- if (parse->offset == dynamic_config[i].offset) break; -+ if (parse->type == PW_TYPE_BOOLEAN) break; - } - if (!parse) break; - -@@ -1434,6 +1462,11 @@ validate: - goto error; - } - -+ /* -+ * It can't be set to "auto". Too bad. -+ */ -+ c->require_ma = (fr_bool_auto_t) c->dynamic_require_ma; -+ - if (!client_add_dynamic(clients, request->client, c)) { - return NULL; - } -diff --git a/src/main/conffile.c b/src/main/conffile.c -index 6d6441a55b..0e1ced2385 100644 ---- a/src/main/conffile.c -+++ b/src/main/conffile.c -@@ -1417,6 +1417,7 @@ int cf_item_parse(CONF_SECTION *cs, char const *name, unsigned int type, void *d - { - int rcode; - bool deprecated, required, attribute, secret, file_input, cant_be_empty, tmpl, multi, file_exists; -+ bool ignore_dflt; - char **q; - char const *value; - CONF_PAIR *cp = NULL; -@@ -1440,6 +1441,7 @@ int cf_item_parse(CONF_SECTION *cs, char const *name, unsigned int type, void *d - cant_be_empty = (type & PW_TYPE_NOT_EMPTY); - tmpl = (type & PW_TYPE_TMPL); - multi = (type & PW_TYPE_MULTI); -+ ignore_dflt = (type & PW_TYPE_IGNORE_DEFAULT); - - if (attribute) required = true; - if (required) cant_be_empty = true; /* May want to review this in the future... */ -@@ -1463,7 +1465,7 @@ int cf_item_parse(CONF_SECTION *cs, char const *name, unsigned int type, void *d - * section, use the default value. - */ - if (!cp) { -- if (deprecated) return 0; /* Don't set the default value */ -+ if (deprecated || ignore_dflt) return 0; /* Don't set the default value */ - - rcode = 1; - value = dflt; -diff --git a/src/main/listen.c b/src/main/listen.c -index ebf7f5221c..0d178138c9 100644 ---- a/src/main/listen.c -+++ b/src/main/listen.c -@@ -456,6 +456,122 @@ int rad_status_server(REQUEST *request) - return 0; - } - -+static void blastradius_checks(RADIUS_PACKET *packet, RADCLIENT *client) -+{ -+ if (client->require_ma == FR_BOOL_TRUE) return; -+ -+ if (client->require_ma == FR_BOOL_AUTO) { -+ if (!packet->message_authenticator) { -+ ERROR("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); -+ ERROR("BlastRADIUS check: Received packet without Message-Authenticator."); -+ ERROR("Setting \"require_message_authenticator = false\" for client %s", client->shortname); -+ ERROR("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); -+ ERROR("UPGRADE THE CLIENT AS YOUR NETWORK IS VULNERABLE TO THE BLASTRADIUS ATTACK."); -+ ERROR("Once the client is upgraded, set \"require_message_authenticator = true\" for client %s", client->shortname); -+ ERROR("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); -+ client->require_ma = FR_BOOL_FALSE; -+ -+ /* -+ * And fall through to the -+ * limit_proxy_state checks, which might -+ * complain again. Oh well, maybe that -+ * will make people read the messages. -+ */ -+ -+ } else if (packet->eap_message) { -+ /* -+ * Don't set it to "true" for packets -+ * with EAP-Message. It's already -+ * required there, and we might get a -+ * non-EAP packet with (or without) -+ * Message-Authenticator -+ */ -+ return; -+ } else { -+ ERROR("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); -+ ERROR("BlastRADIUS check: Received packet with Message-Authenticator."); -+ ERROR("Setting \"require_message_authenticator = true\" for client %s", client->shortname); -+ ERROR("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); -+ ERROR("It looks like the client has been updated to protect from the BlastRADIUS attack."); -+ ERROR("Please set \"require_message_authenticator = true\" for client %s", client->shortname); -+ ERROR("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); -+ -+ client->require_ma = FR_BOOL_TRUE; -+ return; -+ } -+ -+ } -+ -+ /* -+ * If all of the checks are turned off, then complain for every packet we receive. -+ */ -+ if (client->limit_proxy_state == FR_BOOL_FALSE) { -+ /* -+ * We have a Message-Authenticator, and it's valid. We don't need to compain. -+ */ -+ if (!fr_debug_lvl) return; /* easier than checking for each line below */ -+ -+ DEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); -+ DEBUG("BlastRADIUS check: Received packet without Message-Authenticator."); -+ DEBUG("YOU MUST SET \"require_message_authenticator = true\", or"); -+ DEBUG("YOU MUST SET \"limit_proxy_state = true\" for client %s", client->shortname); -+ DEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); -+ DEBUG("The packet does not contain Message-Authenticator, which is a security issue"); -+ DEBUG("UPGRADE THE CLIENT AS YOUR NETWORK IS VULNERABLE TO THE BLASTRADIUS ATTACK."); -+ DEBUG("Once the client is upgraded, set \"require_message_authenticator = true\" for client %s", client->shortname); -+ DEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); -+ return; -+ } -+ -+ /* -+ * Don't complain here. rad_packet_ok() will instead -+ * complain about every packet with Proxy-State but which -+ * is missing Message-Authenticator. -+ */ -+ if (client->limit_proxy_state == FR_BOOL_TRUE) { -+ return; -+ } -+ -+ if (packet->proxy_state && !packet->message_authenticator) { -+ ERROR("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); -+ ERROR("BlastRADIUS check: Received packet with Proxy-State, but without Message-Authenticator."); -+ ERROR("This is either a BlastRADIUS attack, OR"); -+ ERROR("the client is a proxy RADIUS server which has not been upgraded."); -+ ERROR("Setting \"limit_proxy_state = false\" for client %s", client->shortname); -+ ERROR("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); -+ ERROR("UPGRADE THE CLIENT AS YOUR NETWORK IS VULNERABLE TO THE BLASTRADIUS ATTACK."); -+ DEBUG("Once the client is upgraded, set \"require_message_authenticator = true\" for client %s", client->shortname); -+ ERROR("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); -+ -+ client->limit_proxy_state = FR_BOOL_FALSE; -+ -+ } else { -+ client->limit_proxy_state = FR_BOOL_TRUE; -+ -+ ERROR("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); -+ if (!packet->proxy_state) { -+ ERROR("BlastRADIUS check: Received packet without Proxy-State."); -+ } else { -+ ERROR("BlastRADIUS check: Received packet with Proxy-State and Message-Authenticator."); -+ } -+ -+ ERROR("Setting \"limit_proxy_state = true\" for client %s", client->shortname); -+ ERROR("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); -+ -+ if (!packet->message_authenticator) { -+ ERROR("The packet does not contain Message-Authenticator, which is a security issue."); -+ ERROR("UPGRADE THE CLIENT AS YOUR NETWORK MAY BE VULNERABLE TO THE BLASTRADIUS ATTACK."); -+ DEBUG("Once the client is upgraded, set \"require_message_authenticator = true\" for client %s", client->shortname); -+ } else { -+ ERROR("The packet contains Message-Authenticator."); -+ if (!packet->eap_message) ERROR("The client has likely been upgraded to protect from the attack."); -+ ERROR("Please set \"require_message_authenticator = true\" for client %s", client->shortname); -+ } -+ ERROR("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); -+ } -+} -+ -+ - #ifdef WITH_TCP - static int dual_tcp_recv(rad_listen_t *listener) - { -@@ -532,6 +648,21 @@ static int dual_tcp_recv(rad_listen_t *listener) - switch (packet->code) { - case PW_CODE_ACCESS_REQUEST: - if (listener->type != RAD_LISTEN_AUTH) goto bad_packet; -+ -+ /* -+ * Enforce BlastRADIUS checks on TCP, too. -+ */ -+ if (!rad_packet_ok(packet, (client->require_ma == FR_BOOL_TRUE) | ((client->limit_proxy_state == FR_BOOL_TRUE) << 2), NULL)) { -+ FR_STATS_INC(auth, total_malformed_requests); -+ rad_free(&sock->packet); -+ return 0; -+ } -+ -+ /* -+ * Perform BlastRADIUS checks and warnings. -+ */ -+ if (packet->code == PW_CODE_ACCESS_REQUEST) blastradius_checks(packet, client); -+ - FR_STATS_INC(auth, total_requests); - fun = rad_authenticate; - break; -@@ -1562,7 +1693,7 @@ static int auth_socket_recv(rad_listen_t *listener) - * Now that we've sanity checked everything, receive the - * packet. - */ -- packet = rad_recv(ctx, listener->fd, client->message_authenticator); -+ packet = rad_recv(ctx, listener->fd, (client->require_ma == FR_BOOL_TRUE) | ((client->limit_proxy_state == FR_BOOL_TRUE) << 2)); - if (!packet) { - FR_STATS_INC(auth, total_malformed_requests); - if (DEBUG_ENABLED) ERROR("Receive - %s", fr_strerror()); -@@ -1570,6 +1701,12 @@ static int auth_socket_recv(rad_listen_t *listener) - return 0; - } - -+ -+ /* -+ * Perform BlastRADIUS checks and warnings. -+ */ -+ if (packet->code == PW_CODE_ACCESS_REQUEST) blastradius_checks(packet, client); -+ - #ifdef __APPLE__ - #ifdef WITH_UDPFROMTO - /* -@@ -1955,7 +2092,7 @@ static int coa_socket_recv(rad_listen_t *listener) - * Now that we've sanity checked everything, receive the - * packet. - */ -- packet = rad_recv(ctx, listener->fd, client->message_authenticator); -+ packet = rad_recv(ctx, listener->fd, client->require_ma | (((int) client->limit_proxy_state) << 2)); - if (!packet) { - FR_STATS_INC(coa, total_malformed_requests); - if (DEBUG_ENABLED) ERROR("Receive - %s", fr_strerror()); -diff --git a/src/main/mainconfig.c b/src/main/mainconfig.c -index e9dd412dee..854c7155aa 100644 ---- a/src/main/mainconfig.c -+++ b/src/main/mainconfig.c -@@ -73,6 +73,8 @@ static char const *gid_name = NULL; - static char const *chroot_dir = NULL; - static bool allow_core_dumps = false; - static char const *radlog_dest = NULL; -+static char const *require_message_authenticator = NULL; -+static char const *limit_proxy_state = NULL; - - /* - * These are not used anywhere else.. -@@ -87,6 +89,53 @@ static bool do_colourise = false; - - static char const *radius_dir = NULL; //!< Path to raddb directory - -+static const FR_NAME_NUMBER fr_bool_auto_names[] = { -+ { "false", FR_BOOL_FALSE }, -+ { "no", FR_BOOL_FALSE }, -+ { "0", FR_BOOL_FALSE }, -+ -+ { "true", FR_BOOL_TRUE }, -+ { "yes", FR_BOOL_TRUE }, -+ { "1", FR_BOOL_TRUE }, -+ -+ { "auto", FR_BOOL_AUTO }, -+ -+ { NULL, 0 } -+}; -+ -+/* -+ * Get decent values for false / true / auto -+ */ -+int fr_bool_auto_parse(CONF_PAIR *cp, fr_bool_auto_t *out, char const *str) -+{ -+ int value; -+ -+ /* -+ * Don't change anything. -+ */ -+ if (!str) return 0; -+ -+ value = fr_str2int(fr_bool_auto_names, str, -1); -+ if (value >= 0) { -+ *out = value; -+ return 0; -+ } -+ -+ /* -+ * This should never happen, as the defaults are in the -+ * source code. If there's no CONF_PAIR, and there's a -+ * parse error, then the source code is wrong. -+ */ -+ if (!cp) { -+ fprintf(stderr, "%s: Error - Invalid value in configuration", main_config.name); -+ return -1; -+ } -+ -+ cf_log_err(cf_pair_to_item(cp), "Invalid value for \"%s\"", cf_pair_attr(cp)); -+ return -1; -+} -+ -+ - /********************************************************************** - * - * We need to figure out where the logs go, before doing anything -@@ -159,6 +208,8 @@ 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"}, -+ { "require_message_authenticator", FR_CONF_POINTER(PW_TYPE_STRING, &require_message_authenticator), "auto"}, -+ { "limit_proxy_state", FR_CONF_POINTER(PW_TYPE_STRING, &limit_proxy_state), "auto"}, - #ifdef ENABLE_OPENSSL_VERSION_CHECK - { "allow_vulnerable_openssl", FR_CONF_POINTER(PW_TYPE_STRING, &main_config.allow_vulnerable_openssl), "no"}, - #endif -@@ -838,6 +889,8 @@ int main_config_init(void) - if (!main_config.dictionary_dir) { - main_config.dictionary_dir = DICTDIR; - } -+ main_config.require_ma = FR_BOOL_AUTO; -+ main_config.limit_proxy_state = FR_BOOL_AUTO; - - /* - * About sizeof(REQUEST) + sizeof(RADIUS_PACKET) * 2 + sizeof(VALUE_PAIR) * 400 -@@ -1127,6 +1180,23 @@ do {\ - main_config.init_delay.tv_sec = 0; - main_config.init_delay.tv_usec = 2* (1000000 / 3); - -+ { -+ CONF_PAIR *cp = NULL; -+ -+ subcs = cf_section_sub_find(cs, "security"); -+ if (subcs) cp = cf_pair_find(subcs, "require_message_authenticator"); -+ if (fr_bool_auto_parse(cp, &main_config.require_ma, require_message_authenticator) < 0) { -+ cf_file_free(cs); -+ return -1; -+ } -+ -+ if (subcs) cp = cf_pair_find(subcs, "limit_proxy_state"); -+ if (fr_bool_auto_parse(cp, &main_config.limit_proxy_state, limit_proxy_state) < 0) { -+ cf_file_free(cs); -+ return -1; -+ } -+ } -+ - /* - * Free the old configuration items, and replace them - * with the new ones. -diff --git a/src/main/process.c b/src/main/process.c -index 78c6d8a9e5..a478026024 100644 ---- a/src/main/process.c -+++ b/src/main/process.c -@@ -2594,6 +2594,23 @@ int request_proxy_reply(RADIUS_PACKET *packet) - - PTHREAD_MUTEX_UNLOCK(&proxy_mutex); - -+ if (!request->proxy_reply) { -+ decode_fail_t reason; -+ -+ /* -+ * If the home server configuration requires a Message-Authenticator, then set the flag, -+ * but only if the proxied packet is Access-Request or Status-Sercer. -+ * -+ * The realms.c file already clears require_ma for TLS connections. -+ */ -+ bool require_ma = (request->home_server->require_ma == FR_BOOL_TRUE) && (request->proxy->code == PW_CODE_ACCESS_REQUEST); -+ -+ if(!rad_packet_ok(packet, require_ma, &reason)) { -+ DEBUG("Ignoring invalid packet - %s", fr_strerror()); -+ return 0; -+ } -+ } -+ - /* - * No reply, BUT the current packet fails verification: - * ignore it. This does the MD5 calculations in the -@@ -2619,6 +2636,54 @@ int request_proxy_reply(RADIUS_PACKET *packet) - return 0; - } - -+ -+ /* -+ * BlastRADIUS checks. We're running in the main -+ * listener thread, so there's no conflict -+ * checking or setting these fields. -+ */ -+ if (!request->proxy_reply && (request->proxy->code == PW_CODE_ACCESS_REQUEST) && -+#ifdef WITH_TLS -+ !request->home_server->tls && -+#endif -+ !packet->eap_message) { -+ if (request->home_server->require_ma == FR_BOOL_AUTO) { -+ if (!packet->message_authenticator) { -+ RERROR("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); -+ RERROR("BlastRADIUS check: Received response to Access-Request without Message-Authenticator."); -+ RERROR("Setting \"require_message_authenticator = false\" for home_server %s", request->home_server->name); -+ RERROR("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); -+ RERROR("UPGRADE THE HOME SERVER AS YOUR NETWORK IS VULNERABLE TO THE BLASTRADIUS ATTACK."); -+ RERROR("Once the home_server is upgraded, set \"require_message_authenticator = true\" for home_server %s.", request->home_server->name); -+ RERROR("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); -+ -+ request->home_server->require_ma = FR_BOOL_FALSE; -+ } else { -+ RERROR("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); -+ RERROR("BlastRADIUS check: Received response to Access-Request with Message-Authenticator."); -+ RERROR("Setting \"require_message_authenticator = true\" for home_server %s", request->home_server->name); -+ RERROR("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); -+ RERROR("It looks like the home server has been updated to protect from the BlastRADIUS attack."); -+ RERROR("Please set \"require_message_authenticator = true\" for home_server %s", request->home_server->name); -+ RERROR("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); -+ -+ request->home_server->require_ma = FR_BOOL_TRUE; -+ } -+ -+ } else if (fr_debug_lvl && (request->home_server->require_ma == FR_BOOL_FALSE) && !packet->message_authenticator) { -+ /* -+ * If it's "no" AND we don't have a Message-Authenticator, then complain on every packet. -+ */ -+ RDEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); -+ RDEBUG("BlastRADIUS check: Received packet without Message-Authenticator from home_server %s", request->home_server->name); -+ RDEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); -+ RDEBUG("The packet does not contain Message-Authenticator, which is a security issue"); -+ RDEBUG("UPGRADE THE HOME SERVER AS YOUR NETWORK IS VULNERABLE TO THE BLASTRADIUS ATTACK."); -+ RERROR("Once the home_server is upgraded, set \"require_message_authenticator = true\" for home_server %s.", request->home_server->name); -+ RDEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); -+ } -+ } -+ - /* - * This shouldn't happen, but threads and race - * conditions. -diff --git a/src/main/radclient.c b/src/main/radclient.c -index 52d2872b13..dd2b342ba2 100644 ---- a/src/main/radclient.c -+++ b/src/main/radclient.c -@@ -54,6 +54,7 @@ static fr_ipaddr_t server_ipaddr; - static int resend_count = 1; - static bool done = true; - static bool print_filename = false; -+static bool blast_radius = false; - - static fr_ipaddr_t client_ipaddr; - static uint16_t client_port = 0; -@@ -89,6 +90,7 @@ static void NEVER_RETURNS usage(void) - fprintf(stderr, " 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, " -b Mandate checks for Blast RADIUS (this is not set by default).\n"); - fprintf(stderr, " -c Send each packet 'count' times.\n"); - fprintf(stderr, " -d Set user dictionary directory (defaults to " RADDBDIR ").\n"); - fprintf(stderr, " -D Set main dictionary directory (defaults to " DICTDIR ").\n"); -@@ -1000,6 +1002,130 @@ static int send_one_packet(rc_request_t *request) - return 0; - } - -+/* -+ * Do Blast RADIUS checks. -+ * -+ * The request is an Access-Request, and does NOT contain Proxy-State. -+ * -+ * The reply is a raw packet, and is NOT yet decoded. -+ */ -+static int blast_radius_check(rc_request_t *request, RADIUS_PACKET *reply) -+{ -+ uint8_t *attr, *end; -+ VALUE_PAIR *vp; -+ bool have_message_authenticator = false; -+ -+ /* -+ * We've received a raw packet. Nothing has (as of yet) checked -+ * anything in it other than the length, and that it's a -+ * well-formed RADIUS packet. -+ */ -+ switch (reply->data[0]) { -+ case PW_CODE_ACCESS_ACCEPT: -+ case PW_CODE_ACCESS_REJECT: -+ case PW_CODE_ACCESS_CHALLENGE: -+ if (reply->data[1] != request->packet->id) { -+ ERROR("Invalid reply ID %d to Access-Request ID %d", reply->data[1], request->packet->id); -+ return -1; -+ } -+ break; -+ -+ default: -+ ERROR("Invalid reply code %d to Access-Request", reply->data[0]); -+ return -1; -+ } -+ -+ /* -+ * If the reply has a Message-Authenticator, then it MIGHT be fine. -+ */ -+ attr = reply->data + 20; -+ end = reply->data + reply->data_len; -+ -+ /* -+ * It should be the first attribute, so we warn if it isn't there. -+ * -+ * But it's not a fatal error. -+ */ -+ if (blast_radius && (attr[0] != PW_MESSAGE_AUTHENTICATOR)) { -+ RDEBUG("WARNING The %s reply packet does not have Message-Authenticator as the first attribute. The packet may be vulnerable to Blast RADIUS attacks.", -+ fr_packet_codes[reply->data[0]]); -+ } -+ -+ /* -+ * Set up for Proxy-State checks. -+ * -+ * If we see a Proxy-State in the reply which we didn't send, then it's a Blast RADIUS attack. -+ */ -+ vp = fr_pair_find_by_num(request->packet->vps, PW_PROXY_STATE, 0, TAG_ANY); -+ -+ while (attr < end) { -+ /* -+ * Blast RADIUS work-arounds require that -+ * Message-Authenticator is the first attribute in the -+ * reply. Note that we don't check for it being the -+ * first attribute, but simply that it exists. -+ * -+ * That check is a balance between securing the reply -+ * packet from attacks, and not violating the RFCs which -+ * say that there is no order to attributes in the -+ * packet. -+ * -+ * However, no matter the status of the '-b' flag we -+ * still can check for the signature of the attack, and -+ * discard packets which are suspicious. This behavior -+ * protects radclient from the attack, without mandating -+ * new behavior on the server side. -+ * -+ * Note that we don't set the '-b' flag by default. -+ * radclient is intended for testing / debugging, and is -+ * not intended to be used as part of a secure login / -+ * user checking system. -+ */ -+ if (attr[0] == PW_MESSAGE_AUTHENTICATOR) { -+ have_message_authenticator = true; -+ goto next; -+ } -+ -+ /* -+ * If there are Proxy-State attributes in the reply, they must -+ * match EXACTLY the Proxy-State attributes in the request. -+ * -+ * Note that we don't care if there are more Proxy-States -+ * in the request than in the reply. The Blast RADIUS -+ * issue requires _adding_ Proxy-State attributes, and -+ * cannot work when the server _deletes_ Proxy-State -+ * attributes. -+ */ -+ if (attr[0] == PW_PROXY_STATE) { -+ if (!vp || (vp->length != (size_t) (attr[1] - 2)) || (memcmp(vp->vp_octets, attr + 2, vp->length) != 0)) { -+ ERROR("Invalid reply to Access-Request ID %d - Discarding packet due to Blast RADIUS attack being detected.", request->packet->id); -+ ERROR("We received a Proxy-State in the reply which we did not send, or which is different from what we sent."); -+ return -1; -+ } -+ -+ vp = fr_pair_find_by_num(vp->next, PW_PROXY_STATE, 0, TAG_ANY); -+ } -+ -+ next: -+ attr += attr[1]; -+ } -+ -+ /* -+ * If "-b" is set, then we require Message-Authenticator in the reply. -+ */ -+ if (blast_radius && !have_message_authenticator) { -+ ERROR("The %s reply packet does not contain Message-Authenticator - discarding packet due to Blast RADIUS checks.", -+ fr_packet_codes[reply->data[0]]); -+ return -1; -+ } -+ -+ /* -+ * The packet doesn't look like it's a Blast RADIUS attack. The -+ * caller will now verify the packet signature. -+ */ -+ return 0; -+} -+ - /* - * Receive one packet, maybe. - */ -@@ -1051,6 +1177,21 @@ static int recv_one_packet(int wait_time) - } - request = fr_packet2myptr(rc_request_t, packet, packet_p); - -+ -+ /* -+ * We want radclient to be able to send any packet, including -+ * imperfect ones. However, we do NOT want to be vulnerable to -+ * the "Blast RADIUS" issue. Instead of adding command-line -+ * flags to enable/disable similar flags to what the server -+ * sends, we just do a few more smart checks to double-check -+ * things. -+ */ -+ if ((request->packet->code == PW_CODE_ACCESS_REQUEST) && -+ blast_radius_check(request, reply) < 0) { -+ rad_free(&reply); -+ return -1; -+ } -+ - /* - * Fails the signature validation: not a real reply. - * FIXME: Silently drop it and listen for another packet. -@@ -1183,7 +1324,7 @@ int main(int argc, char **argv) - exit(1); - } - -- while ((c = getopt(argc, argv, "46c:d:D:f:Fhn:p:qr:sS:t:vx" -+ while ((c = getopt(argc, argv, "46bc:d:D:f:Fhn:p:qr:sS:t:vx" - #ifdef WITH_TCP - "P:" - #endif -@@ -1196,6 +1337,10 @@ int main(int argc, char **argv) - force_af = AF_INET6; - break; - -+ case 'b': -+ blast_radius = true; -+ break; -+ - case 'c': - if (!isdigit((int) *optarg)) - usage(); -diff --git a/src/main/radtest.in b/src/main/radtest.in -index 38b1ba9a0f..8a6741a26c 100644 ---- a/src/main/radtest.in -+++ b/src/main/radtest.in -@@ -19,6 +19,7 @@ usage() { - 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 -+ echo " -6 Mandate checks for Blast RADIUS (this is not set by default)." >&2 - exit 1 - } - -@@ -55,6 +56,10 @@ do - NAS_ADDR_ATTR="NAS-IPv6-Address" - shift - ;; -+ -b) -+ OPTIONS="$OPTIONS -b" -+ shift -+ ;; - -d) - OPTIONS="$OPTIONS -d $2" - shift;shift -@@ -120,7 +125,6 @@ fi - echo "$PASSWORD = \"$2\"" - echo "$NAS_ADDR_ATTR = $nas" - echo "NAS-Port = $4" -- echo "Message-Authenticator = 0x00" - if [ "$radclient" = "$radeapclient" ] - then - echo "EAP-Code = Response" -diff --git a/src/main/realms.c b/src/main/realms.c -index eb42598116..c82d2eb1ea 100644 ---- a/src/main/realms.c -+++ b/src/main/realms.c -@@ -366,7 +366,10 @@ static CONF_PARSER home_server_coa[] = { - }; - #endif - -+static const char *require_message_authenticator = NULL; -+ - static CONF_PARSER home_server_config[] = { -+ { "require_message_authenticator", FR_CONF_POINTER(PW_TYPE_STRING| PW_TYPE_IGNORE_DEFAULT, &require_message_authenticator), NULL }, - { "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 }, -@@ -640,6 +643,9 @@ home_server_t *home_server_afrom_cs(TALLOC_CTX *ctx, realm_config_t *rc, CONF_SE - home->cs = cs; - home->state = HOME_STATE_UNKNOWN; - home->proto = IPPROTO_UDP; -+ home->require_ma = main_config.require_ma; -+ -+ require_message_authenticator = false; - - /* - * Parse the configuration into the home server -@@ -647,6 +653,10 @@ home_server_t *home_server_afrom_cs(TALLOC_CTX *ctx, realm_config_t *rc, CONF_SE - */ - if (cf_section_parse(cs, home, home_server_config) < 0) goto error; - -+ if (fr_bool_auto_parse(cf_pair_find(cs, "require_message_authenticator"), &home->require_ma, require_message_authenticator) < 0) { -+ goto error; -+ } -+ - /* - * It has an IP address, it must be a remote server. - */ -@@ -924,6 +934,7 @@ home_server_t *home_server_afrom_cs(TALLOC_CTX *ctx, realm_config_t *rc, CONF_SE - * Parse the SSL client configuration. - */ - if (tls) { -+ home->require_ma = false; - home->tls = tls_client_conf_parse(tls); - if (!home->tls) { - goto error; -diff --git a/src/main/tls_listen.c b/src/main/tls_listen.c -index 0eed87b64f..4ae3c5b975 100644 ---- a/src/main/tls_listen.c -+++ b/src/main/tls_listen.c -@@ -299,6 +299,8 @@ get_application_data: - packet->vps = NULL; - PTHREAD_MUTEX_UNLOCK(&sock->mutex); - -+ packet->tls = true; -+ - if (!rad_packet_ok(packet, 0, NULL)) { - if (DEBUG_ENABLED) ERROR("Receive - %s", fr_strerror()); - DEBUG("Closing TLS socket from client"); -@@ -713,6 +715,8 @@ int proxy_tls_recv(rad_listen_t *listener) - memcpy(packet->data, data, packet->data_len); - memcpy(packet->vector, packet->data + 4, 16); - -+ packet->tls = true; -+ - /* - * FIXME: Client MIB updates? - */ -@@ -765,6 +769,7 @@ int proxy_tls_send(rad_listen_t *listener, REQUEST *request) - * if there's no packet, encode it here. - */ - if (!request->proxy->data) { -+ request->reply->tls = true; - request->proxy_listener->encode(request->proxy_listener, - request); - } diff --git a/SOURCES/freeradius-bootstrap-fixed-dhparam.patch b/SOURCES/freeradius-bootstrap-fixed-dhparam.patch deleted file mode 100644 index 6121f4b..0000000 --- a/SOURCES/freeradius-bootstrap-fixed-dhparam.patch +++ /dev/null @@ -1,52 +0,0 @@ -From b31f1ab9a0e1c010037d2d660e3ce4ea7eb07d6c Mon Sep 17 00:00:00 2001 -From: Alexander Scheel -Date: Wed, 5 Aug 2020 16:10:52 -0400 -Subject: [PATCH] Use fixed FIPS-approved dhparam by default - -Signed-off-by: Alexander Scheel ---- - raddb/certs/Makefile | 2 +- - raddb/certs/bootstrap | 7 +++++-- - 2 files changed, 6 insertions(+), 3 deletions(-) - -diff --git a/raddb/certs/Makefile b/raddb/certs/Makefile -index 5cbfd46..41b7aea 100644 ---- a/raddb/certs/Makefile -+++ b/raddb/certs/Makefile -@@ -59,7 +59,7 @@ passwords.mk: server.cnf ca.cnf client.cnf inner-server.cnf - # - ###################################################################### - dh: -- $(OPENSSL) dhparam -out dh -2 $(DH_KEY_SIZE) -+ cp rfc3526-group-18-8192.dhparam dh - - ###################################################################### - # -diff --git a/raddb/certs/bootstrap b/raddb/certs/bootstrap -index 9920ecf..59b3310 100755 ---- a/raddb/certs/bootstrap -+++ b/raddb/certs/bootstrap -@@ -13,6 +13,10 @@ - umask 027 - cd `dirname $0` - -+if [ ! -e random ]; then -+ ln -sf /dev/urandom random -+fi -+ - make -h > /dev/null 2>&1 - - # -@@ -35,8 +39,7 @@ fi - # re-generate these commands. - # - if [ ! -e dh ]; then -- openssl dhparam -out dh 2048 || exit 1 -- ln -sf /dev/urandom random -+ cp rfc3526-group-18-8192.dhparam dh - fi - - if [ ! -e server.key ]; then --- -2.26.2 - diff --git a/SOURCES/freeradius-bootstrap-run-only-once.patch b/SOURCES/freeradius-bootstrap-run-only-once.patch deleted file mode 100644 index ae12c4e..0000000 --- a/SOURCES/freeradius-bootstrap-run-only-once.patch +++ /dev/null @@ -1,72 +0,0 @@ -Author: Antonio Torres -Date: Wed Jul 20 2021 -Subject: [PATCH] ensure bootstrap script is run only once - - The bootstrap script should only run once. By checking if there are - certificates in the directory, we can exit early if certificates were - already generated. - - Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1954521 - Signed-off-by: Antonio Torres antorres@redhat.com ---- - raddb/certs/README | 16 ++++++---------- - raddb/certs/bootstrap | 18 ++++++++++++------ - 2 files changed, 18 insertions(+), 16 deletions(-) - -diff --git a/raddb/certs/README b/raddb/certs/README -index 6288921da1..32413964dd 100644 ---- a/raddb/certs/README -+++ b/raddb/certs/README -@@ -29,17 +29,13 @@ the "ca_file", you permit them to masquerade as you, to authenticate - your users, and to issue client certificates for EAP-TLS. - - If FreeRADIUS was configured to use OpenSSL, then simply starting --the server in root in debugging mode should also create test --certificates, i.e.: -+the server in root mode should also create test certificates. - --$ radiusd -X -- -- That will cause the EAP-TLS module to run the "bootstrap" script in --this directory. The script will be executed only once, the first time --the server has been installed on a particular machine. This bootstrap --script SHOULD be run on installation of any pre-built binary package --for your OS. In any case, the script will ensure that it is not run --twice, and that it does not over-write any existing certificates. -+ The start of FreeRADIUS will cause to run the "bootstrap" script. -+The script will be executed during every start of FreeRADIUS via systemd but -+the script will ensure that it does not overwrite any existing certificates. -+Ideally, the bootstrap script file should be deleted after new testing certificates -+have been generated. - - If you already have CA and server certificates, rename (or delete) - this directory, and create a new "certs" directory containing your -diff --git a/raddb/certs/bootstrap b/raddb/certs/bootstrap -index 0f719aafd4..92254dc936 100755 ---- a/raddb/certs/bootstrap -+++ b/raddb/certs/bootstrap -@@ -1,12 +1,18 @@ - #!/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. -+# Bootstrap script should be run only once. If there are already certificates -+# generated, skip the execution. -+# -+cd `dirname $0` -+if [ $(ls -l *.{pem,crt,key} 2>/dev/null | wc -l) != 0 ]; then -+ exit 0 -+fi -+ - # --# 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. -+# This is a wrapper script to create default certificates when the -+# server starts via systemd. It should also ensure that the -+# permissions and owners are correct for the generated files. Once -+# the certificates have been created, this file should be deleted. - # - # $Id: 0f719aafd4c9abcdefbf547dedb6e7312c535104 $ - # diff --git a/SOURCES/freeradius-fix-crash-on-invalid-abinary-data.patch b/SOURCES/freeradius-fix-crash-on-invalid-abinary-data.patch deleted file mode 100644 index 4269fc2..0000000 --- a/SOURCES/freeradius-fix-crash-on-invalid-abinary-data.patch +++ /dev/null @@ -1,47 +0,0 @@ -From: Antonio Torres -Date: Fri, 09 Dec 2022 -Subject: Fix crash on invalid abinary data - -A malicious RADIUS client or home server can send a malformed abinary -attribute which can cause the server to crash. - -Backport of https://github.com/FreeRADIUS/freeradius-server/commit/0ec2b39d260e - -Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2151706 -Signed-off-by: Antonio Torres ---- -diff --git a/src/lib/filters.c b/src/lib/filters.c -index 4868cd385d9f..3f3b63daeef3 100644 ---- a/src/lib/filters.c -+++ b/src/lib/filters.c -@@ -1205,13 +1205,19 @@ void print_abinary(char *out, size_t outlen, uint8_t const *data, size_t len, in - } - } - } else if (filter->type == RAD_FILTER_GENERIC) { -- int count; -+ 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 < ntohs(filter->u.generic.len); count++) { -+ for (count = 0; count < masklen; count++) { - i = snprintf(p, outlen, "%02x", filter->u.generic.mask[count]); - p += i; - outlen -= i; -@@ -1222,7 +1228,7 @@ void print_abinary(char *out, size_t outlen, uint8_t const *data, size_t len, in - outlen--; - - /* show the value */ -- for (count = 0; count < ntohs(filter->u.generic.len); count++) { -+ for (count = 0; count < masklen; count++) { - i = snprintf(p, outlen, "%02x", filter->u.generic.value[count]); - p += i; - outlen -= i; diff --git a/SOURCES/freeradius-fix-crash-unknown-eap-sim.patch b/SOURCES/freeradius-fix-crash-unknown-eap-sim.patch deleted file mode 100644 index 4a2c2d1..0000000 --- a/SOURCES/freeradius-fix-crash-unknown-eap-sim.patch +++ /dev/null @@ -1,115 +0,0 @@ -From: Antonio Torres -Date: Fri, 09 Dec 2022 -Subject: Fix crash on unknown option in EAP-SIM - -When an EAP-SIM supplicant sends an unknown SIM option, the server will try to -look that option up in the internal dictionaries. This lookup will fail, but the -SIM code will not check for that failure. Instead, it will dereference a NULL -pointer, and cause the server to crash. - -Backport of: -https://github.com/FreeRADIUS/freeradius-server/commit/f1cdbb33ec61c4a64a -https://github.com/FreeRADIUS/freeradius-server/commit/71128cac3ee236a88a05cc7bddd43e43a88a3089 - -Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2151704 -Signed-off-by: Antonio Torres ---- -diff --git a/src/modules/rlm_eap/libeap/eapsimlib.c b/src/modules/rlm_eap/libeap/eapsimlib.c -index cf1e8a7dd92..e438a844eab 100644 ---- a/src/modules/rlm_eap/libeap/eapsimlib.c -+++ b/src/modules/rlm_eap/libeap/eapsimlib.c -@@ -307,42 +307,77 @@ int unmap_eapsim_basictypes(RADIUS_PACKET *r, - 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; - -- /* now, loop processing each attribute that we find */ -- while(attrlen > 0) { -+ /* -+ * 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) { -+ 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; - } - -- if(eapsim_len > MAX_STRING_LEN) { -- eapsim_len = MAX_STRING_LEN; -- } -- if (eapsim_len < 2) { -- fr_strerror_printf("EAP-Sim attribute %d (no.%d) has length too small", eapsim_attribute, -- es_attribute_count); -- return 0; -- } -+ newvp = fr_pair_afrom_num(r, eapsim_attribute + PW_EAP_SIM_BASE, 0); -+ 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; -+ } - -- newvp = fr_pair_afrom_num(r, eapsim_attribute+PW_EAP_SIM_BASE, 0); -- newvp->vp_length = eapsim_len-2; -- newvp->vp_octets = p = talloc_array(newvp, uint8_t, newvp->vp_length); -- memcpy(p, &attr[2], eapsim_len-2); -- fr_pair_add(&(r->vps), newvp); -- newvp = NULL; -+ } 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; diff --git a/SOURCES/freeradius-fix-info-leakage-eap-pwd.patch b/SOURCES/freeradius-fix-info-leakage-eap-pwd.patch deleted file mode 100644 index b236705..0000000 --- a/SOURCES/freeradius-fix-info-leakage-eap-pwd.patch +++ /dev/null @@ -1,76 +0,0 @@ -From: Antonio Torres -Date: Fri, 09 Dec 2022 -Subject: Fix information leakage in EAP-PWD - -The EAP-PWD function compute_password_element() leaks information about the -password which allows an attacker to substantially reduce the size of an -offline dictionary attack. - -Patch adapted from: https://github.com/FreeRADIUS/freeradius-server/commit/9e5e8f2f - -Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2151702 -Signed-off-by: Antonio Torres ---- -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 -index d94851c3aa..9f86b62114 100644 ---- a/src/modules/rlm_eap/types/rlm_eap_pwd/eap_pwd.c -+++ b/src/modules/rlm_eap/types/rlm_eap_pwd/eap_pwd.c -@@ -39,6 +39,8 @@ USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */ - #include - #include - -+static uint8_t allzero[SHA256_DIGEST_LENGTH] = { 0x00 }; -+ - /* The random function H(x) = HMAC-SHA256(0^32, x) */ - static void H_Init(HMAC_CTX *ctx) - { -@@ -114,15 +116,13 @@ int compute_password_element (pwd_session_t *session, uint16_t grp_num, - uint32_t *token) - { - BIGNUM *x_candidate = NULL, *rnd = NULL, *cofactor = NULL; -- HMAC_CTX *ctx = NULL; -+ EVP_MD_CTX *hmac_ctx; -+ EVP_PKEY *hmac_pkey; - uint8_t pwe_digest[SHA256_DIGEST_LENGTH], *prfbuf = NULL, ctr; - int nid, is_odd, primebitlen, primebytelen, ret = 0; - -- ctx = HMAC_CTX_new(); -- if (ctx == NULL) { -- DEBUG("failed allocating HMAC context"); -- goto fail; -- } -+ 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: -@@ -203,13 +203,12 @@ int compute_password_element (pwd_session_t *session, uint16_t grp_num, - * pwd-seed = H(token | peer-id | server-id | password | - * counter) - */ -- H_Init(ctx); -- H_Update(ctx, (uint8_t *)token, sizeof(*token)); -- H_Update(ctx, (uint8_t const *)id_peer, id_peer_len); -- H_Update(ctx, (uint8_t const *)id_server, id_server_len); -- H_Update(ctx, (uint8_t const *)password, password_len); -- H_Update(ctx, (uint8_t *)&ctr, sizeof(ctr)); -- H_Final(ctx, pwe_digest); -+ 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)); - - BN_bin2bn(pwe_digest, SHA256_DIGEST_LENGTH, rnd); - if (eap_pwd_kdf(pwe_digest, SHA256_DIGEST_LENGTH, "EAP-pwd Hunting And Pecking", -@@ -282,7 +281,8 @@ int compute_password_element (pwd_session_t *session, uint16_t grp_num, - BN_clear_free(x_candidate); - BN_clear_free(rnd); - talloc_free(prfbuf); -- HMAC_CTX_free(ctx); -+ EVP_MD_CTX_free(hmac_ctx); -+ EVP_PKEY_free(hmac_pkey); - - return ret; - } diff --git a/SOURCES/freeradius-fixes-to-python3-module-since-v3.0.20.patch b/SOURCES/freeradius-fixes-to-python3-module-since-v3.0.20.patch deleted file mode 100644 index fb96df2..0000000 --- a/SOURCES/freeradius-fixes-to-python3-module-since-v3.0.20.patch +++ /dev/null @@ -1,1955 +0,0 @@ -From 322f3b0d94f32e01e2db0c76fd38409eddf392ce Mon Sep 17 00:00:00 2001 -From: Jorge Pereira -Date: Thu, 5 Dec 2019 16:02:18 -0300 -Subject: [PATCH] Fix rlm_python3 build - -Just backporting from the master branch. - -Backport from rlm_python (#3184) changes to rlm_python3 - -Brief: - -We should append the 'python_path' to sys.path #3180 - -we should append 'python_path' paths in 'sys.path', due to PySys_SetPath() -reset the entire python path causing problems to use the existing libraries - -Remove unnecessary src/modules/rlm_python3/radiusd_test.py - -Don't call if 'instantiate' and 'detach' are not declared. - -It's related to the discussion in #3185. - -Fix missing destroy for some statements - -Fix Py_SetProgramName() use (#3196) - -As the documentation says, the use of Py_SetProgramName() with wchar_t* -should be only from Python >= 3.5.x - -References: - -Python <= 3.4.x https://docs.python.org/3.4/extending/embedding.html#very-high-level-embedding -Python >= 3.5.x https://docs.python.org/3.5/extending/embedding.html#very-high-level-embedding - -Add missing 'ifdef WITH_PROXY' checks (#3198) - -Clean up (#3197) - -don't try and build rlm_python3 if we can't configure it - -Just call Py_DECREF() (#3199) - -Fix libpython3 cross platform load (#3284) - -Python3 fixes (#3350) - -* python3-config for Python 3.8 requires --embed parameter - -As described in https://bugs.python.org/issue36721, python3-config now -requires --embed for embedded interpreters. Otherwise, -lpython3.8 is -not included in ldflags - -* Python 3.8 has removed the "m" suffix in the library name - -As discussed in: https://bugs.python.org/issue36707 - -* Use dl_iterate_phdr to find the appropriate python library - -Otherwise, installation of the libpython3-dev packages is required -in most distributions - -* Update configure file for rlm_python3 - -* Use AX_COMPARE_VERSION to check Python version - -Keep the module directory in python_path ---- - raddb/mods-available/python | 2 +- - raddb/mods-available/python3 | 2 +- - src/include/conf.h | 8 + - src/main/modules.c | 8 - - src/modules/rlm_python3/configure | 1008 ++++++++--------------- - src/modules/rlm_python3/configure.ac | 163 ++-- - src/modules/rlm_python3/radiusd_test.py | 63 -- - src/modules/rlm_python3/rlm_python3.c | 188 ++--- - 8 files changed, 516 insertions(+), 926 deletions(-) - delete mode 100644 src/modules/rlm_python3/radiusd_test.py - -diff --git a/raddb/mods-available/python b/raddb/mods-available/python -index bd172dca05..c19ddcd87e 100644 ---- a/raddb/mods-available/python -+++ b/raddb/mods-available/python -@@ -13,7 +13,7 @@ python { - # item is GLOBAL TO THE SERVER. That is, you cannot have two - # instances of the python module, each with a different path. - # --# python_path="/path/to/python/files:/another_path/to/python_files/" -+# python_path="${modconfdir}/${.:name}:/path/to/python/files:/another_path/to/python_files/" - - module = example - -diff --git a/raddb/mods-available/python3 b/raddb/mods-available/python3 -index 246dfd74ce..0593c69f1a 100644 ---- a/raddb/mods-available/python3 -+++ b/raddb/mods-available/python3 -@@ -13,7 +13,7 @@ python3 { - # item is GLOBAL TO THE SERVER. That is, you cannot have two - # instances of the python module, each with a different path. - # --# python_path="/path/to/python/files:/another_path/to/python_files/" -+# python_path="${modconfdir}/${.:name}:/another_path/to/python_files" - - module = example - -diff --git a/src/include/conf.h b/src/include/conf.h -index 758a332b6e..95005d545f 100644 ---- a/src/include/conf.h -+++ b/src/include/conf.h -@@ -13,3 +13,11 @@ - #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/main/modules.c b/src/main/modules.c -index 319879c870..c05aa5bf67 100644 ---- a/src/main/modules.c -+++ b/src/main/modules.c -@@ -95,14 +95,6 @@ const section_type_value_t section_type_value[MOD_COUNT] = { - #define RTLD_LOCAL (0) - #endif - --#ifdef __APPLE__ --# define LT_SHREXT ".dylib" --#elif defined (WIN32) --# define LT_SHREXT ".dll" --#else --# define LT_SHREXT ".so" --#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 -diff --git a/src/modules/rlm_python3/configure b/src/modules/rlm_python3/configure -index ff89a16149..05907f12c3 100755 ---- a/src/modules/rlm_python3/configure -+++ b/src/modules/rlm_python3/configure -@@ -588,7 +588,17 @@ LIBOBJS - targetname - mod_cflags - mod_ldflags --PYTHON3_BIN -+AWK -+PYTHON3_CONFIG_BIN -+pkgpyexecdir -+pyexecdir -+pkgpythondir -+pythondir -+PYTHON_PLATFORM -+PYTHON_EXEC_PREFIX -+PYTHON_PREFIX -+PYTHON_VERSION -+PYTHON - CPP - OBJEXT - EXEEXT -@@ -638,9 +648,7 @@ SHELL' - ac_subst_files='' - ac_user_opts=' - enable_option_checking --with_rlm_python3_bin --with_rlm_python3_lib_dir --with_rlm_python3_include_dir -+with_rlm_python3_config_bin - ' - ac_precious_vars='build_alias - host_alias -@@ -650,7 +658,8 @@ CFLAGS - LDFLAGS - LIBS - CPPFLAGS --CPP' -+CPP -+PYTHON' - - - # Initialize some variables set by options. -@@ -1257,9 +1266,7 @@ if test -n "$ac_init_help"; then - Optional Packages: - --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] - --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) -- --with-rlm-python3-bin=PATH Path to python3 binary -- --with-rlm-python3-lib-dir=DIR Directory for Python library files -- --with-rlm-python3-include-dir=DIR Directory for Python include files -+ --with-rlm-python3-config-bin=PATH Path to python-config3 binary - - Some influential environment variables: - CC C compiler command -@@ -1270,6 +1277,7 @@ Some influential environment variables: - CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if - you have headers in a nonstandard directory - 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. -@@ -2822,46 +2830,92 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $ - ac_compiler_gnu=$ac_cv_c_compiler_gnu - - -- PYTHON3_BIN= - --# Check whether --with-rlm-python3-bin was given. --if test "${with_rlm_python3_bin+set}" = set; then : -- withval=$with_rlm_python3_bin; case "$withval" in -- no) -- as_fn_error $? "Need rlm-python3-bin" "$LINENO" 5 -- ;; -- yes) -- ;; -- *) -- PYTHON3_BIN="$withval" -- ;; -- esac - --fi - - -- if test "x$PYTHON3_BIN" = x; then -- for ac_prog in python3 --do -- # Extract the first word of "$ac_prog", so it can be a program name with args. --set dummy $ac_prog; ac_word=$2 -+ -+ 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.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_prog_PYTHON3_BIN+:} false; then : -+if ${ac_cv_path_PYTHON+:} false; then : - $as_echo_n "(cached) " >&6 - else -- if test -n "$PYTHON3_BIN"; then -- ac_cv_prog_PYTHON3_BIN="$PYTHON3_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 -+ 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_prog_PYTHON3_BIN="$ac_prog" -+ 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 -@@ -2869,708 +2923,358 @@ done - done - IFS=$as_save_IFS - -+ ;; -+esac - fi --fi --PYTHON3_BIN=$ac_cv_prog_PYTHON3_BIN --if test -n "$PYTHON3_BIN"; then -- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTHON3_BIN" >&5 --$as_echo "$PYTHON3_BIN" >&6; } -+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 - - -- test -n "$PYTHON3_BIN" && break --done --test -n "$PYTHON3_BIN" || PYTHON3_BIN="not-found" -- -- fi -- -- if test "x$PYTHON3_BIN" = "xnot-found"; then -- fail="python-binary" -- fi -- -- PY_LIB_DIR= -- --# Check whether --with-rlm-python3-lib-dir was given. --if test "${with_rlm_python3_lib_dir+set}" = set; then : -- withval=$with_rlm_python3_lib_dir; case "$withval" in -- no) -- as_fn_error $? "Need rlm-python3-lib-dir" "$LINENO" 5 -- ;; -- yes) -- ;; -- *) -- PY_LIB_DIR="$withval" -- ;; -- esac -- --fi -+ fi -+ am_display_PYTHON=$am_cv_pathless_PYTHON -+ fi - - -- PY_INC_DIR= -+ if test "$PYTHON" = :; then -+ : -+ else - --# Check whether --with-rlm-python3-include-dir was given. --if test "${with_rlm_python3_include_dir+set}" = set; then : -- withval=$with_rlm_python3_include_dir; case "$withval" in -- no) -- as_fn_error $? "Need rlm-python3-include-dir" "$LINENO" 5 -- ;; -- yes) -- ;; -- *) -- PY_INC_DIR="$withval" -- ;; -- esac - -+ { $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; sys.stdout.write(sys.version[:3])"` - 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 - - -- if test x$fail = x; then -- PY_PREFIX=`${PYTHON3_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=`${PYTHON3_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=`${PYTHON3_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" -- - -+ PYTHON_PREFIX='${prefix}' - --ac_safe=`echo "Python.h" | sed 'y%./+-%__pm%'` --old_CPPFLAGS="$CPPFLAGS" --smart_include= --smart_include_dir="/usr/local/include /opt/include" -+ PYTHON_EXEC_PREFIX='${exec_prefix}' - --_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 --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 - -+ { $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 -- -- smart_include= -- { $as_echo "$as_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 --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 -- -+ 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 -+ -+ -+ # Just factor out some code duplication. -+ 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: -+# -+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" >&5 -+$as_echo_n "checking for $am_display_PYTHON script directory... " >&6; } -+if ${am_cv_python_pythondir+:} false; then : -+ $as_echo_n "(cached) " >&6 - else -+ if test "x$prefix" = xNONE -+ then -+ am_py_prefix=$ac_default_prefix -+ else -+ am_py_prefix=$prefix -+ fi -+ am_cv_python_pythondir=`$PYTHON -c " -+$am_python_setup_sysconfig -+if can_use_sysconfig: -+ sitedir = sysconfig.get_path('purelib', 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 - -- smart_include= -- { $as_echo "$as_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 -+{ $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 - --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 --int --main () --{ --int a = 1; -- ; -- return 0; --} --_ACEOF --if ac_fn_c_try_compile "$LINENO"; then : -+ pkgpythondir=\${pythondir}/$PACKAGE - -- smart_include=" " -- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 --$as_echo "yes" >&6; } -- break - -+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $am_display_PYTHON extension module directory" >&5 -+$as_echo_n "checking for $am_display_PYTHON extension module directory... " >&6; } -+if ${am_cv_python_pyexecdir+:} false; then : -+ $as_echo_n "(cached) " >&6 - else -- -- smart_include= -- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 --$as_echo "no" >&6; } -+ if test "x$exec_prefix" = xNONE -+ then -+ am_py_exec_prefix=$am_py_prefix -+ else -+ am_py_exec_prefix=$exec_prefix -+ fi -+ am_cv_python_pyexecdir=`$PYTHON -c " -+$am_python_setup_sysconfig -+if can_use_sysconfig: -+ sitedir = sysconfig.get_path('platlib', vars={'platbase':'$am_py_prefix'}) -+else: -+ from distutils import sysconfig -+ sitedir = sysconfig.get_python_lib(1, 0, prefix='$am_py_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 --rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext --fi -- --if test "x$smart_include" = "x"; then -+{ $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 - -- for prefix in $smart_prefix; do - - --if test "x$LOCATE" != "x"; then -- DIRS= -- file="${_prefix}/${1}" -+ pkgpyexecdir=\${pyexecdir}/$PACKAGE - -- for x in `${LOCATE} $file 2>/dev/null`; do -- base=`echo $x | sed "s%/${file}%%"` -- if test "x$x" = "x$base"; then -- continue; -- fi -- -- dir=`${DIRNAME} $x 2>/dev/null` -- exclude=`echo ${dir} | ${GREP} /home` -- if test "x$exclude" != "x"; then -- continue -- fi -- -- already=`echo \$_smart_include_dir ${DIRS} | ${GREP} ${dir}` -- if test "x$already" = "x"; then -- DIRS="$DIRS $dir" -- fi -- done --fi - --eval "_smart_include_dir=\"\$_smart_include_dir $DIRS\"" - -- done -+ fi - - --if test "x$LOCATE" != "x"; then -- DIRS= -- file=Python.h - -- for x in `${LOCATE} $file 2>/dev/null`; do -- base=`echo $x | sed "s%/${file}%%"` -- if test "x$x" = "x$base"; then -- continue; -- fi -+ PYTHON3_CONFIG_BIN= - -- dir=`${DIRNAME} $x 2>/dev/null` -- exclude=`echo ${dir} | ${GREP} /home` -- if test "x$exclude" != "x"; then -- continue -- fi -+# 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 - -- already=`echo \$_smart_include_dir ${DIRS} | ${GREP} ${dir}` -- if test "x$already" = "x"; then -- DIRS="$DIRS $dir" -- fi -- done - fi - --eval "_smart_include_dir=\"\$_smart_include_dir $DIRS\"" -- -- -- for try in $_smart_include_dir; do -- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 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 --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 - -+ 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 -- -- smart_include= -- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 --$as_echo "no" >&6; } -- --fi --rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -+ 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 -- 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" -- targetname= -- 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 -+IFS=$as_save_IFS - --else -- { $as_echo "$as_me:${as_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; } -- -+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 --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 - -+ test -n "$PYTHON3_CONFIG_BIN" && break -+done -+test -n "$PYTHON3_CONFIG_BIN" || PYTHON3_CONFIG_BIN="not-found" - --if test "x$LOCATE" != "x"; then -- DIRS= -- file=libpython${PY_SYS_VERSION}${libltdl_cv_shlibext} -- -- for x in `${LOCATE} $file 2>/dev/null`; do -- base=`echo $x | sed "s%/${file}%%"` -- if test "x$x" = "x$base"; then -- continue; -- fi -- -- dir=`${DIRNAME} $x 2>/dev/null` -- exclude=`echo ${dir} | ${GREP} /home` -- if test "x$exclude" != "x"; then -- continue -- fi -- -- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}` -- if test "x$already" = "x"; then -- DIRS="$DIRS $dir" -- fi -- done --fi -- --eval "smart_lib_dir=\"\$smart_lib_dir $DIRS\"" -- -- -- --if test "x$LOCATE" != "x"; then -- DIRS= -- file=libpython${PY_SYS_VERSION}.a -- -- for x in `${LOCATE} $file 2>/dev/null`; do -- base=`echo $x | sed "s%/${file}%%"` -- if test "x$x" = "x$base"; then -- continue; -- fi -- -- dir=`${DIRNAME} $x 2>/dev/null` -- exclude=`echo ${dir} | ${GREP} /home` -- if test "x$exclude" != "x"; then -- continue -- fi -- -- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}` -- if test "x$already" = "x"; then -- DIRS="$DIRS $dir" -- fi -- done --fi -- --eval "smart_lib_dir=\"\$smart_lib_dir $DIRS\"" -- -- -- for try in $smart_lib_dir /usr/local/lib /opt/lib; do -- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Py_Initialize in -lpython${PY_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 -+ 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; -+ '` -+ { $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 -- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 --$as_echo "no" >&6; } --fi --rm -f core conftest.err conftest.$ac_objext \ -- conftest$ac_exeext conftest.$ac_ext -+ 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 -- 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" -- targetname=rlm_python3 -- 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 -+IFS=$as_save_IFS - --else -- { $as_echo "$as_me:${as_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; } -- -+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 --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 - -+ test -n "$AWK" && break -+done - --if test "x$LOCATE" != "x"; then -- DIRS= -- file=libpython${PY_SYS_VERSION}m${libltdl_cv_shlibext} - -- for x in `${LOCATE} $file 2>/dev/null`; do -- base=`echo $x | sed "s%/${file}%%"` -- if test "x$x" = "x$base"; then -- continue; -- fi - -- dir=`${DIRNAME} $x 2>/dev/null` -- exclude=`echo ${dir} | ${GREP} /home` -- if test "x$exclude" != "x"; then -- continue -- fi - -- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}` -- if test "x$already" = "x"; then -- DIRS="$DIRS $dir" -- fi -- done --fi -+ # Used to indicate true or false condition -+ ax_compare_version=false - --eval "smart_lib_dir=\"\$smart_lib_dir $DIRS\"" -+ # 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'` - - --if test "x$LOCATE" != "x"; then -- DIRS= -- file=libpython${PY_SYS_VERSION}m.a -+ 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'` - -- for x in `${LOCATE} $file 2>/dev/null`; do -- base=`echo $x | sed "s%/${file}%%"` -- if test "x$x" = "x$base"; then -- continue; -- fi - -- dir=`${DIRNAME} $x 2>/dev/null` -- exclude=`echo ${dir} | ${GREP} /home` -- if test "x$exclude" != "x"; then -- continue -- fi -+ 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"` - -- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}` -- if test "x$already" = "x"; then -- DIRS="$DIRS $dir" -- fi -- done --fi - --eval "smart_lib_dir=\"\$smart_lib_dir $DIRS\"" - -+ if test "$ax_compare_version" = "true" ; then -+ EMBED="--embed" -+ fi - -- for try in $smart_lib_dir /usr/local/lib /opt/lib; do -- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Py_Initialize in -lpython${PY_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 -+ 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;} - --else -- { $as_echo "$as_me:${as_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 -+ 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;} - --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 -+ CFLAGS=$old_CFLAGS - -- eval t=\${ac_cv_lib_${sm_lib_safe}_${sm_func_safe}} -- if test "x$t" = "xyes"; then -- mod_ldflags="$PY_LIB_LOC $PY_EXTRA_LIBS $SMART_LIBS -lm" -- targetname=rlm_python3 -- else -- targetname= -- fail="$fail libpython$PY_SYS_VERSION" -- fi -- fi -+ targetname="rlm_python3" - fi - -- for ac_func in dl_iterate_phdr -+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 : -@@ -3603,11 +3307,7 @@ ac_config_headers="$ac_config_headers config.h" - - - -- -- unset ac_cv_env_LIBS_set -- unset ac_cv_env_LIBS_value -- -- ac_config_files="$ac_config_files all.mk" -+ac_config_files="$ac_config_files all.mk" - - cat >confcache <<\_ACEOF - # This file is a shell script that caches the results of configure -@@ -4187,6 +3887,7 @@ gives unlimited permission to copy, distribute and modify it." - - ac_pwd='$ac_pwd' - srcdir='$srcdir' -+AWK='$AWK' - test -n "\$AWK" || AWK=awk - _ACEOF - -@@ -4881,4 +4582,3 @@ if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then - $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 -index a00320fda4..698a8c1d18 100644 ---- a/src/modules/rlm_python3/configure.ac -+++ b/src/modules/rlm_python3/configure.ac -@@ -7,128 +7,81 @@ if test x$with_[]modname != xno; then - - AC_PROG_CC - AC_PROG_CPP -+ AM_PATH_PYTHON([3.0],, [:]) - -- dnl extra argument: --with-rlm-python3-bin -- PYTHON3_BIN= -- AC_ARG_WITH(rlm-python3-bin, -- [ --with-rlm-python3-bin=PATH Path to python3 binary []], -+ dnl extra argument: --with-rlm-python3-config-bin -+ PYTHON3_CONFIG_BIN= -+ AC_ARG_WITH(rlm-python3-config-bin, -+ [ --with-rlm-python3-config-bin=PATH Path to python-config3 binary []], - [ case "$withval" in - no) -- AC_MSG_ERROR(Need rlm-python3-bin) -+ AC_MSG_ERROR(Need rlm-python3-config-bin) - ;; - yes) - ;; - *) -- PYTHON3_BIN="$withval" -+ PYTHON3_CONFIG_BIN="$withval" - ;; - esac ] - ) - -- if test "x$PYTHON3_BIN" = x; then -- AC_CHECK_PROGS(PYTHON3_BIN, [ python3 ], not-found, [${PATH}:/usr/bin:/usr/local/bin]) -+ 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_BIN" = "xnot-found"; then -- fail="python-binary" -- fi -- -- dnl extra argument: --with-rlm-python3-lib-dir -- PY_LIB_DIR= -- AC_ARG_WITH(rlm-python3-lib-dir, -- [ --with-rlm-python3-lib-dir=DIR Directory for Python library files []], -- [ case "$withval" in -- no) -- AC_MSG_ERROR(Need rlm-python3-lib-dir) -- ;; -- yes) -- ;; -- *) -- PY_LIB_DIR="$withval" -- ;; -- esac ] -- ) -- -- dnl extra argument: --with-rlm-python3-include-dir -- PY_INC_DIR= -- AC_ARG_WITH(rlm-python3-include-dir, -- [ --with-rlm-python3-include-dir=DIR Directory for Python include files []], -- [ case "$withval" in -- no) -- AC_MSG_ERROR(Need rlm-python3-include-dir) -- ;; -- yes) -- ;; -- *) -- PY_INC_DIR="$withval" -- ;; -- esac ] -- ) -- -- if test x$fail = x; then -- PY_PREFIX=`${PYTHON3_BIN} -c 'import sys ; print(sys.prefix)'` -- AC_MSG_NOTICE([Python sys.prefix \"${PY_PREFIX}\"]) -- -- PY_EXEC_PREFIX=`${PYTHON3_BIN} -c 'import sys ; print(sys.exec_prefix)'` -- AC_MSG_NOTICE([Python sys.exec_prefix \"${PY_EXEC_PREFIX}\"]) -- -- PY_SYS_VERSION=`${PYTHON3_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" -+ if test "x$PYTHON3_CONFIG_BIN" = xnot-found; then -+ fail="$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 -+ 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; -+ '` -+ 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}\"]) - -- 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 -- fail="$fail Python.h" -- targetname= -- 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" -- targetname=modname -- 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" -- targetname=modname -- else -- targetname= -- fail="$fail libpython$PY_SYS_VERSION" -- fi -- fi -+ targetname="rlm_python3" - fi -- - AC_CHECK_FUNCS([dl_iterate_phdr]) - else - targetname= -diff --git a/src/modules/rlm_python3/radiusd_test.py b/src/modules/rlm_python3/radiusd_test.py -deleted file mode 100644 -index 8582716ccb..0000000000 ---- a/src/modules/rlm_python3/radiusd_test.py -+++ /dev/null -@@ -1,63 +0,0 @@ --#! /usr/bin/env python3 --# --# Python module test --# Miguel A.L. Paraz --# --# $Id: 8582716ccbf340be00ce081ecf5ab078e93d1183 $ -- --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_python3/rlm_python3.c b/src/modules/rlm_python3/rlm_python3.c -index 06187e4ffa..5da23f4d71 100644 ---- a/src/modules/rlm_python3/rlm_python3.c -+++ b/src/modules/rlm_python3/rlm_python3.c -@@ -41,8 +41,17 @@ RCSID("$Id$") - #include - #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) "m.so" -+ "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; -@@ -67,8 +76,10 @@ static CONF_PARSER module_config[] = { - 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) -@@ -98,7 +109,9 @@ static struct { - 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) -@@ -186,18 +199,16 @@ static void python_error_log(void) - - if (!pExcType || !pExcValue) { - ERROR("%s:%d, Unknown error", __func__, __LINE__); -- if (pExcType) { -- Py_DecRef(pExcType); -- } -- if (pExcValue) { -- Py_DecRef(pExcValue); -- } -+ 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) { -@@ -217,46 +228,23 @@ static void python_error_log(void) - char *str = PyBytes_AsString(pTraceString); - ERROR("%s:%d, full_backtrace: %s", __func__, __LINE__, str); - -- if (pyth_val) { -- Py_DecRef(pyth_val); -- } -- if (pystr) { -- Py_DecRef(pystr); -- } -- if (pTraceString) { -- Py_DecRef(pTraceString); -- } -+ Py_DECREF(pyth_val); -+ Py_DECREF(pystr); -+ Py_DECREF(pTraceString); -+ Py_DECREF(pyth_func); - } -- if (pyth_func) { -- Py_DecRef(pyth_func); -- } -- Py_DecRef(pyth_module); -+ Py_DECREF(pyth_module); - } else { - ERROR("%s:%d, py_module is null, name: %p", __func__, __LINE__, module_name); - } - -- if (module_name) { -- Py_DecRef(module_name); -- } -- -- Py_DecRef(pRepr); -+ Py_DECREF(module_name); -+ Py_DECREF(pRepr); -+ Py_DECREF(pExcTraceback); - } - -- if (pExcType) { -- Py_DecRef(pExcType); -- } -- if (pExcValue) { -- Py_DecRef(pExcValue); -- } -- if (pExcTraceback) { -- Py_DecRef(pExcTraceback); -- } -- if (pStr1) { -- Py_DecRef(pStr1); -- } -- if (pStr2) { -- Py_DecRef(pStr2); -- } -+ Py_DECREF(pExcType); -+ Py_DECREF(pExcValue); - } - - static void mod_vptuple(TALLOC_CTX *ctx, REQUEST *request, VALUE_PAIR **vps, PyObject *pValue, -@@ -510,6 +498,7 @@ static rlm_rcode_t do_python_single(REQUEST *request, PyObject *pFunc, char cons - goto finish; - } - -+#ifdef WITH_PROXY - /* fill proxy vps */ - if (request->proxy) { - if (!mod_populate_vps(pArgs, 4, request->proxy->vps)) { -@@ -517,10 +506,13 @@ static rlm_rcode_t do_python_single(REQUEST *request, PyObject *pFunc, char cons - ret = RLM_MODULE_FAIL; - goto finish; - } -- } else { -+ } 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)) { -@@ -528,7 +520,9 @@ static rlm_rcode_t do_python_single(REQUEST *request, PyObject *pFunc, char cons - ret = RLM_MODULE_FAIL; - goto finish; - } -- } else { -+ } else -+#endif -+ { - mod_populate_vps(pArgs, 5, NULL); - } - -@@ -550,9 +544,14 @@ static rlm_rcode_t do_python_single(REQUEST *request, PyObject *pFunc, char cons - 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, "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))) { -+ 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; -@@ -819,8 +818,10 @@ 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) -@@ -1102,7 +1103,7 @@ static int python_interpreter_init(rlm_python_t *inst, CONF_SECTION *conf) - 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 -+#if PY_VERSION_HEX >= 0x03050000 - { - wchar_t *name; - -@@ -1110,13 +1111,6 @@ static int python_interpreter_init(rlm_python_t *inst, CONF_SECTION *conf) - Py_SetProgramName(name); /* The value of argv[0] as a wide char string */ - PyMem_RawFree(name); - } --#elif PY_VERSION_HEX > 0x0300000 -- { -- wchar_t *name; -- -- MEM(name = _Py_char2wchar(main_config.name, NULL)); -- Py_SetProgramName(inst->wide_name); /* The value of argv[0] as a wide char string */ -- } - #else - { - char *name; -@@ -1163,37 +1157,34 @@ static int python_interpreter_init(rlm_python_t *inst, CONF_SECTION *conf) - * 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 *path; -- PyObject* sys = PyImport_ImportModule("sys"); -- PyObject* sys_path = PyObject_GetAttrString(sys,"path"); -- -- MEM(path = Py_DecodeLocale(inst->python_path, NULL)); -- PyList_Append(sys_path, PyUnicode_FromWideChar(path,-1)); -- PyObject_SetAttrString(sys,"path",sys_path); -- PyMem_RawFree(path); -- } -+ 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 *path; -- PyObject* sys = PyImport_ImportModule("sys"); -- PyObject* sys_path = PyObject_GetAttrString(sys,"path"); -- -- MEM(path = _Py_char2wchar(inst->python_path, NULL)); -- PyList_Append(sys_path, PyUnicode_FromWideChar(path,-1)); -- PyObject_SetAttrString(sys,"path",sys_path); -- } --#else -- { -- char *path; -+ wchar_t *py_path; - -- memcpy(&path, &inst->python_path, sizeof(path)); -- Py_SetPath(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); -@@ -1220,7 +1211,7 @@ static int python_interpreter_init(rlm_python_t *inst, CONF_SECTION *conf) - static int mod_instantiate(CONF_SECTION *conf, void *instance) - { - rlm_python_t *inst = instance; -- int code = 0; -+ int code = RLM_MODULE_OK; - - inst->name = cf_section_name2(conf); - if (!inst->name) inst->name = cf_section_name1(conf); -@@ -1245,8 +1236,10 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance) - 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); -@@ -1257,12 +1250,14 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance) - /* - * Call the instantiate function. - */ -- 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; -+ if (inst->instantiate.function) { -+ 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(); - -@@ -1272,22 +1267,31 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance) - static int mod_detach(void *instance) - { - rlm_python_t *inst = instance; -- int ret; -+ int ret = RLM_MODULE_OK; - - /* - * 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 (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(authorize); - 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); -@@ -1313,14 +1317,8 @@ static int mod_detach(void *instance) - 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); -- //if (inst->wide_path) PyMem_RawFree(inst->wide_path); --#endif - } - -- - return ret; - } - -@@ -1348,8 +1346,10 @@ module_t rlm_python3 = { - [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, --- -2.26.2 - diff --git a/SOURCES/freeradius-man-Fix-some-typos.patch b/SOURCES/freeradius-man-Fix-some-typos.patch deleted file mode 100644 index ad4e188..0000000 --- a/SOURCES/freeradius-man-Fix-some-typos.patch +++ /dev/null @@ -1,93 +0,0 @@ -From 285f6f1891e8e8acfeb7281136efdae50dbfbe78 Mon Sep 17 00:00:00 2001 -From: Nikolai Kondrashov -Date: Fri, 14 Sep 2018 11:53:28 +0300 -Subject: [PATCH] man: Fix some typos - ---- - man/man1/radzap.1 | 4 ++-- - man/man5/unlang.5 | 6 +++--- - man/man8/radcrypt.8 | 2 +- - man/man8/radiusd.8 | 4 ++-- - 4 files changed, 8 insertions(+), 8 deletions(-) - -diff --git a/man/man1/radzap.1 b/man/man1/radzap.1 -index a2d529d064..03b9a43a54 100644 ---- a/man/man1/radzap.1 -+++ b/man/man1/radzap.1 -@@ -1,4 +1,4 @@ --.TH RADZAP 1 "8 April 2005" "" "FreeRadius Daemon" -+.TH RADZAP 1 "8 April 2005" "" "FreeRADIUS Daemon" - .SH NAME - radzap - remove rogue entries from the active sessions database - .SH SYNOPSIS -@@ -17,7 +17,7 @@ radzap - remove rogue entries from the active sessions database - .RB [ \-x ] - \fIserver[:port] secret\fP - .SH DESCRIPTION --The FreeRadius server can be configured to maintain an active session -+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 -diff --git a/man/man5/unlang.5 b/man/man5/unlang.5 -index 40db5fa6e7..5f765f1787 100644 ---- a/man/man5/unlang.5 -+++ b/man/man5/unlang.5 -@@ -195,7 +195,7 @@ The can be one of "request", "reply", "proxy-request", - of Version 3, the can be omitted, in which case "request" is - assumed. - --The "control" list is the list of attributes maintainted internally by -+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. -@@ -397,7 +397,7 @@ 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 comparings strings to an empty string, rather than by -+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 -@@ -854,7 +854,7 @@ 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 faiures are not catastrophic. -+administrator determines that the failures are not catastrophic. - .IP reject - Causes the request to be immediately rejected - .SH MODULE RETURN CODES -diff --git a/man/man8/radcrypt.8 b/man/man8/radcrypt.8 -index 08336c66f2..2917f60c46 100644 ---- a/man/man8/radcrypt.8 -+++ b/man/man8/radcrypt.8 -@@ -30,7 +30,7 @@ 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. -+the plaintext password. - - .SH EXAMPLES - .nf -diff --git a/man/man8/radiusd.8 b/man/man8/radiusd.8 -index 98aef5e1be..2ef5ccf789 100644 ---- a/man/man8/radiusd.8 -+++ b/man/man8/radiusd.8 -@@ -211,11 +211,11 @@ 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 -+Defines certain hints to the radius server based on the users' 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. Ofcourse -+"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 diff --git a/SOURCES/freeradius-no-dh-param-load-FIPS.patch b/SOURCES/freeradius-no-dh-param-load-FIPS.patch deleted file mode 100644 index b727a26..0000000 --- a/SOURCES/freeradius-no-dh-param-load-FIPS.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 42693cba452efa00a4848beb1514229149520cc1 Mon Sep 17 00:00:00 2001 -From: Alexander Scheel -Date: Wed, 5 Aug 2020 11:39:45 -0400 -Subject: [PATCH] Ignore user-provided dhparams in FIPS mode (#3554) - -OpenSSL in RHEL 8.3 introduces a breaking change in FIPS mode: -user-provided dhparams will be ignored (and dhparam generation -may fail as well), unless they are on the FIPS approved list of -parameters. However, OpenSSL since v1.1.1 will automatically select -an appropriate DH parameter set anyways, if the user did not provide -any. These will be FIPS approved. - -Signed-off-by: Alexander Scheel ---- - src/main/tls.c | 17 +++++++++++++++++ - 1 file changed, 17 insertions(+) - -diff --git a/src/main/tls.c b/src/main/tls.c -index 5809a1bd7d..5e6493333c 100644 ---- a/src/main/tls.c -+++ b/src/main/tls.c -@@ -1352,6 +1352,23 @@ static int load_dh_params(SSL_CTX *ctx, char *file) - - if (!file) return 0; - -+ /* -+ * 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."); -+ return 0; -+ } -+#endif -+ - if ((bio = BIO_new_file(file, "r")) == NULL) { - ERROR(LOG_PREFIX ": Unable to open DH file - %s", file); - return -1; diff --git a/SOURCES/rfc3526-group-18-8192.pem b/SOURCES/rfc3526-group-18-8192.pem deleted file mode 100644 index af54dd6..0000000 --- a/SOURCES/rfc3526-group-18-8192.pem +++ /dev/null @@ -1,24 +0,0 @@ ------BEGIN DH PARAMETERS----- -MIIECAKCBAEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb -IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft -awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT -mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh -fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq -5RXSJhiY+gUQFXKOWoqqxC2tMxcNBFB6M6hVIavfHLpk7PuFBFjb7wqK6nFXXQYM -fbOXD4Wm4eTHq/WujNsJM9cejJTgSiVhnc7j0iYa0u5r8S/6BtmKCGTYdgJzPshq -ZFIfKxgXeyAMu+EXV3phXWx3CYjAutlG4gjiT6B05asxQ9tb/OD9EI5LgtEgqSEI -ARpyPBKnh+bXiHGaEL26WyaZwycYavTiPBqUaDS2FQvaJYPpyirUTOjbu8LbBN6O -+S6O/BQfvsqmKHxZR05rwF2ZspZPoJDDoiM7oYZRW+ftH2EpcM7i16+4G912IXBI -HNAGkSfVsFqpk7TqmI2P3cGG/7fckKbAj030Nck0AoSSNsP6tNJ8cCbB1NyyYCZG -3sl1HnY9uje9+P+UBq2eUw7l2zgvQTABrrBqU+2QJ9gxF5cnsIZaiRjaPtvrz5sU -7UTObLrO1Lsb238UR+bMJUszIFFRK9evQm+49AE3jNK/WYPKAcZLkuzwMuoV0XId -A/SC185udP721V5wL0aYDIK1qEAxkAscnlnnyX++x+jzI6l6fjbMiL4PHUW3/1ha -xUvUB7IrQVSqzI9tfr9I4dgUzF7SD4A34KeXFe7ym+MoBqHVi7fF2nb1UKo9ih+/ -8OsZzLGjE9Vc2lbJ7C7yljI4f+jXbjwEaAQ+j2Y/SGDuEr8tWwt0dNbmlPkebb4R -WXSjkm8S/uXkOHd8tqky34zYvsTQc7kxujvIMraNndMAdB+nv4r8R+0ldvaTa6Qk -ZjqrY5xa5PVoNCO0dCvxyXgjjxbL451lLeP9uL78hIrZIiIuBKQDfAcT61eoGiPw -xzRz/GRs6jBrS8vIhi+Dhd36nUt/osCH6HloMwPtW906Bis89bOieKZtKhP4P0T4 -Ld8xDuB0q2o2RZfomaAlXcFk8xzFCEaFHfmrSBld7X6hsdUQvX7nTXP682vDHs+i -aDWQRvTrh5+SQAlDi0gcbNeImgAu1e44K8kZDab8Am5HlVjkR1Z36aqeMFDidlaU -38gfVuiAuW5xYMmA3Zjt09///////////wIBAg== ------END DH PARAMETERS----- diff --git a/SOURCES/freeradius-Adjust-configuration-to-fit-Red-Hat-specifics.patch b/freeradius-Adjust-configuration-to-fit-Red-Hat-specifics.patch similarity index 100% rename from SOURCES/freeradius-Adjust-configuration-to-fit-Red-Hat-specifics.patch rename to freeradius-Adjust-configuration-to-fit-Red-Hat-specifics.patch diff --git a/SOURCES/freeradius-Use-system-crypto-policy-by-default.patch b/freeradius-Use-system-crypto-policy-by-default.patch similarity index 76% rename from SOURCES/freeradius-Use-system-crypto-policy-by-default.patch rename to freeradius-Use-system-crypto-policy-by-default.patch index 199e583..74f3cfd 100644 --- a/SOURCES/freeradius-Use-system-crypto-policy-by-default.patch +++ b/freeradius-Use-system-crypto-policy-by-default.patch @@ -4,6 +4,7 @@ Date: Wed, 8 May 2019 10:16:31 -0400 Subject: [PATCH] Use system-provided crypto-policies by default Signed-off-by: Alexander Scheel +[antorres@redhat.com]: update patch to 3.2.1 state --- raddb/mods-available/eap | 4 ++-- raddb/mods-available/inner-eap | 2 +- @@ -12,21 +13,21 @@ Signed-off-by: Alexander Scheel 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/raddb/mods-available/eap b/raddb/mods-available/eap -index 36849e10f2..b28c0f19c6 100644 +index 62152a6dfc..9f64963034 100644 --- a/raddb/mods-available/eap +++ b/raddb/mods-available/eap -@@ -368,7 +368,7 @@ eap { - # - # For EAP-FAST, use "ALL:!EXPORT:!eNULL:!SSLv2" +@@ -400,7 +400,7 @@ eap { + # TLS cipher suites. The format is listed + # in "man 1 ciphers". # - cipher_list = "DEFAULT" + cipher_list = "PROFILE=SYSTEM" - # If enabled, OpenSSL will use server cipher list - # (possibly defined by cipher_list option above) -@@ -912,7 +912,7 @@ eap { - # Note - for OpenSSL 1.1.0 and above you may need - # to add ":@SECLEVEL=0" + # Set this option to specify the allowed + # TLS signature algorithms for OpenSSL 1.1.1 and above. +@@ -1082,7 +1082,7 @@ eap { + # "DEFAULT" as "DEFAULT" contains "!aNULL" so instead it is + # recommended "ALL:!EXPORT:!eNULL:!SSLv2" is used # - # cipher_list = "ALL:!EXPORT:!eNULL:!SSLv2" + # cipher_list = "PROFILE=SYSTEM" @@ -47,23 +48,23 @@ index 576eb7739e..ffa07188e2 100644 # You may want to set a very small fragment size. # The TLS data here needs to go inside of the diff --git a/raddb/sites-available/abfab-tls b/raddb/sites-available/abfab-tls -index 92f1d6330e..cd69b3905a 100644 +index b8d0626bbe..073b2933c2 100644 --- a/raddb/sites-available/abfab-tls +++ b/raddb/sites-available/abfab-tls -@@ -19,7 +19,7 @@ listen { +@@ -20,7 +20,7 @@ listen { dh_file = ${certdir}/dh fragment_size = 8192 ca_path = ${cadir} - cipher_list = "DEFAULT" + cipher_list = "PROFILE=SYSTEM" - cache { enable = no + lifetime = 24 # hours diff --git a/raddb/sites-available/tls b/raddb/sites-available/tls -index bbc761b1c5..83cd35b851 100644 +index 137fcbc6cc..a65f8a8711 100644 --- a/raddb/sites-available/tls +++ b/raddb/sites-available/tls -@@ -215,7 +215,7 @@ listen { +@@ -292,7 +292,7 @@ listen { # Set this option to specify the allowed # TLS cipher suites. The format is listed # in "man 1 ciphers". @@ -72,15 +73,15 @@ index bbc761b1c5..83cd35b851 100644 # If enabled, OpenSSL will use server cipher list # (possibly defined by cipher_list option above) -@@ -517,7 +517,7 @@ home_server tls { +@@ -676,7 +676,7 @@ home_server tls { # Set this option to specify the allowed # TLS cipher suites. The format is listed # in "man 1 ciphers". - cipher_list = "DEFAULT" + cipher_list = "PROFILE=SYSTEM" - } - } + # + # Connection timeout for outgoing TLS connections. -- 2.21.0 diff --git a/SOURCES/freeradius-bootstrap-create-only.patch b/freeradius-bootstrap-create-only.patch similarity index 87% rename from SOURCES/freeradius-bootstrap-create-only.patch rename to freeradius-bootstrap-create-only.patch index 5b788d9..17cab04 100644 --- a/SOURCES/freeradius-bootstrap-create-only.patch +++ b/freeradius-bootstrap-create-only.patch @@ -1,20 +1,18 @@ -From 3f40655ad0708b74a4a41b13c2b21995b157c14d Mon Sep 17 00:00:00 2001 +From acaf4be8e301a01041acba189194d9502994611d Mon Sep 17 00:00:00 2001 From: Alexander Scheel -Date: Wed, 5 Aug 2020 15:53:45 -0400 +Date: Wed, 13 May 2020 10:01:47 -0400 Subject: [PATCH] Don't clobber existing files on bootstrap -Rebased: v3.0.20 - Signed-off-by: Alexander Scheel --- - raddb/certs/bootstrap | 35 +++++++++++++++++++---------------- - 1 file changed, 19 insertions(+), 16 deletions(-) + raddb/certs/bootstrap | 31 +++++++++++++++---------------- + 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/raddb/certs/bootstrap b/raddb/certs/bootstrap -index 0f719aa..336a2bd 100755 +index ede09bc..e555491 100755 --- a/raddb/certs/bootstrap +++ b/raddb/certs/bootstrap -@@ -31,52 +31,55 @@ fi +@@ -20,56 +20,55 @@ cd `dirname $0` # Don't edit the following text. Instead, edit the Makefile, and # re-generate these commands. # @@ -32,7 +30,7 @@ index 0f719aa..336a2bd 100755 -if [ ! -f server.key ]; then +if [ ! -e server.key ]; then openssl req -new -out server.csr -keyout server.key -config ./server.cnf || exit 1 -+ chmod g+r server.key + chmod g+r server.key fi -if [ ! -f ca.key ]; then @@ -58,14 +56,14 @@ index 0f719aa..336a2bd 100755 -if [ ! -f server.p12 ]; then +if [ ! -e 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 + chmod g+r server.p12 fi -if [ ! -f server.pem ]; then +if [ ! -e 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 + chmod g+r server.pem fi -if [ ! -f ca.der ]; then @@ -76,7 +74,7 @@ index 0f719aa..336a2bd 100755 -if [ ! -f client.key ]; then +if [ ! -e client.key ]; then openssl req -new -out client.csr -keyout client.key -config ./client.cnf -+ chmod g+r client.key + chmod g+r client.key fi -if [ ! -f client.crt ]; then diff --git a/SOURCES/freeradius-bootstrap-make-permissions.patch b/freeradius-bootstrap-make-permissions.patch similarity index 100% rename from SOURCES/freeradius-bootstrap-make-permissions.patch rename to freeradius-bootstrap-make-permissions.patch diff --git a/freeradius-configure-c99.patch b/freeradius-configure-c99.patch new file mode 100644 index 0000000..cc9daff --- /dev/null +++ b/freeradius-configure-c99.patch @@ -0,0 +1,35 @@ +The backtrace_symbols function expects a pointer to an array of void * +values, not a pointer to an array of a single element. Removing the +address operator ensures that the right type is used. + +This avoids an unconditional failure of this probe with compilers that +treat incompatible pointer types as a compilation error. + +Submitted upstream: + +diff --git a/configure b/configure +index ed01ee2bdd912f63..1e6d2284779cdd58 100755 +--- a/configure ++++ b/configure +@@ -13390,7 +13390,7 @@ main (void) + { + + void *sym[1]; +- backtrace_symbols(&sym, sizeof(sym)) ++ backtrace_symbols(sym, sizeof(sym)) + ; + return 0; + } +diff --git a/configure.ac b/configure.ac +index 76320213b51d7bb4..6a689711d6c90483 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -2168,7 +2168,7 @@ if test "x$ac_cv_header_execinfo_h" = "xyes"; then + #include + ]], [[ + void *sym[1]; +- backtrace_symbols(&sym, sizeof(sym)) ]])],[ ++ backtrace_symbols(sym, sizeof(sym)) ]])],[ + AC_MSG_RESULT(yes) + ac_cv_lib_execinfo_backtrace_symbols="yes" + ],[ diff --git a/freeradius-disable-openssl-engine.patch b/freeradius-disable-openssl-engine.patch new file mode 100644 index 0000000..a7a39e7 --- /dev/null +++ b/freeradius-disable-openssl-engine.patch @@ -0,0 +1,55 @@ +From: Antonio Torres +Date: Wed, 10 Jul 2024 +Subject: Remove OpenSSL Engine usage + +Engine functionality from OpenSSL is deprecated and shouldn't be used. + +Related: https://gitlab.com/redhat/centos-stream/rpms/openssl/-/merge_requests/144 +Signed-off-by: Antonio Torres +--- + configure | 2 +- + configure.ac | 3 +-- + src/include/tls-h | 3 --- + 3 files changed, 2 insertions(+), 6 deletions(-) + +diff --git a/configure b/configure +index 5041ca264f..5ccb061a4c 100755 +--- a/configure ++++ b/configure +@@ -10515,7 +10515,7 @@ smart_prefix= + 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 ++ 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 + 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" +diff --git a/configure.ac b/configure.ac +index a24a8061f6..f6074f694e 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1446,8 +1446,7 @@ if test "x$WITH_OPENSSL" = xyes; then + openssl/rand.h \ + openssl/sha.h \ + openssl/ssl.h \ +- openssl/ocsp.h \ +- openssl/engine.h, ++ openssl/ocsp.h, + [ OPENSSL_CPPFLAGS="$smart_include" ], + [ + AC_MSG_FAILURE([failed locating OpenSSL headers. Use --with-openssl-include-dir=, or --with-openssl=no (builds without OpenSSL)]) +diff --git a/src/include/tls-h b/src/include/tls-h +index 506fb19778..b195ec9fdb 100644 +--- a/src/include/tls-h ++++ b/src/include/tls-h +@@ -37,9 +37,6 @@ RCSIDH(tls_h, "$Id$") + # define OPENSSL_NO_KRB5 + #endif + #include +-#ifdef HAVE_OPENSSL_ENGINE_H +-# include +-#endif + #include + + #ifdef __cplusplus diff --git a/freeradius-disable-perl-script.patch b/freeradius-disable-perl-script.patch new file mode 100644 index 0000000..58f4705 --- /dev/null +++ b/freeradius-disable-perl-script.patch @@ -0,0 +1,22 @@ +From: Antonio Torres +Date: Wed, 10 Jul 2024 +Subject: Remove unsupported Perl script from package + +The recently added radsecret script depends on unsupported packages +(Convert::Base32 and Crypt::URandom, which are available only in EPEL), so +remove it from package. + +Signed-off-by: Antonio Torres +--- + src/main/all.mk | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/main/all.mk b/src/main/all.mk +index f3db386a2a..2517cd215a 100644 +--- a/src/main/all.mk ++++ b/src/main/all.mk +@@ -1,3 +1,3 @@ + SUBMAKEFILES := radclient.mk radiusd.mk radsniff.mk radmin.mk radattr.mk \ +- radwho.mk radlast.mk radtest.mk radzap.mk checkrad.mk radsecret.mk \ ++ radwho.mk radlast.mk radtest.mk radzap.mk checkrad.mk \ + libfreeradius-server.mk unittest.mk diff --git a/freeradius-ease-openssl-version-check.patch b/freeradius-ease-openssl-version-check.patch new file mode 100644 index 0000000..23f1df7 --- /dev/null +++ b/freeradius-ease-openssl-version-check.patch @@ -0,0 +1,35 @@ +From: Antonio Torres +Date: Tue, 12 Sep 2023 +Subject: Ease OpenSSL version check requirement + +FreeRADIUS includes an OpenSSL version check that compares built vs linked version, +and fails to start if this check fails. We can ease this requirement in Fedora/RHEL as +ABI changes are tracked and soname is changed accordingly, as discussed in previous +Bugzilla for this issue [1]. + +[1]: https://bugzilla.redhat.com/show_bug.cgi?id=1299388 + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2238511 +Signed-off-by: Antonio Torres +--- + src/main/version.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/main/version.c b/src/main/version.c +index c190337c1d..fee2150eb2 100644 +--- a/src/main/version.c ++++ b/src/main/version.c +@@ -79,11 +79,11 @@ int ssl_check_consistency(void) + */ + if ((ssl_linked & 0x0000000f) != (ssl_built & 0x0000000f)) { + mismatch: +- ERROR("libssl version mismatch. built: %lx linked: %lx", ++ DEBUG2("libssl version mismatch. built: %lx linked: %lx", + (unsigned long) ssl_built, + (unsigned long) ssl_linked); + +- return -1; ++ return 0; + } + + /* diff --git a/freeradius-ldap-infinite-timeout-on-starttls.patch b/freeradius-ldap-infinite-timeout-on-starttls.patch new file mode 100644 index 0000000..40df134 --- /dev/null +++ b/freeradius-ldap-infinite-timeout-on-starttls.patch @@ -0,0 +1,31 @@ +From: Antonio Torres +Date: Fri, 28 Jan 2022 +Subject: Use infinite timeout when using LDAP+start-TLS + +This will ensure that the TLS connection to the LDAP server will complete +before starting FreeRADIUS, as it forces libldap to use a blocking socket during +the process. Infinite timeout is the OpenLDAP default. +Avoids this: https://git.openldap.org/openldap/openldap/-/blob/87ffc60006298069a5a044b8e63dab27a61d3fdf/libraries/libldap/tls2.c#L1134 + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1992551 +Signed-off-by: Antonio Torres +--- + src/modules/rlm_ldap/ldap.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/src/modules/rlm_ldap/ldap.c b/src/modules/rlm_ldap/ldap.c +index cf7a84e069..841bf888a1 100644 +--- a/src/modules/rlm_ldap/ldap.c ++++ b/src/modules/rlm_ldap/ldap.c +@@ -1472,7 +1472,10 @@ void *mod_conn_create(TALLOC_CTX *ctx, void *instance) + } + + #ifdef LDAP_OPT_NETWORK_TIMEOUT +- if (inst->net_timeout) { ++ bool using_tls = inst->start_tls || ++ inst->port == 636 || ++ strncmp(inst->server, "ldaps://", strlen("ldaps://")) == 0; ++ if (inst->net_timeout && !using_tls) { + memset(&tv, 0, sizeof(tv)); + tv.tv_sec = inst->net_timeout; + diff --git a/SOURCES/freeradius-logrotate b/freeradius-logrotate similarity index 99% rename from SOURCES/freeradius-logrotate rename to freeradius-logrotate index e1e58be..c962254 100644 --- a/SOURCES/freeradius-logrotate +++ b/freeradius-logrotate @@ -26,7 +26,6 @@ su radiusd radiusd } - /var/log/radius/radius.log { monthly rotate 4 diff --git a/freeradius-no-antora-docs.patch b/freeradius-no-antora-docs.patch new file mode 100644 index 0000000..5ac1ab0 --- /dev/null +++ b/freeradius-no-antora-docs.patch @@ -0,0 +1,9267 @@ +From: Antonio Torres +Date: Tue, 2 Apr 2024 +Subject: Remove Antora docs from sources + +These files are meant to be used for upstream web documentation, so we don't need them for +distribution in RHEL. + +Generated by removing doc/antora directory in FreeRADIUS repo, and requesting the diff: +git diff --patch --stat + +Binary files such as *.png might need to be removed manually from patch. + +Resolves: https://issues.redhat.com/browse/RHEL-31184 +Signed-off-by: Antonio Torres +--- + doc/antora/antora.yml | 18 - + doc/antora/modules/ROOT/assets/images/favicon.svg | 104 --- + doc/antora/modules/ROOT/nav.adoc | 1 - + doc/antora/modules/ROOT/pages/directories.adoc | 69 -- + doc/antora/modules/ROOT/pages/index.adoc | 137 ---- + doc/antora/modules/concepts/nav.adoc | 6 - + doc/antora/modules/concepts/pages/aaa.adoc | 60 -- + doc/antora/modules/concepts/pages/index.adoc | 8 - + .../pages/modules/ldap/authentication.adoc | 203 ----- + doc/antora/modules/developers/nav.adoc | 7 - + doc/antora/modules/developers/pages/bugs.adoc | 194 ----- + .../modules/developers/pages/coding-methods.adoc | 235 ------ + .../modules/developers/pages/contributing.adoc | 126 --- + doc/antora/modules/developers/pages/coverage.adoc | 11 - + doc/antora/modules/developers/pages/index.adoc | 18 - + doc/antora/modules/developers/pages/profile.adoc | 41 - + .../modules/developers/pages/release-method.adoc | 55 -- + doc/antora/modules/howto/nav.adoc | 22 - + doc/antora/modules/howto/pages/index.adoc | 17 - + .../modules/howto/pages/monitoring/index.adoc | 67 -- + .../modules/howto/pages/monitoring/statistics.adoc | 336 -------- + .../modules/howto/pages/protocols/dhcp/enable.adoc | 213 ----- + .../modules/howto/pages/protocols/dhcp/index.adoc | 35 - + .../modules/howto/pages/protocols/dhcp/policy.adoc | 14 - + .../protocols/dhcp/policy_common_options.adoc | 80 -- + .../protocols/dhcp/policy_device_options.adoc | 310 ------- + .../pages/protocols/dhcp/policy_ippool_access.adoc | 54 -- + .../protocols/dhcp/policy_ippool_creation.adoc | 112 --- + .../protocols/dhcp/policy_network_options.adoc | 237 ------ + .../protocols/dhcp/policy_subnet_options.adoc | 184 ----- + .../howto/pages/protocols/dhcp/prepare.adoc | 59 -- + .../modules/howto/pages/protocols/dhcp/test.adoc | 143 ---- + .../protocols/proxy/enable_proxy_protocol.adoc | 114 --- + .../howto/pages/protocols/proxy/enable_radsec.adoc | 188 ----- + .../modules/howto/pages/protocols/proxy/index.adoc | 126 --- + .../howto/pages/protocols/proxy/radsec_client.adoc | 181 ----- + .../pages/protocols/proxy/radsec_with_haproxy.adoc | 134 ---- + .../pages/protocols/proxy/radsec_with_traefik.adoc | 128 --- + .../modules/howto/pages/simultaneous_use.adoc | 78 -- + doc/antora/modules/installation/nav.adoc | 5 - + .../modules/installation/pages/dependencies.adoc | 35 - + doc/antora/modules/installation/pages/index.adoc | 15 - + .../modules/installation/pages/packages.adoc | 22 - + doc/antora/modules/installation/pages/source.adoc | 199 ----- + doc/antora/modules/installation/pages/upgrade.adoc | 737 ----------------- + doc/antora/modules/unlang/.gitignore | 1 - + doc/antora/modules/unlang/nav.adoc | 51 -- + doc/antora/modules/unlang/pages/attr.adoc | 77 -- + doc/antora/modules/unlang/pages/break.adoc | 28 - + doc/antora/modules/unlang/pages/case.adoc | 44 - + doc/antora/modules/unlang/pages/condition/and.adoc | 21 - + doc/antora/modules/unlang/pages/condition/cmp.adoc | 104 --- + doc/antora/modules/unlang/pages/condition/eq.adoc | 30 - + .../modules/unlang/pages/condition/index.adoc | 85 -- + doc/antora/modules/unlang/pages/condition/not.adoc | 19 - + .../modules/unlang/pages/condition/operands.adoc | 37 - + doc/antora/modules/unlang/pages/condition/or.adoc | 21 - + .../modules/unlang/pages/condition/para.adoc | 19 - + .../modules/unlang/pages/condition/regex.adoc | 180 ----- + .../unlang/pages/condition/return_codes.adoc | 35 - + doc/antora/modules/unlang/pages/default.adoc | 47 -- + doc/antora/modules/unlang/pages/else.adoc | 30 - + doc/antora/modules/unlang/pages/elsif.adoc | 43 - + doc/antora/modules/unlang/pages/foreach.adoc | 40 - + doc/antora/modules/unlang/pages/group.adoc | 39 - + doc/antora/modules/unlang/pages/if.adoc | 29 - + doc/antora/modules/unlang/pages/index.adoc | 162 ---- + doc/antora/modules/unlang/pages/keywords.adoc | 78 -- + doc/antora/modules/unlang/pages/list.adoc | 72 -- + doc/antora/modules/unlang/pages/load-balance.adoc | 32 - + doc/antora/modules/unlang/pages/module.adoc | 86 -- + .../modules/unlang/pages/module_builtin.adoc | 42 - + doc/antora/modules/unlang/pages/module_method.adoc | 27 - + .../unlang/pages/redundant-load-balance.adoc | 39 - + doc/antora/modules/unlang/pages/redundant.adoc | 42 - + doc/antora/modules/unlang/pages/return.adoc | 36 - + doc/antora/modules/unlang/pages/return_codes.adoc | 17 - + doc/antora/modules/unlang/pages/switch.adoc | 83 -- + .../modules/unlang/pages/type/all_types.adoc | 80 -- + doc/antora/modules/unlang/pages/type/double.adoc | 39 - + doc/antora/modules/unlang/pages/type/index.adoc | 117 --- + doc/antora/modules/unlang/pages/type/ip.adoc | 15 - + doc/antora/modules/unlang/pages/type/numb.adoc | 11 - + .../unlang/pages/type/string/backticks.adoc | 38 - + .../modules/unlang/pages/type/string/double.adoc | 68 -- + .../modules/unlang/pages/type/string/escaping.adoc | 14 - + .../modules/unlang/pages/type/string/single.adoc | 19 - + .../modules/unlang/pages/type/string/unquoted.adoc | 21 - + doc/antora/modules/unlang/pages/update.adoc | 160 ---- + .../modules/unlang/pages/xlat/alternation.adoc | 24 - + .../modules/unlang/pages/xlat/attribute.adoc | 54 -- + doc/antora/modules/unlang/pages/xlat/builtin.adoc | 891 --------------------- + .../modules/unlang/pages/xlat/character.adoc | 80 -- + doc/antora/modules/unlang/pages/xlat/index.adoc | 56 -- + doc/antora/modules/unlang/pages/xlat/module.adoc | 18 - + .../modules/unlang/partials/rcode_table.adoc | 39 - + 98 files changed, 8578 deletions(-) + +diff --git a/doc/antora/antora.yml b/doc/antora/antora.yml +deleted file mode 100644 +index 263945a943..0000000000 +--- a/doc/antora/antora.yml ++++ /dev/null +@@ -1,18 +0,0 @@ +-# +-# 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.5' +-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.svg b/doc/antora/modules/ROOT/assets/images/favicon.svg +deleted file mode 100644 +index 7476355932..0000000000 +--- a/doc/antora/modules/ROOT/assets/images/favicon.svg ++++ /dev/null +@@ -1,104 +0,0 @@ +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +diff --git a/doc/antora/modules/ROOT/nav.adoc b/doc/antora/modules/ROOT/nav.adoc +deleted file mode 100644 +index 3d924122c1..0000000000 +--- a/doc/antora/modules/ROOT/nav.adoc ++++ /dev/null +@@ -1 +0,0 @@ +-* xref:index.adoc[Introduction] +diff --git a/doc/antora/modules/ROOT/pages/directories.adoc b/doc/antora/modules/ROOT/pages/directories.adoc +deleted file mode 100644 +index 9b16249044..0000000000 +--- a/doc/antora/modules/ROOT/pages/directories.adoc ++++ /dev/null +@@ -1,69 +0,0 @@ +-= 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 +deleted file mode 100644 +index e9bc7a0954..0000000000 +--- a/doc/antora/modules/ROOT/pages/index.adoc ++++ /dev/null +@@ -1,137 +0,0 @@ +-= 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/concepts/nav.adoc b/doc/antora/modules/concepts/nav.adoc +deleted file mode 100644 +index 493b956641..0000000000 +--- a/doc/antora/modules/concepts/nav.adoc ++++ /dev/null +@@ -1,6 +0,0 @@ +-* xref:index.adoc[Concepts] +-** General +-*** xref:aaa.adoc[AAA] +-** Modules +-*** LDAP +-**** xref:modules/ldap/authentication.adoc[Authentication] +diff --git a/doc/antora/modules/concepts/pages/aaa.adoc b/doc/antora/modules/concepts/pages/aaa.adoc +deleted file mode 100644 +index 294305cb5b..0000000000 +--- a/doc/antora/modules/concepts/pages/aaa.adoc ++++ /dev/null +@@ -1,60 +0,0 @@ +-= AAA +- +-== 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 two steps in processing an authentication request +-coming from a NAS in FreeRADIUS: authorization and authentication. +-If we use FreeRADIUS as a proxy to re-send the request to another +-RADIUS server there will be additional steps. +- +-=== Authorization +- +-Authorization is the process of finding and returning information +-about what the user is allowed to do. For example, finding out what +-kind of authentication methods they are allowed to run, and what VLAN +-the user should be placed into. +- +-Authorization modules generally "get data" from somewhere, +-e.g. `ldap`, `sql`, `files`, etc. +- +-The authentication method is usually determined when the server gets +-the users credentials from a database. Once the credentials are +-available, the server can authenticate the user. +- +-=== Authentication +- +-Authentication is simply a process of comparing user’s credentials in +-request with the "known good" credentials retrieved from a +-database. Authentication usually deals with password +-encryption. The modules `pap`, `chap`, `mschap`, etc. do authentication. +- +-Some modules do both authentication and limited authorization. For +-example, the `mschap` module authenticates MS-CHAP credentials, but it +-may also be used as an authorization module, which verifies that +-request contains `MS-CHAP` related attribute. If so, the module +-instructs the server to use `mschap` for authentication, too +- +-These dual modules are usually related to protocol-specific +-attributes, such as the `pap` module for the `User-Password` +-attribute, `chap` for `CHAP-Password`, `mschap` for `MS-CHAP-*`, etc. +- +-=== Request Processing +- +-When the server processes requests, it manages four +-xref:unlang:list.adoc[attribute lists]: +- +-`request`:: attributes taken from the received packet +- +-`reply`:: attributes which will be sent in the reply +- +-`control`:: attributes used to control how the server operates. These are never sent in a packet +- +-`session-state`:: attributes which are saved and restroed across multiple request / reply exchanges. +- +-All of these lists are available to all modules. All of these +-lists are available in xref:unlang:index.adoc[Unlang]. +- +diff --git a/doc/antora/modules/concepts/pages/index.adoc b/doc/antora/modules/concepts/pages/index.adoc +deleted file mode 100644 +index f2bc25f36f..0000000000 +--- a/doc/antora/modules/concepts/pages/index.adoc ++++ /dev/null +@@ -1,8 +0,0 @@ +-= Concepts +- +-This section documents concerning the protocols and modules used by the +-FreeRADIUS server. +- +-It intended to provide more theoretical information about particular subjects +-than would be appropriate to include inline in module configurations or as +-sidebars in howto guides. +diff --git a/doc/antora/modules/concepts/pages/modules/ldap/authentication.adoc b/doc/antora/modules/concepts/pages/modules/ldap/authentication.adoc +deleted file mode 100644 +index edc553e80a..0000000000 +--- a/doc/antora/modules/concepts/pages/modules/ldap/authentication.adoc ++++ /dev/null +@@ -1,203 +0,0 @@ +-== Authenticating Users with LDAP +- +-Please be aware the FreeRADIUS is an AAA server, and LDAP +-is a _database_. This separation of roles means that FreeRADIUS +-supports multiple kinds of authentication protocols such as `PAP`, +-`CHAP`, `MS-CHAP`, etc. An LDAP database supports only one +-authentication method: "bind as user". This authentication method is +-compatible only with PAP. +- +-Our recommendation is to use LDAP as a database. FreeRADIUS should +-read the "known good" password from LDAP, and then use that +-information to authenticate the user. It is almost always wrong to +-use the LDAP "bind as user" method for authenticating users. +- +-The only caveat to the above recommendation is Active Directory. For +-"security" reasons, Active Directory will not return the "known good" +-password to FreeRADIUS over a standard LDAP query. Therefore when +-Active Directory is used, the choices are: +- +-PAP:: +-Use "bind as user" +- +-MS-CHAP:: +-Use xref:raddb:mods-available/ntlm_auth.adoc[`ntlm`] or xref:raddb:mods-available/winbind.adoc[`winbind`]. +- +-Due to the limitations of Active Directory, There are unfortunately no +-other possible choices. +- +-== LDAP Security Recommendations +- +-The credentials (username *and* password) for FreeRADIUS to use to +-connect to your LDAP server(s) should be secure. We make the +-following recommendations for LDAP "best practices" security. +- +-* Create a dedicated account for use by FreeRADIUS +- +-* Ensure that this account does not have administrator access +- +-* Ensure that this account is read-only, and has no write permissions +- +-* Start by using 'simple authentication' instead of +- https://en.wikipedia.org/wiki/Simple_Authentication_and_Security_Layer[SASL]. +- The SASL protocol should be attempted only after 'simple +- authentication' has been verified to work. +- +-* Use TLS for connecting between FreeRADIUS and the LDAP server. See +- the `tls` sub-section of the default `ldap` module for instructions +- +-* When storing RADIUS user profiles (quotas, `Simultaneous-Use` flags, +- access time restrictions, etc) in LDAP, the LDAP schema +- `doc/schemas/ldap/openldap/freeradius-radius.schema` must first be imported +- into the LDAP server. +- +-== Authentication method compatibility +- +-The LDAP module is compatible a few different kinds of authentication +-methods. Note that we say _compatible_, and not _supports_. LDAP +-servers are databases, and do not support authentication protocols +-such as CHAP, MS-CHAP, or EAP. +- +-PAP:: +-The user supplies a `User-Password` (plaintext or EAP-TTLS/PAP) +-+ +-FreeRADIUS reads the "known good" password from LDAP, and compares +-that to what the user entered. +- +-Bind as user:: +-The user supplies a `User-Password` (plaintext or EAP-TTLS/PAP) +-+ +-FreeRADIUS uses that password to "bind as the user" to LDAP, using the +-supplied `User-Name` and `User-Password. If the bind is successfull, +-the user is authenticated. Otherwise, authentication fails. +- +-CHAP:: +-The user supplies a `CHAP` password attribute. +-+ +-FreeRADIUS reads the "known good" password from LDAP in cleartext, and +-compares that to what the user entered. +- +-MS-CHAP:: +-The user supplies a `MS-CHAP` password attribute. Either as +-MS-CHAPv2, or as PEAP/MSCHAPv2, or as EAP-TTLS/MS-CHAPv2. +-+ +-FreeRADIUS reads the "known good" password from LDAP in cleartext, or +-as an NT hash, and compares that to what the user entered. +- +-All of above authentication methods other than "bind as user" require +-that FreeRADIUS obtain the `userPassword` field from LDAP. If that +-field is not returned to FreeRADIUS, then normal authentication is +-impossible. Either FreeRADIUS has to be configured to use "bind as +-user" for authentication, or the LDAP database has to be updated to +-return the `userPassword` field to FreeRADIUS. This change usually +-involves giving the FreeRADIUS "read-only" user permission to read the +-`userPassword` field. +- +-Again, the best method is to test authentication is with the +-xref:howto:modules/ldap/ldapsearch/index.adoc[ldapsearch] tool. +-These tests *must* be run prior to configuring FreeRADIUS. We strongly +-recommend having the LDAP database return the `userPassword` field to +-FreeRADIUS, so that FreeRADIUS can authenticate the user. +- +-We also strongly recommend that the passwords be stored in LDAP as +-cleartext. Otherwise, the only authentication methods that will work +-are PAP and EAP-TTLS/PAP. The next section explains these issues in +-more detail. +- +-== Password Storage Methods +- +-If the `userPassword` field is returned from LDAP to FreeRADIUS, that +-information can be stored in a number of different formats: +- +-* the value can be cleartext +-* the value can be prepended with a string enclosed by braces, such as with `{crypt}` or `{ssha3}`. +-* the value can be have a suffix of `::`, in which case the password is generally a https://en.wikipedia.org/wiki/Base64[base64] encoded version of the real password +- +-TIP: Base64 values can be decoded via the command: `printf "%s" +-"VALUE" | base64 -d` +- +-FreeRADIUS is capable of understanding and parsing all of the above +-formats. There is sufficient information in the password values to +-determine what format it is in (base64, binary, or text), and what +-password "encryption" mechanism has been used (crypt, MD5, SHA, SSHA2, +-SHA3, etc). All that is necessary is that the +-xref:raddb:mods-available/ldap.adoc[ldap module] be configured to map +-the `userPassword` LDAP field to the `&control.Password.With-Header` +-attribute in FreeRADIUS. FreeRADIUS will then "do the right thing" to +-authenticate the user. +- +-This mapping is done in the default module configuration. There are +-no additional changes required for FreeRADIUS to correctly read and +-decode the `userPassword` field from LDAP. Please see the +-xref:raddb:mods-available/pap.adoc[pap module] for a full list of +-supported password "encryption" formats. +- +-== Additional Considerations +- +-There are some major caveats with the above authentication methods. +-The first is that we *strongly recommend* against using "bind as +-user". This process is slow, and causes unnecessary churn in the +-connections used to contact the LDAP server. Further, the "bind as +-user" process works _only_ when a `User-Password attribute exists in +-the request. If any other authentication type is used in the request, +-then the "bind as user" _will not work_. There is no amount of +-"fixing" things or configuration changes which will make it work. +- +-The second caveat is that the `CHAP` authentication type works _only_ +-when a "clear text" password is stored in the LDAP database. The +-`CHAP` calclulations are designed around having access to the "clear +-text" password. It is impossible to use any "encrypted" or "hashed" +-passwords with `CHAP`. +- +-The third caveat is that the `MS-CHAP` authentication type works +-_only_ when a "clear text" password or "NT hashed" passwords which are +-stored in the LDAP database. The `MS-CHAP` calculations are designed +-around having access to "known good" passwords in those formats. It +-is impossible to use any other kind of "encrypted" or "hashed" +-passwords with `MS-CHAP`. +- +-The final caveat is that when the LDAP database contains "encrypted" +-or "hashed" passwords, the _only_ authentication type which is +-compatible with those passwords is PAP. i.e. when the `User-Password` +-is supplied to FreeRADIUS. +- +-For recommendations on password storage methods in LDAP, please see +-the LDAP +-https://openldap.org/doc/admin24/security.html#Password%20Storage[password +-storage] page. Please note that the recommendations there are made +-for LDAP security, and pay no attention to the caveats described +-above. When both RADIUS and LDAP are used together, then the +-requirements of _both_ systems must be met in order for them to work +-together. In many cases, a naive approach to LDAP security will +-prevent RADIUS from working. +- +-The issue of a database storing passwords in clear-text has to be +-balanced against the users sending clear-text passwords in +-authentication protocols. While those passwords are protected by TLS +-(EAP-TTLS) or by RADIUS (in it's own "encryption" mechanism), it is +-generally better to use a stronger authentication method than just +-PAP. +- +-In the end, there is no perfect solution to security requirements. +-The choice may be either to give up on using a particular +-authentication method, or to relax the security requirements on LDAP +-and on password storage. The final decision as to which choice is +-best can only be made by a local administrator. +- +-== Integrating Novell eDirectory with FreeRADIUS +- +-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 +-https://www.netiq.com/documentation/edir_radius/ +diff --git a/doc/antora/modules/developers/nav.adoc b/doc/antora/modules/developers/nav.adoc +deleted file mode 100644 +index ed6962a734..0000000000 +--- a/doc/antora/modules/developers/nav.adoc ++++ /dev/null +@@ -1,7 +0,0 @@ +-* xref:index.adoc[Developers] +-** xref:bugs.adoc[Bugs] +-** xref:coding-methods.adoc[Coding Methods] +-** xref:coverage.adoc[Code Coverage] +-** xref:profile.adoc[Profiling] +-** xref:contributing.adoc[Contributing] +-** xref:release-method.adoc[Release Method] +diff --git a/doc/antora/modules/developers/pages/bugs.adoc b/doc/antora/modules/developers/pages/bugs.adoc +deleted file mode 100644 +index b63329c0bb..0000000000 +--- a/doc/antora/modules/developers/pages/bugs.adoc ++++ /dev/null +@@ -1,194 +0,0 @@ +-= Bugs +- +-== Introduction +- +-The FreeRADIUS web site is at https://freeradius.org/, and most +-information referenced in this document can be found there. +- +-This document 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! +- +-== 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 https://bugs.freeradius.org/, including +-information from the debugging sections below. +- +-For any other issues, you should first discuss them on the +-https://freeradius.org/support/[FreeRADIUS 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://www.freeradius.org/list/users.html Please make +-sure to READ and RESPECT the house-rules. You will get much better +-response and much faster if you do! +- +-== 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 the proceeding section. +- +-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. +- +-== 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 -fxx +-``` +- +-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 the next section. +- +-== 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: +- +-https://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. +- +-== Valgrind +- +-On Linux systems, `valgrind` is a useful tool that can catch certain +-classes of bugs. To use it, run the server via: +- +-``` +-$ 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. +- +-== 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 https://www.gnu.org/software/screen/[screen] session: `$ 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 (one built with `--enable-developer` as above). +-* Configure screen to log to a file by pressing `Ctrl+a`, then `h`. +-* Type `gdb /path/to/radiusd` (or /path/to/freeradius on Debian). +-* At the `(gdb)` prompt, type `run -X`. +-* Detach from screen with `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 2019 +diff --git a/doc/antora/modules/developers/pages/coding-methods.adoc b/doc/antora/modules/developers/pages/coding-methods.adoc +deleted file mode 100644 +index 3de92c460e..0000000000 +--- a/doc/antora/modules/developers/pages/coding-methods.adoc ++++ /dev/null +@@ -1,235 +0,0 @@ +-= 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 programmer’s mind +-while they are 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. +- +-== Comment your code +- +-If you don’t, you’ll be forced to debug it six 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 the developer documentation site, https://doc.freeradius.org/. +- +-== 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. +- +-[source,c] +----- +-struct smurf { +- char *smurf_pappa_smurf; +-} +----- +- +-If your code reads as full English sentences, you’re doing it right. +- +-== 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()` (`fr_assert()`) is ugly. Use it. +- +-[NOTE] +-==== +-GIGO, "Garbage In, Garbage Out," is wrong. If your function gets +-garbage input, it should complain loudly and with great +-descriptiveness. +-==== +- +-== 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. +- +-== 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: +- +-[source,c] +----- +-fp = fopen(...); +-fgetc(fp); /* core dumps! */ +----- +- +-If the programmer had bothered to check for a `NULL` fp (error +-condition), then they could have produced a descriptive error message +-instead of having the program core dump. +- +-== 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…) +- +-== 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 +-xref:#_check_input_parameters_in_the_functions_you_write[#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. +- +-== 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. +- +-== `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. +- +-== 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 xref:#_initialize_your_variables[#7]. +- +-Notice that the C compiler error messages are helpful? You should write error +-messages like this, too. See xref:#_write_useful_error_messages[#4]. +- +-== 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. +- +-== 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 +-xref:#_give_things_reasonable_names[#2]. +- +-== Test your code +- +-Even Donald Knuth writes buggy code. You’ll never find all of the bugs in your +-code. But writing a test program definitely helps. +- +-This 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. +- +-== 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. +- +-== #ifdefs are ugly +- +-Code cluttered with `#ifdef` s is difficult to read and maintain. Don’t do it. +-Instead, put your `#ifdef` s 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: +- +-[source,c] +----- +-#ifdef CONFIG_MY_FUNKINESS +- init_my_stuff(foo); +-#endif +----- +- +-Cleaned-up example: +- +-(in header): +- +-[source,c] +----- +-#ifndef CONFIG_MY_FUNKINESS +- static inline void init_my_stuff(char *foo) {} +-#endif +----- +- +-(in the code itself): +- +-[source,c] +----- +-init_my_stuff(dev); +----- +- +-== `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__$$`. +- +-== 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/antora/modules/developers/pages/contributing.adoc b/doc/antora/modules/developers/pages/contributing.adoc +deleted file mode 100644 +index e4a4b0a1c5..0000000000 +--- a/doc/antora/modules/developers/pages/contributing.adoc ++++ /dev/null +@@ -1,126 +0,0 @@ +-= Contributing +- +-== 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 +-https://github.com/FreeRADIUS/freeradius-server/pulls[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 the next point. +- +-=== 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. +-mailto:freeradius-devel@lists.freeradius.org[freeradius-devel@lists.freeradius.org] +- +-Otherwise, send the patch to +-mailto:patches@freeradius.org[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/antora/modules/developers/pages/coverage.adoc b/doc/antora/modules/developers/pages/coverage.adoc +deleted file mode 100644 +index af6048e39e..0000000000 +--- a/doc/antora/modules/developers/pages/coverage.adoc ++++ /dev/null +@@ -1,11 +0,0 @@ +-= Code Coverage +- +-We use the link:https://gcc.gnu.org/onlinedocs/gcc/Gcov-Intro.html#Gcov-Intro[gcov] tool to know our tests coverage. +- +-[source,shell] +----- +-$ make clean +-$ make coverage +----- +- +-If completed with success, a pretty report will be available in `${source_tree}/build/coverage/index.html` +diff --git a/doc/antora/modules/developers/pages/index.adoc b/doc/antora/modules/developers/pages/index.adoc +deleted file mode 100644 +index e66ef61382..0000000000 +--- a/doc/antora/modules/developers/pages/index.adoc ++++ /dev/null +@@ -1,18 +0,0 @@ +-= FreeRADIUS Development +- +-List with some usual howtos for FreeRADIUS. +- +-Programming reference documentation can be found at the +-https://doc.freeradius.org/[Doxygen] site. +- +-== Topics +- +-* xref:bugs.adoc[Bugs] +-* xref:coding-methods.adoc[Coding Methods] +-* xref:coverage.adoc[Code Coverage] +-* xref:profile.adoc[Profiling] +-* xref:contributing.adoc[Contributing] +-* xref:release-method.adoc[Release Method] +- +-Also see the xref:installation:dependencies.adoc[build +-dependencies] page. +diff --git a/doc/antora/modules/developers/pages/profile.adoc b/doc/antora/modules/developers/pages/profile.adoc +deleted file mode 100644 +index ca94f53a40..0000000000 +--- a/doc/antora/modules/developers/pages/profile.adoc ++++ /dev/null +@@ -1,41 +0,0 @@ +-= Profiling +- +-Build with gperftools, and ensure that it's built: +- +-[source,shell] +----- +-$ grep profile Make.inc +-GPERFTOOLS_LIBS = -lprofiler +----- +- +-Run your test using the profiling tools. One signal will start the +-profiling, another will stop it. +- +-[source,shell] +----- +-env CPUPROFILE=/tmp/freeradius.prof CPUPROFILESIGNAL=12 freeradius ... +-killall -12 freeradius +- ... wait ... +-killall -12 freeradius +----- +- +-View the results +- +-[source,shell] +----- +-pprof --text /path/to/freeradius /tmp/freeradius.prof +----- +- +-or as a graph +- +-[source,shell] +----- +-pprof --gv /path/to/freeradius /tmp/freeradius.prof +----- +- +-or as cachgrind output +- +-[source,shell] +----- +-pprof --cachegrind /path/to/freeradius /tmp/freeradius.prof +----- +diff --git a/doc/antora/modules/developers/pages/release-method.adoc b/doc/antora/modules/developers/pages/release-method.adoc +deleted file mode 100644 +index 1de9e2dc17..0000000000 +--- a/doc/antora/modules/developers/pages/release-method.adoc ++++ /dev/null +@@ -1,55 +0,0 @@ +-= Release Method +- +-== Topics +- +-[arabic] +-. 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 +-``` +- +-[arabic, start=2] +-. Change version numbers in the VERSION file: +- +-``` +-# vi VERSION +-# git commit VERSION +-``` +- +-[arabic, start=3] +-. Make the files +- +-NOTE: It also does `make dist-check`, which checks the build rules for +-various packages. +- +-``` +-# make dist +-``` +- +-[arabic, start=4] +-. Validate that the packages are OK. If so, tag the release. +- +-NOTE: This does NOT actually do the tagging! You will have to run the +-command it prints out yourself. +- +-``` +-# make dist-tag +-``` +- +-[arabic, start=5] +-. Sign the packages. You will need the correct GPG key for this to work. +- +-``` +-# make dist-sign +-``` +- +-[arabic, start=6] +-. 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/antora/modules/howto/nav.adoc b/doc/antora/modules/howto/nav.adoc +deleted file mode 100644 +index dab23f80d6..0000000000 +--- a/doc/antora/modules/howto/nav.adoc ++++ /dev/null +@@ -1,22 +0,0 @@ +-* 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] +-** xref:monitoring/index.adoc[Monitoring] +-*** xref:monitoring/statistics.adoc[Server statistics] +-** xref:simultaneous_use.adoc[Simultaneous-Use] +diff --git a/doc/antora/modules/howto/pages/index.adoc b/doc/antora/modules/howto/pages/index.adoc +deleted file mode 100644 +index 47a51460c1..0000000000 +--- a/doc/antora/modules/howto/pages/index.adoc ++++ /dev/null +@@ -1,17 +0,0 @@ +-= 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/monitoring/index.adoc b/doc/antora/modules/howto/pages/monitoring/index.adoc +deleted file mode 100644 +index a08ffb4194..0000000000 +--- a/doc/antora/modules/howto/pages/monitoring/index.adoc ++++ /dev/null +@@ -1,67 +0,0 @@ +-= Monitoring +- +-Any good systems administrator will want to know how well +-their systems are operating, both to catch issues before they +-become a serious problem, or for long term analysis. +-The term "monitoring" can encompass all kinds of watching how the +-system is working, from generating and watching logs, gathering +-statistics or ensuring that the service daemon is still running +-and serving requests. +- +-We break the different types of monitoring down into the following +-sections. +- +-== Service checking +- +-Checking the running service can include the following: +- +-* Ensuring the daemon is still running, i.e. process monitoring +-* Sending regular RADIUS authentication or accounting requests and checking they are correctly responded to +-* Sending Status-Server RADIUS requests +- +-Within a proxy environment FreeRADIUS needs to know if upstream +-proxies are available. It can do this itself using the latter two +-options above. +- +-== Logging +- +-System logs are often the most critical part of a RADIUS system. +-They are necessary for the administrator to know who has logged in +-and when, for debugging purposes such as when an end user cannot +-connect, and often for regulatory or compliance purposes. +- +-RADIUS server logs are also often used as a basic form of +-recording accounting requests, which are in and of themselves a +-form of logging by the NAS. Getting correct logging systems +-operational is key to running an efficient and easy to maintain +-RADIUS server. +- +-FreeRADIUS has many options for being able to generate and store +-logs, including the following: +- +-* Main daemon logging, configured in `radiusd.conf` +-* Line-based text logging, using `rlm_linelog` +-* Detailed RADIUS packet logs, using `rlm_detail` +- +-As well as recording direct to disk, the above can be sent via a +-local syslog server, which opens up many opportunities for central +-logging. +- +-It is possible to integrate FreeRADIUS into other more complicated +-logging systems, some options may include: +- +-* To CSV files, for example via `rlm_linelog` +-* Writing entries to an SQL database using `rlm_sql` +-* Into a log management system such as Elasticsearch or Graylog +- +- +-== Statistics gathering +- +-It is often useful to collect statistics from a running RADIUS +-server. These are often plotted on graphs to show current load or +-for trend analysis, as well as an indication of system operation. +- +-Statistics are usually gathered in two ways: +- +-* FreeRADIUS xref:monitoring/statistics.adoc[internal statistics] +-* Analysing logs with some external tool +diff --git a/doc/antora/modules/howto/pages/monitoring/statistics.adoc b/doc/antora/modules/howto/pages/monitoring/statistics.adoc +deleted file mode 100644 +index 0583f0adc0..0000000000 +--- a/doc/antora/modules/howto/pages/monitoring/statistics.adoc ++++ /dev/null +@@ -1,336 +0,0 @@ +-= Server statistics +- +-FreeRADIUS collects statistics internally about certain operations +-it is doing, such as the number of authentication and accounting +-requests, how many accepts and failures, and server queue lengths. +-These can be queried by sending a specially-crafted RADIUS +-`Status-Server` packet to a "status" virtual server. +- +-== Configuring the status virtual server +- +-The `status` virtual server is present in the default +-configuration, but needs to be enabled before it can be used. To +-do this, create a symlink from `sites-enabled/status` to +-`../sites-available/status`: +- +-[source,shell] +----- +-# cd raddb/sites-enabled +-# ln -s ../sites-available/status +----- +- +-[NOTE] +-==== +-If you are not starting from the default configuration, check that +-`status_server` is still set to `yes` in `raddb/radiusd.conf` as +-well. +-==== +- +-While the default configuration will work for most setups, you may +-edit the virtual server configuration in `sites-enabled/status`. +-No major changes are necessary here, though the default secret, +-`adminsecret`, should be changed. Other possible changes may be +-the listening IP address and port, and the clients that are +-allowed to connect. By default, connections are restricted to the +-local host only. +- +-Having enabled and configured the status server, restart +-FreeRADIUS to make it active. +- +-== Querying the server +- +-To get the current statistics from the server, send a RADIUS +-request of type `Status-Server` to the status port. Unless edited +-above, the request must come from the same server that FreeRADIUS +-is running on, and be sent to port 18121 with the secret +-'adminsecret' . At a minimum, the `FreeRADIUS-Statistics-Type` +-attribute must be set. For example: +- +- $ cat < FreeRADIUS-Statistics-Type = 0x01 +- > Message-Authenticator = 0x00 +- > EOF +- Sent Status-Server Id 145 from 0.0.0.0:b852 to 127.0.0.1:18121 length 62 +- FreeRADIUS-Statistics-Type = Authentication +- Message-Authenticator = 0x00 +- Received Access-Accept Id 145 from 127.0.0.1:46c9 to 127.0.0.1:47186 length 152 +- FreeRADIUS-Total-Access-Requests = 27 +- FreeRADIUS-Total-Access-Accepts = 20 +- FreeRADIUS-Total-Access-Rejects = 1 +- FreeRADIUS-Total-Access-Challenges = 0 +- FreeRADIUS-Total-Auth-Responses = 5 +- FreeRADIUS-Total-Auth-Duplicate-Requests = 0 +- FreeRADIUS-Total-Auth-Malformed-Requests = 0 +- FreeRADIUS-Total-Auth-Invalid-Requests = 0 +- FreeRADIUS-Total-Auth-Dropped-Requests = 0 +- FreeRADIUS-Total-Auth-Unknown-Types = 0 +- FreeRADIUS-Total-Auth-Conflicts = 0 +- +-The `FreeRADIUS-Statistics-Type` attribute is a bitmask - add +-together the following numbers to select the statistics required. +-Some options are mutually exclusive, so it might be necessary to +-send multiple requests to collect all information. +- +-[%header,cols="2,1,1,5"] +-|=== +-|Name|Hex value|Decimal value|Description +- +-|Authentication +-|0x01 +-|1 +-|Stats about authentications +- +-|Accounting +-|0x02 +-|2 +-|Stats about accounting +- +-|Proxy Auth +-|0x04 +-|4 +-|Proxied authentication requests +- +-|Proxy Accounting +-|0x08 +-|8 +-|Proxied accounting requests +- +-|Internal +-|0x10 +-|16 +-|Queue lengths, thread information etc. +- +-|Client +-|0x20 +-|32 +-|Statistics about RADIUS clients e.g. defined in `clients.conf` +- +-|Server +-|0x40 +-|64 +-|Statistics about server 'listen' sockets e.g. in `sites-enabled/*` +- +-|Home Server +-|0x80 +-|128 +-|Statistics about a proxy home servers e.g. in `proxy.conf` +-|=== +- +-== Worked examples +- +-To show the statistics available, a few examples follow. +- +-=== Global server authentications +- +-Using `FreeRADIUS-Statistics-Type = 0x01` requests stats about +-authentications. Because, for example, no "Client" qualifier has +-been added (`0x20`) the numbers are global to the server. +- +-[source,shell] +----- +-# cat <` 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 `/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 `/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 /sites-enabled +-ln -s ../sites-available/dhcp . +----- +- +-or: +- +-[source,shell] +----- +-cd /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 +-`/mods-available`. +-These should be symlinked or copied into `/mods-enabled` in order to +-enable them. +- +- +-==== Configure the `dhcp_sql` module +- +-Add the `dhcp_sql` module to the active configuration: +- +-[source,shell] +----- +-cd /mods-enabled +-ln -s ../mods-available/dhcp_sql . +----- +- +-or: +- +-[source,shell] +----- +-cd /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_`, 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 /mods-enabled +-ln -s ../mods-available/dhcp_sqlippool . +----- +- +-or +- +-[source,shell] +----- +-cd /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 `/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 `` for DHCP packets +-================================================================== +- # ss -lunp +- Netid Recv-Q Send-Q Local Address:Port ... +- udp 0 0 0.0.0.0%: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 +deleted file mode 100644 +index fde22024f0..0000000000 +--- a/doc/antora/modules/howto/pages/protocols/dhcp/index.adoc ++++ /dev/null +@@ -1,35 +0,0 @@ +-= 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 +deleted file mode 100644 +index d8f1bcb79a..0000000000 +--- a/doc/antora/modules/howto/pages/protocols/dhcp/policy.adoc ++++ /dev/null +@@ -1,14 +0,0 @@ +-== 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 +deleted file mode 100644 +index ca4d98fee5..0000000000 +--- a/doc/antora/modules/howto/pages/protocols/dhcp/policy_common_options.adoc ++++ /dev/null +@@ -1,80 +0,0 @@ +-== Configure common reply options +- +-FreeRADIUS includes a powerful xref: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 +-`/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 +deleted file mode 100644 +index 05845ea893..0000000000 +--- a/doc/antora/modules/howto/pages/protocols/dhcp/policy_device_options.adoc ++++ /dev/null +@@ -1,310 +0,0 @@ +-== 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 +-`/mods-available/dhcp_passwd` into `/mods-enabled/`. The +-suggested configuration expects the group membership file to be in +-`/mods-config/files/dhcp_groups` and take the form of: +- +-[source,config] +----- +-|,, +-|, +----- +- +-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 +-`/policy.d/dhcp` in the `dhcp_group_options` policy and in +-`/mods-available/dhcp_files` as the `dhcp_set_group_options` instance. +- +-The same data file `/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 = , groupname = , 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 < 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 +deleted file mode 100644 +index 40b8e3094a..0000000000 +--- a/doc/antora/modules/howto/pages/protocols/dhcp/policy_ippool_access.adoc ++++ /dev/null +@@ -1,54 +0,0 @@ +-== 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 `/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 +deleted file mode 100644 +index e976873c12..0000000000 +--- a/doc/antora/modules/howto/pages/protocols/dhcp/policy_ippool_creation.adoc ++++ /dev/null +@@ -1,112 +0,0 @@ +-=== 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 -s -e \ +- -t (-d | -f [ -i ]) \ +- [ -c ] [ -x ] +----- +- +-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 -t -k \ +- (-d | -f [-i ]) +----- +- +-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 +deleted file mode 100644 +index e2657a8cfe..0000000000 +--- a/doc/antora/modules/howto/pages/protocols/dhcp/policy_network_options.adoc ++++ /dev/null +@@ -1,237 +0,0 @@ +-== 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 +-`/sites-enabled/dhcp`. +-==== +- +-To use the provided example `files` module instance for DHCP, symlink or copy +-`/mods-available/dhcp_files` into `/mods-enabled/` and then +-uncomment the calls to `dhcp_network` in `/sites-enabled/dhcp`. +- +-A template configuration file `/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 ` +- `. In the case of the second block we match the +-`DHCP-Network-Subnet` to an enclosing subnet with +-`DHCP-Network-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 ` := `. 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 +-`/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 < 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 < 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 < 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 +deleted file mode 100644 +index 1980e89cd0..0000000000 +--- a/doc/antora/modules/howto/pages/protocols/dhcp/policy_subnet_options.adoc ++++ /dev/null +@@ -1,184 +0,0 @@ +-== 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 `/mods-available/dhcp_files`: +- +-[source,config] +----- +-files dhcp_subnets { +- filename = ${modconfdir}/files/dhcp +- key = "subnet" +-} +----- +- +-Additionally, uncomment the `dhcp_subnets` policy in `/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 `/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 +-`/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 +deleted file mode 100644 +index aa43530a66..0000000000 +--- a/doc/antora/modules/howto/pages/protocols/dhcp/prepare.adoc ++++ /dev/null +@@ -1,59 +0,0 @@ +-== 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 +deleted file mode 100644 +index 322de08fa9..0000000000 +--- a/doc/antora/modules/howto/pages/protocols/dhcp/test.adoc ++++ /dev/null +@@ -1,143 +0,0 @@ +-== 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 < 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 +deleted file mode 100644 +index a4ab3dbada..0000000000 +--- a/doc/antora/modules/howto/pages/protocols/proxy/enable_proxy_protocol.adoc ++++ /dev/null +@@ -1,114 +0,0 @@ +-== 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 +deleted file mode 100644 +index f5e7603c10..0000000000 +--- a/doc/antora/modules/howto/pages/protocols/proxy/enable_radsec.adoc ++++ /dev/null +@@ -1,188 +0,0 @@ +-== 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: +- +- +- +-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 +deleted file mode 100644 +index 5100635921..0000000000 +--- a/doc/antora/modules/howto/pages/protocols/proxy/index.adoc ++++ /dev/null +@@ -1,126 +0,0 @@ +-= 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 +deleted file mode 100644 +index d92345e9e8..0000000000 +--- a/doc/antora/modules/howto/pages/protocols/proxy/radsec_client.adoc ++++ /dev/null +@@ -1,181 +0,0 @@ +-== 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: +- +- +- +-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 +deleted file mode 100644 +index e58abfe53b..0000000000 +--- a/doc/antora/modules/howto/pages/protocols/proxy/radsec_with_haproxy.adoc ++++ /dev/null +@@ -1,134 +0,0 @@ +-== 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 +deleted file mode 100644 +index 11030e92fd..0000000000 +--- a/doc/antora/modules/howto/pages/protocols/proxy/radsec_with_traefik.adoc ++++ /dev/null +@@ -1,128 +0,0 @@ +-== 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/howto/pages/simultaneous_use.adoc b/doc/antora/modules/howto/pages/simultaneous_use.adoc +deleted file mode 100644 +index b4a97abb91..0000000000 +--- a/doc/antora/modules/howto/pages/simultaneous_use.adoc ++++ /dev/null +@@ -1,78 +0,0 @@ +-= Simultaneous-Use checking +- +-There are a whole lot of pieces which have to work together for +-`Simultaneous-Use` to work. In this guide, we assume that user +-sessions are stored in SQL. +- +-For `Simultaneous-Use` to work. the server needs to know who is +-online, which means that accounting must be configured and working. +-Start off by checking the basics, independent of `Simultaneous-Use`. +- +-As always, start off with reading the debug output, and use that +-information to answer a few questions. +- +-== Did the user get Access-Accept? +- +-*No* - Fix that. Make sure that the user can be authenticated! +- +-*Yes* - FreeRADIUS told the NAS to allow the user online. This usually +- works, but perhaps the NAS disagreed, and still dropped the user. It happens. +- +-The only way you know that a user is actually online is to check the +-accounting data. So we will do that next. +- +-== Did the server then get an Accounting-Request for that user? +- +-*No* - The NAS isn't sending accounting packets, Simultaneous-Use will never work. +- +-Go fix the NAS so that it sends accounting packets. +- +-*Yes* - The NAS is telling FreeRADIUS that it allowed the user online, +- and the user has an active session. We now have to see where that data is stored. +- +-== Did the accounting data go into the radacct table? +- +-As always, Read the debug output. +- +-*No* - There is nothing in the debug output about radacct? Configure the server to write accounting data to SQL +- +-ou can use `radclient` to send fake accounting packets for testing. +-Use a real accounting packet as a template for input to `radclient`, +-but change the `User-Name` so that the tests don't affect real users. +- +- +-*Yes* - You see successful `INSERT` or `UPDATE` lines in `radacct`. That's good! +- +-== One last check +- +-Double-check the radacct database using an SQL client. Just to be sure that the data is really there. +- +-== It is now set up correctly to track user sessions +- +-If all that works, then the server is set up correctly to authenticate +-users, and to store their data in SQL. This is the foundation for +-`Simultaneous-Use`. +- +-== Set Simultaneous-Use +- +-Then, configure the server to set `Simultaneous-Use=1`. That tells the server to enforce `Simultaneous-Use`. That configuration can go into the `files` module, `sql`, or whereever else you want. +- +-You will also need to configure the `default` virtual server to check session data in SQL. Look for `Simultaneous-Use` in `sites-available/default`. Uncomment the line containing `sql` +- +-== Double check that a user can still log in! +- +-Go through all of the above steps _again_, checking that the user can +-log in, and that the server is receiving accounting packets. +- +-This time, also look for the debug output to contain: +- +-``` +-# Executing section session from file ... +-session { +-``` +- +-That shows it is checking the `session` database. If all goes well, the next few lines after that should show that it is checking `sql`. +- +-If the above text doesn't appear, then the server isn't getting told to set `Simultaneous-Use = 1`. You will have to fix that before going to the next step. +- +-If the user has not logged in yet, you will see an `Access-Accept`. Otherwise, if the user already has an active session, the server should say that the user is being rejected due to multiple logins. +diff --git a/doc/antora/modules/installation/nav.adoc b/doc/antora/modules/installation/nav.adoc +deleted file mode 100644 +index 26ce32e54e..0000000000 +--- a/doc/antora/modules/installation/nav.adoc ++++ /dev/null +@@ -1,5 +0,0 @@ +-* 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 +deleted file mode 100644 +index 3fb366796a..0000000000 +--- a/doc/antora/modules/installation/pages/dependencies.adoc ++++ /dev/null +@@ -1,35 +0,0 @@ +-= FreeRADIUS Dependencies +- +-Some external dependencies must be installed before building or +-running FreeRADIUS. For version 3, the core depends on one +-mandatory library: `libtalloc` for memory management. +- +-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, CentOS, Rocky Linux or equivalent* +- +-``` +-# yum install libtalloc-devel +-``` +diff --git a/doc/antora/modules/installation/pages/index.adoc b/doc/antora/modules/installation/pages/index.adoc +deleted file mode 100644 +index b810078083..0000000000 +--- a/doc/antora/modules/installation/pages/index.adoc ++++ /dev/null +@@ -1,15 +0,0 @@ +-== 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 +deleted file mode 100644 +index ffc52cd8f3..0000000000 +--- a/doc/antora/modules/installation/pages/packages.adoc ++++ /dev/null +@@ -1,22 +0,0 @@ +-== 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 +deleted file mode 100644 +index cf40a792f4..0000000000 +--- a/doc/antora/modules/installation/pages/source.adoc ++++ /dev/null +@@ -1,199 +0,0 @@ +-== 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 +deleted file mode 100644 +index 67874c859a..0000000000 +--- a/doc/antora/modules/installation/pages/upgrade.adoc ++++ /dev/null +@@ -1,737 +0,0 @@ +-= 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//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 `-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 ("%{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 +deleted file mode 100644 +index c5722d7c54..0000000000 +--- a/doc/antora/modules/unlang/.gitignore ++++ /dev/null +@@ -1 +0,0 @@ +-!*.adoc +diff --git a/doc/antora/modules/unlang/nav.adoc b/doc/antora/modules/unlang/nav.adoc +deleted file mode 100644 +index e2d68b30e0..0000000000 +--- a/doc/antora/modules/unlang/nav.adoc ++++ /dev/null +@@ -1,51 +0,0 @@ +-* 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_codes.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 +deleted file mode 100644 +index 70afce41af..0000000000 +--- a/doc/antora/modules/unlang/pages/attr.adoc ++++ /dev/null +@@ -1,77 +0,0 @@ +-= &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[] +----- +- +-When an attribute appears multiple times in a list, this syntax allows +-you to address the attributes as if they were array entries. The +-`` 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 +deleted file mode 100644 +index 01783ea8f2..0000000000 +--- a/doc/antora/modules/unlang/pages/break.adoc ++++ /dev/null +@@ -1,28 +0,0 @@ +-= 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 +deleted file mode 100644 +index 2d5749dd8e..0000000000 +--- a/doc/antora/modules/unlang/pages/case.adoc ++++ /dev/null +@@ -1,44 +0,0 @@ +-= The case Statement +- +-.Syntax +-[source,unlang] +----- +-case [ ] { +- [ 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 `` text can be an attribute reference such as `&User-Name`, +-or it can be a xref:type/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 `` 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 +deleted file mode 100644 +index 50b3deb2e0..0000000000 +--- a/doc/antora/modules/unlang/pages/condition/and.adoc ++++ /dev/null +@@ -1,21 +0,0 @@ +-= 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 +deleted file mode 100644 +index 4138b869ae..0000000000 +--- a/doc/antora/modules/unlang/pages/condition/cmp.adoc ++++ /dev/null +@@ -1,104 +0,0 @@ +-= 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] +----- +-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] +----- +-&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] +----- +-`/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 +deleted file mode 100644 +index d9e51f3f13..0000000000 +--- a/doc/antora/modules/unlang/pages/condition/eq.adoc ++++ /dev/null +@@ -1,30 +0,0 @@ +-= 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 +deleted file mode 100644 +index 10a84c8485..0000000000 +--- a/doc/antora/modules/unlang/pages/condition/index.adoc ++++ /dev/null +@@ -1,85 +0,0 @@ +-= 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_codes.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 +deleted file mode 100644 +index bde038e2de..0000000000 +--- a/doc/antora/modules/unlang/pages/condition/not.adoc ++++ /dev/null +@@ -1,19 +0,0 @@ +-= 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 +deleted file mode 100644 +index 5b19af32f0..0000000000 +--- a/doc/antora/modules/unlang/pages/condition/operands.adoc ++++ /dev/null +@@ -1,37 +0,0 @@ +-= 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_codes.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 +deleted file mode 100644 +index 80c2cb45a8..0000000000 +--- a/doc/antora/modules/unlang/pages/condition/or.adoc ++++ /dev/null +@@ -1,21 +0,0 @@ +-= 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 +deleted file mode 100644 +index bdb3f013c3..0000000000 +--- a/doc/antora/modules/unlang/pages/condition/para.adoc ++++ /dev/null +@@ -1,19 +0,0 @@ +-= 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 +deleted file mode 100644 +index 038faa647f..0000000000 +--- a/doc/antora/modules/unlang/pages/condition/regex.adoc ++++ /dev/null +@@ -1,180 +0,0 @@ +-= Regular Expressions +- +-.Syntax +-==== +-[source,unlang] +----- +-( =~ //) +-( =~ //[imsux]) +- +-( !~ //) +-( !~ //[imsux]) +----- +-==== +- +-== Matching +-The regular expression operators perform regular expression matching +-on the data. The `` field can be an attribute reference or data, +-as with the other xref:condition/cmp.adoc[comparison] operators. The `//` +-field must be a valid regular expression. +- +-The `=~` operator evaluates to `true` when `data` matches the +-`//`. Otherwise, it evaluates to `false`. +- +-The `!~` operator evaluates to `true` when `data` does not match the +-`//`. 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 `//` 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:}`. +- +-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 +-// 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 +deleted file mode 100644 +index ebc49ed5c7..0000000000 +--- a/doc/antora/modules/unlang/pages/condition/return_codes.adoc ++++ /dev/null +@@ -1,35 +0,0 @@ +-= 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 +deleted file mode 100644 +index 30912ef40a..0000000000 +--- a/doc/antora/modules/unlang/pages/default.adoc ++++ /dev/null +@@ -1,47 +0,0 @@ +-= The case Statement +- +-.Syntax +-[source,unlang] +----- +-case [ ] { +- [ 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 `` text can be an attribute reference such as `&User-Name`, +-or it can be a xref:type/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 `` 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 +deleted file mode 100644 +index a795d0e12c..0000000000 +--- a/doc/antora/modules/unlang/pages/else.adoc ++++ /dev/null +@@ -1,30 +0,0 @@ +-= 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 +deleted file mode 100644 +index ff5799c791..0000000000 +--- a/doc/antora/modules/unlang/pages/elsif.adoc ++++ /dev/null +@@ -1,43 +0,0 @@ +-= 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 +deleted file mode 100644 +index 6ed3ddff67..0000000000 +--- a/doc/antora/modules/unlang/pages/foreach.adoc ++++ /dev/null +@@ -1,40 +0,0 @@ +-= The foreach Statement +- +-.Syntax +-[source,unlang] +----- +-foreach { +- [ statements ] +-} +----- +- +-The `foreach` statement loops over a set of attributes as given by +-``. The loop can be exited early by using the +-xref:break.adoc[break] keyword. +- +-:: +- +-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 +deleted file mode 100644 +index 98801fd280..0000000000 +--- a/doc/antora/modules/unlang/pages/group.adoc ++++ /dev/null +@@ -1,39 +0,0 @@ +-= 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 +deleted file mode 100644 +index ea549efb52..0000000000 +--- a/doc/antora/modules/unlang/pages/if.adoc ++++ /dev/null +@@ -1,29 +0,0 @@ +-= 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 +deleted file mode 100644 +index fc812f873d..0000000000 +--- a/doc/antora/modules/unlang/pages/index.adoc ++++ /dev/null +@@ -1,162 +0,0 @@ +-= 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 +deleted file mode 100644 +index e6411ea984..0000000000 +--- a/doc/antora/modules/unlang/pages/keywords.adoc ++++ /dev/null +@@ -1,78 +0,0 @@ +-= 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[] | Execute a named module, e.g., `sql`. +-| xref:module_method.adoc[.] | 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 +deleted file mode 100644 +index a55a54f992..0000000000 +--- a/doc/antora/modules/unlang/pages/list.adoc ++++ /dev/null +@@ -1,72 +0,0 @@ +-= 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 __ 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 +deleted file mode 100644 +index d64b161590..0000000000 +--- a/doc/antora/modules/unlang/pages/load-balance.adoc ++++ /dev/null +@@ -1,32 +0,0 @@ +-= 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 +deleted file mode 100644 +index fd18f2f4ba..0000000000 +--- a/doc/antora/modules/unlang/pages/module.adoc ++++ /dev/null +@@ -1,86 +0,0 @@ +-= Modules +- +-.Syntax +-[source,unlang] +----- +- +----- +- +-The `` 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 ` = (0+||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 +deleted file mode 100644 +index f21a128953..0000000000 +--- a/doc/antora/modules/unlang/pages/module_builtin.adoc ++++ /dev/null +@@ -1,42 +0,0 @@ +-= 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 +deleted file mode 100644 +index 98cd37582e..0000000000 +--- a/doc/antora/modules/unlang/pages/module_method.adoc ++++ /dev/null +@@ -1,27 +0,0 @@ +-= Module methods +- +-.Syntax +-[source,unlang] +----- +-. +----- +- +-This variant of xref:module.adoc[] 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 `` portion must refer to an existing module; the +-`` 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 +deleted file mode 100644 +index 2322f726fd..0000000000 +--- a/doc/antora/modules/unlang/pages/redundant-load-balance.adoc ++++ /dev/null +@@ -1,39 +0,0 @@ +-= 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 +deleted file mode 100644 +index e837d1f369..0000000000 +--- a/doc/antora/modules/unlang/pages/redundant.adoc ++++ /dev/null +@@ -1,42 +0,0 @@ +-= 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 +deleted file mode 100644 +index aea1bc2ab2..0000000000 +--- a/doc/antora/modules/unlang/pages/return.adoc ++++ /dev/null +@@ -1,36 +0,0 @@ +-= 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 +deleted file mode 100644 +index 3b09c2dc52..0000000000 +--- a/doc/antora/modules/unlang/pages/return_codes.adoc ++++ /dev/null +@@ -1,17 +0,0 @@ +-= 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 +deleted file mode 100644 +index deff7032bd..0000000000 +--- a/doc/antora/modules/unlang/pages/switch.adoc ++++ /dev/null +@@ -1,83 +0,0 @@ +-= The switch Statement +- +-.Syntax +-[source,unlang] +----- +-switch { +- case { +- [ statements-1 ] +- } +- case { +- [ 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 ( == ) { +- [ statements-1 ] +-} +-elsif ( == ) { +- [ 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 +deleted file mode 100644 +index 0bace01354..0000000000 +--- a/doc/antora/modules/unlang/pages/type/all_types.adoc ++++ /dev/null +@@ -1,80 +0,0 @@ +-= 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 +deleted file mode 100644 +index 6c3e708eaa..0000000000 +--- a/doc/antora/modules/unlang/pages/type/double.adoc ++++ /dev/null +@@ -1,39 +0,0 @@ +-= 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 +deleted file mode 100644 +index f26489b179..0000000000 +--- a/doc/antora/modules/unlang/pages/type/index.adoc ++++ /dev/null +@@ -1,117 +0,0 @@ +-= 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: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: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}}" == 192.0.2.1) } +- .... +-} +----- +- +-In this example, we prefix the IP address with the string ``. +-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: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 +deleted file mode 100644 +index fc25ae8eb2..0000000000 +--- a/doc/antora/modules/unlang/pages/type/ip.adoc ++++ /dev/null +@@ -1,15 +0,0 @@ +-= 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 +deleted file mode 100644 +index 284cf819c1..0000000000 +--- a/doc/antora/modules/unlang/pages/type/numb.adoc ++++ /dev/null +@@ -1,11 +0,0 @@ +-= 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 +deleted file mode 100644 +index 9372b4c736..0000000000 +--- a/doc/antora/modules/unlang/pages/type/string/backticks.adoc ++++ /dev/null +@@ -1,38 +0,0 @@ +-= 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 +deleted file mode 100644 +index ea87bc5c45..0000000000 +--- a/doc/antora/modules/unlang/pages/type/string/double.adoc ++++ /dev/null +@@ -1,68 +0,0 @@ +-= 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` | A byte whose numerical value is given by `` interpreted as a hexadecimal number. +-| `\x` | A byte whose numerical value is given by `` 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 +-// 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 +deleted file mode 100644 +index e63a498ce0..0000000000 +--- a/doc/antora/modules/unlang/pages/type/string/escaping.adoc ++++ /dev/null +@@ -1,14 +0,0 @@ +-= 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 +deleted file mode 100644 +index fa2ac05255..0000000000 +--- a/doc/antora/modules/unlang/pages/type/string/single.adoc ++++ /dev/null +@@ -1,19 +0,0 @@ +-= 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 +deleted file mode 100644 +index 9dd6e557b7..0000000000 +--- a/doc/antora/modules/unlang/pages/type/string/unquoted.adoc ++++ /dev/null +@@ -1,21 +0,0 @@ +-= 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 +deleted file mode 100644 +index 645f4d8aba..0000000000 +--- a/doc/antora/modules/unlang/pages/update.adoc ++++ /dev/null +@@ -1,160 +0,0 @@ +-= The update Statement +- +-.Syntax +-[source,unlang] +----- +-update [ ] { +- +- ... +-} +----- +- +-The `update` statement adds attributes to, or edits the attributes in, +-the named __. +- +-The `update` statement consists of the following syntax elements: +- +-:: The attribute list which will be updated. The list is +-usually `request`, `reply`, or `control`. +-+ +-If the __ qualifier is omitted, then each entry inside of the +-`update` section *must* be prefixed with a list name. For example, +-`&request.User-Name ...` +- +-:: The server attribute which is assigned the +-__. +- +-:: The operator such as `=`, `:=`, etc. +- +-:: 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 __ field sets the attribute list that will be updated. If +-the __ 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 __ field is an attribute name, such as +-`&Reply-Message`. The attribute name may also be prefixed with a +-__ qualifier, which overrides the __ given at the start +-of the `update` section. +- +-NOTE: In version 3, the leading `&` is optional but recommended. +- +-== Editing Operators +- +-The `` 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 __. +-| !* | 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 __ and +-__ fields to enforce limits on all attributes in the given +-__, and to edit attributes which have a matching +-__ name. All other attributes are ignored. +- +-.Filtering Operators +-[options="header] +-[cols="10%,90%"] +-|===== +-| Operator | Description +-| == | Keep only the attributes in the list that match __ +-| < | Keep only the attributes in the list that have values less than __. +-| \<= | Keep only the attributes in the list that have values less than or equal to __. +-| > | Keep only the attributes in the list that have values greater than __. +-| >= | Keep only the attributes in the list that have values greater than or equal to __. +-| =~ | Keep only the attributes in the list which match the regular expression given in __. +-| !~ | Keep only the attributes in the list which do not match the regular expression given in __. +-|===== +- +-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 __ +-given here. If no attribute exists, it is created with the given +-__. +- +-For IP addresses, the operators `>`, `>=`, `<`, and `\<=` check for +-membership in a network. The __ 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 __ field is the value which is assigned to the +-__. The interpretation of the __ 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 +deleted file mode 100644 +index adb76043dd..0000000000 +--- a/doc/antora/modules/unlang/pages/xlat/alternation.adoc ++++ /dev/null +@@ -1,24 +0,0 @@ +-= 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}:-}` +- +-// 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 +deleted file mode 100644 +index a3ee29bb06..0000000000 +--- a/doc/antora/modules/unlang/pages/xlat/attribute.adoc ++++ /dev/null +@@ -1,54 +0,0 @@ +-= Attribute References +- +-Attributes in a list may be referenced via one of the following two +-syntaxes: +- +-`%{Attribute-Name}` + +-`%{:Attribute-Name}` +- +-The `:` prefix is optional. If given, it must be a valid +-reference to an xref:list.adoc[attribute list]. +- +-If the `:` 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 +deleted file mode 100644 +index 10d31482fc..0000000000 +--- a/doc/antora/modules/unlang/pages/xlat/builtin.adoc ++++ /dev/null +@@ -1,891 +0,0 @@ +-= 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:} +- +-Generate random number from `0` to `-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:} +- +-CAUTION: This expansion is deprecated and will likely be removed. +- +-Returns a list of tags for any attributes found using ````. +- +-.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:} +- +-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:} +- +-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:} +- +-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:} +- +-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:} +- +-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> } +- +-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> } +- +-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: } +- +-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: } +- +-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:}+ +- +-Return named subcapture value from the last regular expression evaluated. +- +-Results of named capture groups are available using the `%{regex:}` expansion. They will also be accessible using the numbered expansions +-described xref:#_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: