summaryrefslogtreecommitdiffstats
path: root/raddb/mods-available
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--raddb/mods-available/date45
-rw-r--r--raddb/mods-available/detail33
-rw-r--r--raddb/mods-available/dpsk145
-rw-r--r--raddb/mods-available/eap75
-rw-r--r--raddb/mods-available/json2
-rw-r--r--raddb/mods-available/ldap27
-rw-r--r--raddb/mods-available/ldap_google2
-rw-r--r--raddb/mods-available/mschap38
-rw-r--r--raddb/mods-available/sql32
-rw-r--r--raddb/mods-available/sql_map5
-rw-r--r--raddb/mods-available/totp45
11 files changed, 433 insertions, 16 deletions
diff --git a/raddb/mods-available/date b/raddb/mods-available/date
index 25a64da..2d7d85e 100644
--- a/raddb/mods-available/date
+++ b/raddb/mods-available/date
@@ -33,3 +33,48 @@ date wispr2date {
# default = no
# utc = yes
}
+
+#
+# The date module also provides the %{time_since:} xlat, which
+# makes it possible to both:
+# - get the time since the epoch in seconds, milliseconds or
+# microseconds; and
+# - calculate the time elapsed since a given time.
+#
+# Syntax is: %{time_since:BASE[ (number|&attribute)]}
+# where "BASE" is "s", "ms" or "us".
+#
+# Examples:
+# %{time_since:s}
+# - time in seconds since the epoch, same as %c
+#
+# %{time_since:s 1695753388}
+# - time in seconds since Tue 26 Sep 19:36:28 BST 2023
+# (which is 1695753388 in UNIX time)
+#
+# %{time_since:s &Tmp-Integer-0}
+# - Time since the number of seconds in Tmp-Integer-0
+#
+# %{time_since:ms}
+# - Milliseconds since the epoch
+#
+# %{time_since:us}
+# - Microseconds since the epoch
+#
+# The provided attribute should be an Integer (or Integer64 for
+# ms or us bases). However, other attributes will be converted if
+# possible, with a warning given. The only one that might make
+# sense is a Date attribute (which will be scaled appropriately
+# according to the base, as Date is always in seconds).
+#
+# Primary usage would be for taking latenct measurements, for
+# example to calculate the number of microseconds an LDAP call
+# took:
+#
+# update request {
+# &Tmp-Integer64-0 := %{time_since:us}"
+# }
+# ldap
+# update request {
+# &Tmp-Integer64-1 := %{time_since:us &Tmp-Integer64-0}"
+# }
diff --git a/raddb/mods-available/detail b/raddb/mods-available/detail
index ccf65f9..665b677 100644
--- a/raddb/mods-available/detail
+++ b/raddb/mods-available/detail
@@ -94,6 +94,39 @@ detail {
#
# log_packet_header = yes
+
+ #
+ # There are many, many, issues with dates being printed as
+ # humanly-readable strings. The server tries hard to both
+ # print and parse dates correctly, however this is not always
+ # possible.
+ #
+ # The detail files may be generated on one machine, and read
+ # on another. The two systems may have different languages,
+ # so the names of the month may not be parseable. The two
+ # systems may have different time zones. Time zone parsing
+ # is pretty much impossible, as there are multiple time zones
+ # with the same name!
+ #
+ # In some cases, the local libraries may not be able to
+ # correctly parse the time zone it printed! i.e. the system
+ # documentation for the C library time functions sometimes
+ # even says that the time zones are ignored, and the dates
+ # are parsed as UTC.
+ #
+ # All of these issues can be avoided by printing the dates as
+ # integer. In nearly all cases, the integer printed is
+ # exactly what was received in the packet.
+ #
+ # This may resolve some issues, but it's not perfect. The
+ # dates received by FreeRADIUS are sent by the NAS, and
+ # created on the NAS. So if the time on the NAS is wrong,
+ # the dates printed by FreeRADIUS will also be wrong. The
+ # only solution is to make sure that the NAS is using the
+ # correct time.
+ #
+# dates_as_integer = yes
+
#
# Certain attributes such as User-Password may be
# "sensitive", so they should not be printed in the
diff --git a/raddb/mods-available/dpsk b/raddb/mods-available/dpsk
new file mode 100644
index 0000000..3cd8411
--- /dev/null
+++ b/raddb/mods-available/dpsk
@@ -0,0 +1,145 @@
+# -*- text -*-
+#
+# $Id$
+
+#
+# Calculate dynamic PSKs
+#
+# This module needs the following attributes as input:
+#
+# * control:Pre-Shared-Key - the PSK for the user
+# * User-Name - the supplicant MAC in hex format, e.g. "abcdef012345"
+# * Called-Station-MAC - the AP MAC in binary
+# this attribute is set by the "rewrite_called_station_id" policy.
+# * FreeRADIUS-802.1X-Anonce - from the AP
+# * FreeRADIUS-802.1X-EAPoL-Key-Msg - from the AP
+#
+# Note that you MUST run the "rewrite_called_station_id" policy before calling this module.
+#
+# That policy MUST also create the Called-Station-MAC attribute.
+#
+# Then place the following configuration into the "authorize" section:
+#
+# authorize {
+# ...
+# rewrite_called_station_id
+#
+# update control {
+# &PSK-Identity := "bob"
+# &Pre-Shared-Key := "this-is-super-secret"
+# }
+# dpsk
+#
+# }
+#
+# And update the "authenticate" section to list the "dpsk" module:
+#
+# authenticate {
+# ...
+# dpsk
+# ...
+# }
+#
+# The module will return "fail" if the PSK is not correct. It will return "ok"
+# if the PSK is correct.
+#
+# It also updates &reply:Pre-Shared-Key with the found key, along with
+# &reply:PSK-Identity with the found identity.
+#
+# We STRONGLY RECOMMEND THAT NO ONE USE THIS MODULE.
+#
+# While it works, it needs to use a brute-force method to match MAC
+# to PSK. That process is extremely slow, and scales very poorly.
+#
+# i.e. if you have 10 PSKs, it's not too bad. If you have 10,000
+# PSKs, then the module can comsume 100% of CPU trying to
+# brute-force every PSK.
+#
+# This is a limitation of how DPSK works. There is no way to make it
+# better. The only thing we've done is to add a cache which can help
+# to minimize the amount of brute-force attempts.
+#
+
+#
+# The modules configuration.
+#
+dpsk {
+ #
+ # The maximum number of entries to cache.
+ #
+ # The cache is keyed by (supplicant MAC + SSID)
+ #
+ # The cache entry is the PSK-Identity and Pre-Sharedd-Key,
+ # and/or the PMK which are used to verify the information in
+ # the Access-Request.
+ #
+ cache_size = 1024
+
+ #
+ # The lifetime of an entry in the cache.
+ #
+ cache_lifetime = 86400
+
+ #
+ # PSKs can also be stored in a CSV file. The format of the file is:
+ #
+ # identity,psk,mac
+ #
+ # If there are commas in a field, then the field can be
+ # double quoted: "psk".
+ #
+ # The mac field is optional. If it exists, then that PSK
+ # will be used. It is highly recommended that the MAC *not* be placed
+ # into the CSV file. Instead, the MAC and PSK should be placed into a
+ # database. The server can then be configured to look up the MAC in the
+ # database, which returns the PSK. That way this module will only ever
+ # check one PSK, which is fast.
+ #
+ # i.e. the CSV file should only contain the small number of PSKs where
+ # you do not yet know the MAC. As soon as you know the MAC, you should
+ # put the MAC and PSK into a database, and then remove the MAC and PSK
+ # from the CSV file.
+ #
+ # NOTE: the file is opened and read from top to bottom for every
+ # new request which comes in. This process can be very slow!
+ #
+ # However, opening the file for every new request means that the
+ # server does not have to be reloaded when the file changes. Instead,
+ # the file can be generated, and then moved into place atomically:
+ #
+ # create csv file > psk.csv.new
+ # mv psk.csv.new psk.csv
+ #
+ # Any process which writes a new "psk.csv" file MUST NOT
+ # write to the file directly, as that will cause the dpsk
+ # module to read partial entries and fail. Instead, use "mv"
+ # to atomically overwrite the old file with a new one.
+ #
+ # Both "cache_size" and "filename" can be configured at the
+ # same time, which is recommended. When an entry in the file
+ # is found, the identity, PSK, and MAC are saved in the cache.
+ #
+ # If a cache entry is found, then the filename is NOT read.
+ #
+ # The resulting combination of features means that the module
+ # should be as fast as possible, given the limitations of DPSK.
+ #
+ # NOTE: Tests show that the module can do ~100K PSK / DPSK
+ # checks per second. This means that if you have 10,000
+ # users and 10 packets a second, the system will be 100% busy
+ # checking PSKs.
+ #
+ # As a result, the DPSK functionality is scales poorly. It
+ # should be used only with a small number of PSKs (100s
+ # perhaps), and only at low packet rates. If the server is
+ # getting 1000 packets per second, then it can only handle
+ # 100 PSKs before running out of CPU.
+ #
+ # Using the cache will help substantially. But the cache is
+ # only in memory, which means that all cache entries are lost
+ # when the server restarts. As a result, the combination of
+ # number of PSKs and packet rates should be kept as low as
+ # possible.
+ #
+# filename = "${modconfdir}/${..:name}/psk.csv"
+}
diff --git a/raddb/mods-available/eap b/raddb/mods-available/eap
index ee9e539..d149707 100644
--- a/raddb/mods-available/eap
+++ b/raddb/mods-available/eap
@@ -33,6 +33,28 @@ eap {
#
timer_expire = 60
+ #
+ # Some supplicants may misbehave by starting many thousands
+ # of EAP sessions, but never finishing them. These sessions
+ # can cause the server to hit 'max_sessions' very quickly.
+ # The 'timer_expire' configuration above does not help as
+ # much as it could, because the old (duplicate) session
+ # should be deleted as soon as the new one comes in.
+ #
+ # If you set the 'dedup_key' below, whenever the EAP module
+ # starts a new session, it will check for a previous session
+ # which has the same dedup key. If a previous session
+ # is found, it is deleted.
+ #
+ # Setting this configuration item may cause issues if the
+ # same device uses multiple EAP sessions at the same time.
+ # But that device behavior should be rare to non-existent.
+ #
+ # The configuration item is commented out so that upgrades
+ # do not change existing behavior.
+ #
+# dedup_key = "%{Calling-Station-Id}"
+
# There are many EAP types, but the server has support
# for only a limited subset. If the server receives
# a request for an EAP type it does not support, then
@@ -231,6 +253,9 @@ eap {
# Directory where multiple CAs are stored. Both
# "ca_file" and "ca_path" can be used at the same time.
#
+ # Each file in this directory must contain one
+ # certificate, and ONLY one certificate.
+ #
ca_path = ${cadir}
# OpenSSL does not reload contents of ca_path dir over time.
@@ -1112,4 +1137,54 @@ eap {
#
# virtual_server = inner-tunnel
#}
+
+ # EAP-TEAP
+ #
+ # The TEAP module implements the EAP-TEAP protocol
+ #
+ #teap {
+ # Point to the common TLS configuration
+ #
+ # tls = tls-common
+
+ # default_eap_type = mschapv2
+
+ # If 'cipher_list' is set here, it will over-ride the
+ # 'cipher_list' configuration from the 'tls-common'
+ # configuration. The EAP-TEAP module has it's own
+ # over-ride for 'cipher_list' because the
+ # specifications mandata a different set of ciphers
+ # than are used by the other EAP methods.
+ #
+ # cipher_list though must include "ADH" for anonymous provisioning.
+ # This is not as straight forward as appending "ADH" alongside
+ # "DEFAULT" as "DEFAULT" contains "!aNULL" so instead it is
+ # recommended "ALL:!EXPORT:!eNULL:!SSLv2" is used
+ #
+ # cipher_list = "ALL:!EXPORT:!eNULL:!SSLv2"
+
+ # PAC lifetime in seconds (default: seven days)
+ #
+ # pac_lifetime = 604800
+
+ # Authority ID of the server
+ #
+ # If you are running a cluster of RADIUS servers, you should make
+ # the value chosen here (and for "pac_opaque_key") the same on all
+ # your RADIUS servers. This value should be unique to your
+ # installation. We suggest using a domain name.
+ #
+ # authority_identity = "1234"
+
+ # PAC Opaque encryption key (must be exactly 32 bytes in size)
+ #
+ # This value MUST be secret, and MUST be generated using
+ # a secure method, such as via 'openssl rand -hex 32'
+ #
+ # pac_opaque_key = "0123456789abcdef0123456789ABCDEF"
+
+ # Same as for TTLS, PEAP, etc.
+ #
+ # virtual_server = inner-tunnel
+ #}
}
diff --git a/raddb/mods-available/json b/raddb/mods-available/json
index 02a62ae..88f17c0 100644
--- a/raddb/mods-available/json
+++ b/raddb/mods-available/json
@@ -142,7 +142,7 @@ json {
# .Example
#
# ```
-# %{json_encode:&request[*] !&reply[*] &control.User-Name}
+# %{json_encode:&request[*] !&reply[*] &control:User-Name}
# ```
#
# #### Output format modes
diff --git a/raddb/mods-available/ldap b/raddb/mods-available/ldap
index 997d41e..d5838ff 100644
--- a/raddb/mods-available/ldap
+++ b/raddb/mods-available/ldap
@@ -41,7 +41,7 @@ ldap {
# That will give you the LDAP information for 'user'.
#
# Group membership can be queried by using the above "ldapsearch" string,
- # and adding "memberof" qualifiers. For ActiveDirectory, use:
+ # and adding "memberof" qualifiers. For Active Directory, use:
#
# ldapsearch ... '(&(objectClass=user)(sAMAccountName=user)(memberof=CN=group,${base_dn}))'
#
@@ -152,10 +152,10 @@ ldap {
# LDAP "bind as user" configuration to check PAP passwords.
#
- # Active Directory needs "bind as user", which can be done by
- # adding the following "if" statement to the authorize {} section
- # of the virtual server, after the "ldap" module. For
- # example:
+ # Active Directory (or Azure AD) needs "bind as user", which
+ # can be done by adding the following "if" statement to the
+ # authorize {} section of the virtual server, after the
+ # "ldap" module. For example:
#
# ...
# ldap
@@ -174,6 +174,23 @@ ldap {
# "Auth-Type LDAP" in order to do an LDAP "bind as user", which will hand
# the user name / password to AD for verification.
#
+ # Note that this ONLY works if FreeRADIUS receives a
+ # User-Password attribute in the Access-Request packet.
+ # e.g. PAP, or TTLS/PAP.
+ #
+ # USING MS-CHAP OR PEAP/MS-CHAP WITH ACTIVE DIRECTORY OVER LDAP WILL NOT WORK.
+ #
+ # ** EVER ***.
+ #
+ # THERE IS NOTHING YOU CAN DO TO MAKE IT WORK.
+ #
+ # If you have a local Active Directory server, you can use
+ # Samba and ntlm_auth. See the "mschap" and "ntlm_auth"
+ # modules for more information.
+ #
+ # Unfortunately, you cannot use Samba with Azure AD. You
+ # MUST use PAP or TTLS/PAP.
+ #
#
# Name of the attribute that contains the user DN.
diff --git a/raddb/mods-available/ldap_google b/raddb/mods-available/ldap_google
index 03c98d3..9487c4b 100644
--- a/raddb/mods-available/ldap_google
+++ b/raddb/mods-available/ldap_google
@@ -21,7 +21,7 @@
# username and password. That username and password should be used
# below.
#
-# Ensure the Goolge client configuration which is used for FreeRADIUS
+# Ensure the Google client configuration which is used for FreeRADIUS
# has sufficient permissions to read user information, and, if group
# membership is part of the FreeRADIUS policy, ensure that the client
# can read group information. This configuration is done on Google's
diff --git a/raddb/mods-available/mschap b/raddb/mods-available/mschap
index 1748d57..5fbdcee 100644
--- a/raddb/mods-available/mschap
+++ b/raddb/mods-available/mschap
@@ -51,9 +51,26 @@ mschap {
# and the mschap module will do the authentication itself,
# without calling ntlm_auth.
#
- # Be VERY careful when editing the following line!
+ # This authentication can go wrong for a number of reasons:
+ # 1) the user does not exist in AD
+ # 2) the password entered by the user is not the same as
+ # what is in AD
+ # 3) some magic MS-CHAP data is wrong.
#
- # You can also try setting the user name as:
+ # These situations can be checked by running ntlm_auth
+ # from the command line with a name and a password:
+ #
+ # ntlm_auth --username=NAME --password=PASSWORD
+ #
+ # If that works, you know both that the user exists, and the
+ # password is correct. You also know what AD expects for the
+ # username.
+ #
+ # There is often confusion between different formats of the
+ # username. Is it "user", or "user@domain" or "DOMAIN\\user"?
+ # The answer is "that depends on your local AD system".
+ #
+ # One solution is to use this for the username:
#
# ... --username=%{mschap:User-Name} ...
#
@@ -61,6 +78,23 @@ mschap {
# attribute, and do prefix/suffix checks in order to obtain
# the "best" user name for the request.
#
+ # Another option is to use the Stripped-User-Name, as in the
+ # example configuration below.
+ #
+ # You can test which format works by running the server in
+ # debug mode, and copying the hex strings from the
+ # --challenge=... and --nt-response=... output.
+ #
+ # Then, run ntlm_auth from the command line, using the same
+ # command-line options as given below. Since you can't
+ # change the challenge or nt-response strings, try changing
+ # the --username=... and --domain=... parameters. Try
+ # different formats for them until one works. There should only
+ # be a small number of variations possible.
+ #
+ # That is the username and domain format which you need to
+ # configure here in this file.
+ #
# For Samba 4, you should also set the "ntlm auth" parameter
# in the Samba configuration:
#
diff --git a/raddb/mods-available/sql b/raddb/mods-available/sql
index 0f435ad..68ac4da 100644
--- a/raddb/mods-available/sql
+++ b/raddb/mods-available/sql
@@ -291,6 +291,23 @@ sql {
#
# Setting 'max' to MORE than the number of threads means
# that there are more connections than necessary.
+ #
+ # The setting here should be lower than the maximum
+ # number of connections allowed by the database.
+ #
+ # i.e. There is no point in telling FreeRADIUS to use
+ # 64 connections, while the database is limited to 32
+ # connections. That configuration will cause the
+ # server to be "starved" of connections, and it will
+ # block during normal operations, even when the
+ # database is largely idle.
+ #
+ # At the same time, if the database is slow, there is
+ # no point in increasing "max". More connections
+ # will just cause the database to run more slowly.
+ # The correct fix for a slow database is to fix it, so
+ # that it responds to FreeRADIUS quickly.
+ #
max = ${thread[pool].max_servers}
# Spare connections to be left idle
@@ -371,6 +388,21 @@ sql {
# of the SQL module.
group_attribute = "SQL-Group"
+ # When attributes read from the network are used in SQL queries
+ # their values are escaped to make them safe.
+ # By default FreeRADIUS uses its escaping routine which replaces
+ # unsafe characters with their mime-encoded equivalent.
+ # The list of safe characters is conservative, to allow for differences
+ # between different SQL implementations.
+ #
+ # If you are using the mysql or postgresql drivers, those have their
+ # own escaping functions which only escape characters as required
+ # by those databases.
+ #
+ # Set this option to yes to use the database driver provided escape
+ # function.
+# auto_escape = no
+
# Read database-specific queries
$INCLUDE ${modconfdir}/${.:name}/main/${dialect}/queries.conf
}
diff --git a/raddb/mods-available/sql_map b/raddb/mods-available/sql_map
index 93b2636..a0b32ef 100644
--- a/raddb/mods-available/sql_map
+++ b/raddb/mods-available/sql_map
@@ -6,11 +6,6 @@ sql_map {
# use the *instance* name here: sql1.
sql_module_instance = "sql"
- # This is duplicative of info available in the SQL module, but
- # we have to list it here as we do not yet support nested
- # reference expansions.
- dialect = "mysql"
-
# Name of the check item attribute to be used as a key in the SQL queries
query = "SELECT ... FROM ... "
diff --git a/raddb/mods-available/totp b/raddb/mods-available/totp
index 695365f..a68a317 100644
--- a/raddb/mods-available/totp
+++ b/raddb/mods-available/totp
@@ -13,6 +13,12 @@
#
# &control:TOTP-Secret
#
+# Any "bare" key should be placed into:
+#
+# &control:TOTP-Key
+#
+# If TOTP-Key exists, then it will be used instead of TOTP-Secret.
+#
# The TOTP password entered by the user should be placed into:
#
# &request:TOTP-Password
@@ -32,9 +38,44 @@
# https://linux.die.net/man/1/qrencode
#
# and then run that locally to get an image.
-#
#
-# The module takes no configuration items.
+#
+# Some tokens get severely out of sync with local time. It is
+# possible to offset the definition of "now" for one token by setting:
+#
+# &control:TOTP-Time-Offset := 120
+#
+# This is a signed integer, with allowed values between -600 to +600.
+# The offset is added to to the current time, to get the tokens idea
+# of "now".
#
totp {
+ #
+ # Default time step between time changes
+ #
+ time_step = 30
+
+ #
+ # Length of the one-time password.
+ #
+ # Must be 6 or 8
+ #
+ otp_length = 6
+
+ #
+ # How many steps backward in time we look for a matching OTP
+ #
+ lookback_steps = 1
+
+ #
+ # How many steps forward in time we look for a matching OTP
+ #
+ lookforward_steps = 0
+
+ #
+ # Time delta between steps.
+ #
+ # Cannot be larger than time_step
+ #
+ lookback_interval = 30
}