diff options
Diffstat (limited to '')
-rw-r--r-- | raddb/mods-available/date | 45 | ||||
-rw-r--r-- | raddb/mods-available/detail | 33 | ||||
-rw-r--r-- | raddb/mods-available/dpsk | 145 | ||||
-rw-r--r-- | raddb/mods-available/eap | 75 | ||||
-rw-r--r-- | raddb/mods-available/json | 2 | ||||
-rw-r--r-- | raddb/mods-available/ldap | 27 | ||||
-rw-r--r-- | raddb/mods-available/ldap_google | 2 | ||||
-rw-r--r-- | raddb/mods-available/mschap | 38 | ||||
-rw-r--r-- | raddb/mods-available/sql | 32 | ||||
-rw-r--r-- | raddb/mods-available/sql_map | 5 | ||||
-rw-r--r-- | raddb/mods-available/totp | 45 |
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 } |