command-line option, and it will tell you where the dictionary
files are located.
-The v3 names are in ${dictdir}/radius/alias/alias.VENDOR where
+The v3 names are in ${dictdir}/radius/alias/VENDOR.txt where
VENDOR is the name of the vendor, which is taken from the VENDOR
definition in the v3 dictionaries.
All of the v3 compatibility names are in the RADIUS namespace.
+
== Default Configuration
```
#ATTRIBUTE My-Local-String 3000 string
#ATTRIBUTE My-Local-IPAddr 3001 ipaddr
#ATTRIBUTE My-Local-Integer 3002 integer
-BEGIN-PROTOCOL RADIUS
-#$INCLUDE ${dictdir}/radius/alias/alias.cisco
-END-PROTOCOL RADIUS
+#BEGIN-PROTOCOL RADIUS
+#$INCLUDE ${dictdir}/radius/alias/cisco.txt
+#END-PROTOCOL RADIUS
```
| xref:mods-available/couchbase.adoc[couchbase] | Allows attributes to be stored and retrieved from a couchbase server. Client definitions may also be bulk loaded from a
couchbase server as FreeRADIUS starts.
| xref:mods-available/csv.adoc[csv] | Maps values in a CSV file to FreeRADIUS attributes and adds them to the request.
+| xref:mods-available/kafka.adoc[kafka] | Produces messages, placing them in a Kafka messaging queue
| xref:mods-available/passwd.adoc[passwd] | Reads and caches line-oriented files that are in a format similar to ``/etc/passwd``.
| xref:mods-available/radutmp.adoc[radutmp] | Writes a utmp style file that lists the users who are logged in. The file is used mainly for Simultaneous-Use checking
and by radwho to see who has current sessions.
| xref:mods-available/mac2ip.adoc[mac2ip] | Mac2IP
| xref:mods-available/mac2vlan.adoc[mac2vlan] | Mac2Vlan
| xref:mods-available/ntlm_auth.adoc[ntlm_auth] | NTLM Auth
+| xref:mods-available/redundant_sql.adoc[redundant_sql] | redundant_sql
| xref:mods-available/smbpasswd.adoc[smbpasswd] | SMBPasswd
| xref:mods-available/sradutmp.adoc[sradutmp] | sRadutmp
| xref:mods-available/stats.adoc[stats] | Stats
+| xref:mods-available/totp.adoc[totp] |
|=====
== Policy Modules
| xref:mods-available/date.adoc[date] | Converts date strings between user configurable formats.
| xref:mods-available/delay.adoc[delay] | Introduces an artificial non-blocking delay when processing a request.
| xref:mods-available/escape.adoc[escape] | Escapes and unescapes strings using the MIME escape format
-| xref:mods-available/expiration.adoc[expiration] | Determines whether a user account has expired, with the expiration time set by another module.
-| xref:mods-available/expr.adoc[expr] | Registers a string expansion "%{expr:}" that allows basic arithmetic and binary operations.
| xref:mods-available/idn.adoc[idn] | Converts internationalized domain names to ASCII.
| xref:mods-available/json.adoc[json] | Parses JSON strings into an in memory format using the json-c library.
| xref:mods-available/logintime.adoc[logintime] | Enforces the time span during which a user may login to the system.
[options="header,autowidth"]
|===
| Driver | Description
-| `rlm_cache_rbtree` | An in memory, non persistent rbtree based datastore.
+| `rbtree` | An in memory, non persistent rbtree based datastore.
Useful for caching data locally.
-| `rlm_cache_memcached` | A non persistent "webscale" distributed datastore.
+| `memcached` | A non persistent "webscale" distributed datastore.
Useful if the cached data need to be shared between
a cluster of RADIUS servers.
-| `rlm_cache_redis` | A persistent "webscale" clustered, sharded, data store.
+| `redis` | A persistent "webscale" clustered, sharded, data store.
Extremely fast, and a good candidate for sharing
data such as EAP session blobs, between a cluster of
servers.
Add your own value for `link:https://freeradius.org/rfc/rfc2865.html#Class[Class]`.
+## How to use
+
+### Configuration
+
This module supports a number of runtime configuration parameters
represented by attributes in the `&control.` list.
cache entries into the current request. Useful if results of execs or
expansions are stored directly in the cache.
+
NOTE: All runtime configuration attributes will be removed from the
`&control.` list after the cache module is called.
+### Methods
+
+The cache module also allows handling the cache using the methods.
+
+cache.status:: Verify if an entry already exists without load the entries.
+
+[options="header,autowidth"]
+|===
+| Return | Description
+| `ok` | if a cache entry was found.
+| `notfound` | if no cache entry was found.
+|===
+
+cache.load:: Load an existing cache entry and merge it into the request.
+
+[options="header,autowidth"]
+|===
+| Return | Description
+| `updated` | if a cache entry was found and loaded.
+| `notfound` | if no cache entry was found.
+|===
+
+cache.store:: Perform an upset against the data store. (Not affect the existing
+request).
+
+[options="header,autowidth"]
+|===
+| Return | Description
+| `updated` | if we added cache entry.
+| `noop` | if a cache entry ready exists.
+|===
+
+cache.clear:: Delete cache entry from the data store without checking if the entry
+already exists.
+
+[options="header,autowidth"]
+|===
+| Return | Description
+| `ok` | if we found and remove a entry.
+| `notfound` | if no cache entry was found.
+|===
+
+cache.ttl:: Change the TTL on an existing entry.
+
+[options="header,autowidth"]
+|===
+| Return | Description
+| `updated` | if we found entry and updated the ttl.
+| `notfound` | if no cache entry was found.
+|===
+
+### Examples
+
+```
+# Add a cache entry
+&control.Cache-TTL := 1h
+cache.store
+if (updated) {
+ ..keys stored
+}
+
+# Get the cache status
+cache.status
+if (ok) {
+ ..Exist a cache entry
+}
+
+# Load the cache entry
+cache.load
+if (updated) {
+ ..loaded
+}
+
+# Change the entries TTL
+&control.Cache-TTL := 30m
+cache.ttl
+if (updated) {
+ ..ttl changed
+}
+
+# Clear the cache
+cache.clear
+if (ok) {
+ ..cache is empty
+}
+```
+
+[NOTE]
+====
+ * This is evaluated before `Cache-TTL`, so entries being expired
+may first be merged.
+ * All runtime configuration attributes will be removed from the
+`&control:` list after any cache method is called.
+====
+
== Default Configuration
| Parameter | Description
| <fr attr> | Is the destination RADIUS attribute
with any valid list and request qualifiers.
-| <op> | Is any assignment attribute (=, :=, +=, ^=, -=).
+| <op> | Is any assignment attribute (=, :=, +=, -=).
| <csv field> | Is the name of a field from the CSV file, as taken
from the `fields` configuration item.
|===
= Date Module
-The `date` module xlat does convert time formats.
+The `date` module parses dates, and prints them.
+
+The server will normally print dates in its own pre-defined format.
+It will also parse dates in a few limited formats. However, these
+operations are for full dates (e.g. January 1, 2020 12:34pm). The
+server does not print dates in other formats, and does not parse
+dates in other formats.
+
+The `date` module adds that functionality. It allows you to print
+dates in almost any format you want. It allows you to parse dates
+in almost any format, so long as you know what the fields are, and
+how they are defined.
## Configuration Settings
+format:: Formatting of the output string.
+
+The format arguments are the same as for the system
+`strftime` call. See `man strftime` for documentation.
+
+
-### Simple date
+utc:: Whether conversions are in UTC or local time.
+
+If `utc` is enabled then any conversions will be made
+as UTC, not localtime.
+
+.Default is to use localtime.
-format::
-The `xlat` performs in three modes depending on the input it
-is passed.
+### ISO format
+
+The core `xlat`, `%T` returns the request timestamp in `ISO` format
+including milliseconds. This expansion returns it without the
+millisecond component.
+
+Use e.g. `%(date_iso:request):`
+
+
-The input string can be:
+### xlat expansions
- - an expanded date or integer attribute;
- - an expanded string attribute;
- - the fixed strings `request` or `now`.
+The `date` module defines an expansion `%{date:}` When the
+expansion is not passed an argument, it returns the current date
+printed according to the `format` string defined above.
."Attribute" mode:
-If the given attribute is of `date` or `integer` type, the date
-xlat will convert it to a `time` string in the format of the
-format config item.
+If the argument to `%{date:...}` is an attribute of `date` or
+`integer` type, the date used will be the time given by the
+relevant attribute. If the attributes is of type `string`, the
+string will be parsed according to the `format` configuration,
+and a Unix date will be returned, as integer seconds since the epoch.
-If the given attribute is a `string` type, the `xlat` will attempt
-to parse it in the format specified by the format config item,
-and will expand to a Unix timestamp (seconds since the epoch).
+For example, `%{date:&Event-Timestamp}` will use the date from the
+`link:https://freeradius.org/rfc/rfc2869.html#Event-Timestamp[Event-Timestamp]` attribute as the source of the date for printing.
."Get time" mode:
If the input is the string `now`, the `xlat` will behave as
above, for the current time.
-See also the core provided expansions which are equivalent to
-`request` and `now`, but return numerical values:
-
-[options="header,autowidth"]
-|===
-| Parameter | Description
-| %l | request time in seconds since the epoch.
-| %M | request time microsecond component.
-| %c | current time in seconds since the epoch.
-| %C | current time microsecond component.
-|===
-
+If the input string begins with `+`, then the remainder of the
+string is interpreted as if the string had been given in the
+`format` configuration item.
+For example `%{date:'+%A'}` will return `Monday` if today is Monday.
-utc::
+Note that the `%` character is special for xlat expansions, and therefore
+either has to be "protected" by string quotation, or the `%` character has
+to be escaped itself, as in `%{date:+%%A}`
-If `utc` is enabled then any conversions will be made
-as UTC, not localtime.
+."Integer output"
-.Default is to use localtime.
+In some cases, it is useful for the module to parse dates instead
+of printing them. In this mode, the format string is ignored.
+Instead, the input arguments are parsed, and the output is an
+integer containg the requested value.
+The following expansions return integer numbers:
-
-### ISO format
-
-The core `xlat`, `%T` returns the request timestamp in `ISO` format
-including milliseconds. This expansion returns it without the
-millisecond component.
-
-Use e.g. `%(date_iso:request):`
+[options="header,autowidth"]
+|===
+| Parameter | Description
+| %l | request time in seconds since the epoch.
+| %M | request time microsecond component.
+| %c | current time in seconds since the epoch.
+| %C | current time microsecond component.
+| &Attribute-Name | for string attributes, parse the string according to `format`, and return the integer value as a Unix timestamp.
+|===
== Default Configuration
-mode:: Which client certificates should be verified
+verify:: Parameters for controlling client cert chain
+verification.
+
+Certificate verification is performed in two phases.
+The first is handled by the SSL library which checks
+whether a trusted chain of certificates can be built
+between the certificates loaded from `ca_file` or
+found in `ca_path`.
+
+The second (optional) phase is performed using the
+`verify * { ... }` sections of the tls
+`virtual_server`.
+
+
+mode:: Which certificates in the verification chain
+should be checked.
+
+Certificate verification is performed in two phases.
+The first is handled by the SSL library which checks
+whether a trusted chain of certificates can be built
+between the certificates loaded from `ca_file` or
+found in `ca_path`.
+
+The SSL library also checks that the the correct usage
+OIDs are present in the presented client certificate
+and that none of the certificates have expired.
[options="header,autowidth"]
|===
It is recommended to leave mode as `all` except
when debugging, or in an emergency situation.
-[NOTE]
-====
-This verification is only applied during a full
-handshake, and with stateful session resumption.
-Verification for stateless session resumption
-should be performed using the `verify [*] { ... }`
-section(s) of the specified `virtual_server`.
-====
-
attribute_mode:: Which client certificates should
| `client-and-issuer`
| Create attributes for the client certificate
and its issuer.
-| `client`
+| `client`
| Only create attributes for the client
certificate.
|===
allow_not_yet_valid_crl:: Accept a not-yet-valid Certificate Revocation List.
-
### TLS Session resumption
Once authentication has completed the TLS client may be
+session_ticket_key::
+
+Sets a persistent key used to encrypt stateless session
+tickets. If this is not set, then a random key will be
+chosen when the server starts.
+As the ticket key length depends on the version/flavour
+of OpenSSL being used, the value provided is fed into
+a HKDF function (digest SHA256,
+label "freeradius-session-ticket"). The number of
+bytes OpenSSL indicates it needs are then extracted from
+the HKDF.
+
+It is important that a strong key is chosen here. If the
+key were ever revealed, then an attacker could manipulate
+the contents of a session ticket. This could in turn
+allow privilege escalation, or if OpenSSL's ticket parsing
+code is less than perfect, buffer overflow attacks.
+
+
+
[NOTE]
====
As of 4.0 OpenSSL's internal cache has been disabled due to
### EAP-SIM
-Triplets can be provided using control attributes:
-
- * `&control.EAP-SIM-KC`
- * `&control.EAP-SIM-RAND`
- * `&control.EAP-SIM-SRES`
-
-NOTE: Three instances of each attribute must be provided.
-
-Alternatively triplets can be generated locally using
-control attributes:
-
- * `&control.SIM-Ki`
- * `&control.SIM-OPc`
- * `&control.SIM-Algo-Version` (optional - see defaults below)
-
-UMTS Milenage inputs (AMF, SQN) are ignored.
-
-`&control.SIM-Algo-Version` selects the SIM algorithm used,
-it must match the algorithm used by the SIM.
-
-Accepted values for `SIM-Algo-Version` are:
-
- * `Comp128v1`
- * `Comp128v2`
- * `Comp128v3` (default if no &control.SIM-OPc)
- * `Comp128v4` (default if &control.SIM-OPc is available)
-
-NOTE: In general operators will not provide the Ki (subscriber
-key) for their `SIM cards`, as the Ki is considered highly
-sensitive.
-
-Local triplet generation is intended for testing and
-research purposes where programmable or virtual SIM cards
-are in use.
-
virtual_server:: EAP-SIM virtual server containing policy
sections. This must be set, EAP-SIM will not function
# allow_expired_crl = no
# allow_not_yet_valid_crl = no
}
- cache {
+ session {
# mode = auto
# name = "%{EAP-Type}%{Virtual-Server}"
# lifetime = 86400
# require_extended_master_secret = yes
# require_perfect_forward_secrecy = no
+ *
+# session_ticket_key = "super-secret-key"
}
}
tls {
User-Name=BobUser => USER_NAME="BobUser"
+Note that this escaping only applies to environmental variables
+created from the request list. For environmental variables inherited
+from the main radiusd process no escaping is applied.
+
+
+
+env_inherit:: Inherit the environment of the current radiusd process.
+
+Any `input_pairs` will be merged with these environmental variables.
+
timeout:: Set a time wait for the program to finish.
input_pairs = request
# output_pairs = reply
shell_escape = yes
+# env_inherit = no
timeout = 10
}
```
[source,unlang]
----
-update control {
- &Tmp-String-0 := '$.my.json.payload[1]'
-}
-update reply {
- &Reply-Message := "Validation of %{control.Tmp-String-0} is %{jpathvalidate:$.my.json.payload[1]}"
-}
+&control.Tmp-String-0 := '$.my.json.payload[1]'
+&reply.Reply-Message := "Validation of %{control.Tmp-String-0} is %{jpathvalidate:$.my.json.payload[1]}"
----
.Output
[source,unlang]
----
-update control {
- &Tmp-String-0 := "caipirinha/gelada"
-}
-update reply {
- &Reply-Message := "The string %{control.Tmp-String-0} should be %{jsonquote:%{control.Tmp-String-0}} to be a valid JSON string."
-}
+&control.Tmp-String-0 := "caipirinha/gelada"
+&reply.Reply-Message := "The string %{control.Tmp-String-0} should be %{jsonquote:%{control.Tmp-String-0}} to be a valid JSON string."
----
.Output
for the behavioral semantics of specifying more than one host.
Depending on the `libldap` in use, server may be specified as an LDAP
-URI. In the case of `OpenLDAP` this allows additional the following
+URI. In the case of `OpenLDAP` this allows the following
additional schemes:
[options="header,autowidth"]
| Parameter | Description
| <fr attr> | Is the attribute you wish to create,
with any valid list and request qualifiers.
-| <op> | Is any assignment operator (`=`, `:=`, `+=`, `^=`, `-=`).
+| <op> | Is any assignment operator (`=`, `:=`, `+=`, `-=`).
| <value> | Is the value to parse into the new attribute.
If the value is wrapped in double quotes it
will be xlat expanded.
-### Global
-
-
-random_file:: Provides random number generator.
-
-
-
-ldap_debug:: Debug flags for libldap (see OpenLDAP documentation).
-
-.Please see the option 'ldap_debug'
-
-
-
### Mapping of LDAP directory attributes to RADIUS dictionary attributes.
WARNING: Although this format is almost identical to the `unlang`
| Parameter | Description
| <fr attr> | Is the destination RADIUS attribute
with any valid list and request qualifiers.
-| <op> | Is any assignment attribute (=, :=, +=, ^=, -=).
+| <op> | Is any assignment attribute (=, :=, +=, -=).
| <ldap attr> | Is the attribute associated with user or
profile objects in the LDAP directory.
If the attribute name is wrapped in double quotes
----
ldap
if ((ok || updated) && &User-Password) {
- update {
- &control.Auth-Type := ldap
- }
+ &control.Auth-Type := ldap
}
----
====
-chase_referrals:: controls whether the server follows references returned by LDAP directory.
+chase_referrals:: controls whether the server follows references returned
+by the LDAP directory.
They are mostly for Active Directory compatibility.
If you set this to `no`, then searches will likely return 'operations error',
-rebind:: If `chase_referrals` is `yes`, then, when a referral is followed, having `rebind`
-set to `no` will cause libldap to do an anonymous bind when making any additional connections.
-Setting this to `yes` will either bind with the admin credentials or the credientials from the
-rebind url depending on `use_referral_credentials`.
+rebind:: If `chase_referrals` is `yes` then, when a referral is followed
+having `rebind` set to `no` will cause the server to do an anonymous bind when
+making any additional connections. Setting this to `yes` will either bind
+with the admin credentials or the credentials from the rebind url depending
+on `use_referral_credentials`.
-ldap_debug:: Debug flags for libldap (see OpenLDAP documentation).
-Set this to enable debugging output from different code areas within libldap.
-
-NOTE: These debugging options can produce significant amounts of logging output.
-
-[options="header,autowidth"]
-|===
-| Option | Value
-| LDAP_DEBUG_TRACE | 0x0001
-| LDAP_DEBUG_PACKETS | 0x0002
-| LDAP_DEBUG_ARGS | 0x0004
-| LDAP_DEBUG_CONNS | 0x0008
-| LDAP_DEBUG_BER | 0x0010
-| LDAP_DEBUG_FILTER | 0x0020
-| LDAP_DEBUG_CONFIG | 0x0040
-| LDAP_DEBUG_ACL | 0x0080
-| LDAP_DEBUG_STATS | 0x0100
-| LDAP_DEBUG_STATS2 | 0x0200
-| LDAP_DEBUG_SHELL | 0x0400
-| LDAP_DEBUG_PARSE | 0x0800
-| LDAP_DEBUG_SYNC | 0x4000
-| LDAP_DEBUG_NONE | 0x8000
-| LDAP_DEBUG_ANY | (-1)
-|===
-
-e.g:
-
-If you want to see the LDAP logs only for `trace` and `parse`,
-facilities you should use:
-
- (LDAP_DEBUG_TRACE + LDAP_DEBUG_PARSE) = 0x0801
-
-Setting the `ldap_debug` configuration item as follows:
-
- ldap_debug = 0x0801
-
-Default: 0x0000 (no debugging messages)
+reconnection_delay:: Sets the time in seconds before a failed connection
+will attempt reconnection. This includes failures to bind as the admin
+user due to incorrect credentials.
# realm = 'example.org'
}
# valuepair_attribute = 'radiusAttribute'
- global {
-# random_file = /dev/urandom
-# ldap_debug = 0x0000
- }
update {
&control.Password.With-Header += 'userPassword'
# &control.NT-Password := 'ntPassword'
idle = 60
probes = 3
interval = 3
- ldap_debug = 0x0000
+ reconnection_delay = 10
}
tls {
# start_tls = yes
-update request { ... }::
-
`Status-Server` packet contents are fixed and cannot
be edited.
-For other packet types, you can create the contents
-here. The section MUST be "update request", and
+For other packet types, you can set the contents
+here. The section MUST be set over "&request.<attribute> = value", and
anything else will cause a parse error.
We RECOMMEND that you use packet contents which
# originate = no
status_check {
type = Status-Server
-# update request {
-# &User-Name := "test-user"
-# &User-Password := "this-is-not-a-real-password"
-# &NAS-Identifier := "Status check. Are you alive?"
-# &Event-Timestamp = 0
-# }
+# &request.User-Name := "test-user"
+# &request.User-Password := "this-is-not-a-real-password"
+# &request.NAS-Identifier := "Status check. Are you alive?"
+# &request.Event-Timestamp = 0
}
response_window = 15
zombie_period = 10
-case_sensitive:: Whether or not we want to treat `user` the same
-as `USER`, or `User`.
-
-Some systems have problems with case sensitivity, so this should be
-set to `no` to enable the comparisons of the key attribute to be
-case insensitive.
-
-
-
check_with_nas:: Accounting information may be lost, so the user MAY
have logged off of the NAS, but we haven't noticed.
radutmp {
filename = ${logdir}/radutmp
username = %{User-Name}
- case_sensitive = yes
check_with_nas = yes
permissions = 0600
# caller_id = "yes"
it will be `redundant_sql`. You can then use this expansion
just like any other:
- update reply {
- Filter-Id := "%{redundant_sql: ... }"
- }
+ &reply.Filter-Id := "%{redundant_sql: ... }"
In this example, the expansion is done via module `sql1`, and if
that expansion fails, using module `sql2`.
|===
| Option | Description
| `uri` | To send the request to.
-| `proxy` | Rhe request via this server, supports `socks/http/https` uri and `:port`.
+| `proxy` | The request via this server, supports `socks/http/https` uri and `:port`.
+ May be set to "none" to disable proxying, overriding any environmental
+ variables set like http_proxy.
| `method` | HTTP method to use, one of 'get', 'post', 'put', 'patch',
'delete' or any custom HTTP method.
| `body` | The format of the HTTP body sent to the remote server.
In some cases, the driver is different from the `dialect`.
-The rlm_sql_null driver can be used with any `dialect`,
+The null driver can be used with any `dialect`,
along with the `logfile` directive below. It will then
write the SQL queries to a log file.
[options="header,autowidth"]
|===
| Driver | Dialect
-| rlm_sql_db2 | mssql
-| rlm_sql_firebird | mssql
-| rlm_sql_freetds | mssql
-| rlm_sql_null | any
-| rlm_sql_unixodbc | mssql
+| db2 | mssql
+| firebird | mssql
+| freetds | mssql
+| null | any
+| unixodbc | mssql
|===
-query_timeout:: Set the maximum query duration for `rlm_sql_mysql` and `rlm_sql_cassandra`.
+query_timeout:: Set the maximum query duration for `mysql` and `cassandra`.
[options="header,autowidth"]
|===
-| Driver | Description
-| rlm_sql_firebird | Likely possible but no documentation.
-| rlm_sql_oracle | Not possible.
-| rlm_sql_postgresql | Should be set via the radius_db string instead.
+| Driver | Description
+| firebird | Likely possible but no documentation.
+| oracle | Not possible.
+| postgresql | Should be set via the radius_db string instead.
|===
+offer_duration:: DHCP offer duration.
+
+
+
+pool_name: The attribute in the `control` list which contains the pool name.
+
+
+
allocated_address_attr:: List and attribute where the allocated address is written to.
[NOTE]
dialect = "mysql"
ippool_table = "fr_ippool"
lease_duration = 3600
+ offer_duration = 60
+ pool_name = IP-Pool.Name
allocated_address_attr = radius.Framed-IP-Address
owner = "%{radius.Calling-Station-ID}"
# owner = "%{%{dhcpv4.Client-Identifier}:-%{dhcpv4.Client-Hardware-Address}}"
--- /dev/null
+
+
+
+Time-based One-Time Passwords (TOTP)
+
+Defined in https://tools.ietf.org/html/rfc6238[RFC 6238], and used in Google Authenticator.
+
+This module can only be used in the "authenticate" section.
+
+The Base32-encoded secret should be placed into:
+
+
+The TOTP password entered by the user should be placed into:
+
+
+The module will return "ok" if the passwords match, and "fail"
+if the passwords do not match.
+
+Note that this module will NOT interact with Google. The module is
+intended to be used where the local administrator knows the TOTP
+secret key, and user has an authenticator app on their phone.
+
+Note also that while you can use the Google "chart" APIs to
+generate a QR code, doing this will give the secret to Google!
+
+Administrators should instead install a tool such as "qrcode"
+
+
+and then run that locally to get an image.
+
+
+The module takes no configuration items.
+
+
+== Default Configuration
+
+```
+# &control.TOTP.Secret
+# &request.TOTP.From-User
+# https://linux.die.net/man/1/qrencode
+totp {
+}
+```
recv Access-Request {
radius
if (ok) {
- update reply {
- &Packet-Type := Access-Accept
- }
+ &reply.Packet-Type := Access-Accept
}
}
send Access-Accept {
-Should likely be ${localstatedir}/lib/radiusd
-
-
-
libdir:: Where to find the rlm_* modules.
This should be automatically set at configuration time.
colourise:: Highlight important messages sent to stderr and stdout.
-Option will be ignored (disabled) if output if `TERM` is not
+Option will be ignored (disabled) if output of `TERM` is not
an xterm or output is not to a TTY.
+.Global Library Settings
+
+Each library which has global settings will have its own configuration
+file in global.d
+
+
+
.Module Configuration
The names and configuration of each module is located in this section.
-.Instantiation
-
-This section orders the loading of the modules. Modules
-listed here will get loaded BEFORE the later sections like
-authorize, authenticate, etc. get examined.
-
-This section is not strictly needed. When a section like
-authorize refers to a module, it's automatically loaded and
-initialized. However, some modules may not be listed in any
-of the following sections, so they can be listed here.
-
-Also, listing modules here ensures that you have control over
-the order in which they are initialized. If one module needs
-something defined by another module, you can list them in order
-here, and ensure that the configuration will be OK.
-
-After the modules listed here have been loaded, all of the modules
-in the "mods-enabled" directory will be loaded. Loading the
-"mods-enabled" directory means that unlike Version 2, you usually
-don't need to list modules here.
-
-
-We list the counter module here so that it registers
-the check_name attribute before any module which sets
-it.
-
-
-
-subsections here can be thought of as `virtual` modules.
-
-e.g. If you have two redundant SQL servers, and you want to
-use them in the authorize and accounting sections, you could
-place a `redundant` block in each section, containing the
-exact same text. Or, you could uncomment the following
-lines, and list `redundant_sql` in the authorize and
-accounting sections.
-
-The `virtual` module defined here can also be used with
-dynamic expansions, under a few conditions:
-
- * The section is `redundant`, or `load-balance`, or
- `redundant-load-balance`
- * The section contains modules ONLY, and no sub-sections
- * All modules in the section are using the same rlm_
- driver, e.g. They are all sql, or all ldap, etc.
-
-When those conditions are satisfied, the server will
-automatically register a dynamic expansion, using the
-name of the `virtual` module. In the example below,
-it will be `redundant_sql`. You can then use this expansion
-just like any other:
-
- update reply {
- Filter-Id := "%{redundant_sql: ... }"
- }
-
-In this example, the expansion is done via module `sql1`,
-and if that expansion fails, using module `sql2`.
-
-For best results, configure the `pool` subsection of the
-module so that `retry_delay` is non-zero. That will allow
-the redundant block to quickly ignore all "down" SQL
-databases. If instead we have `retry_delay = 0`, then
-every time the redundant block is used, the server will try
-to open a connection to every `down` database, causing
-problems.
-
- sql1
- sql2
-
-
.Policies
-Policies are virtual modules, similar to those defined in the
-`instantiate` section above.
+Policies are virtual modules.
Defining a policy in one of the `policy.d` files means that it can be
referenced in multiple places as a *name*, rather than as a series of
certdir = ${confdir}/certs
cadir = ${confdir}/certs
run_dir = ${localstatedir}/run/${name}
-db_dir = ${raddbdir}
+db_dir = ${localstatedir}/lib/${name}
libdir = ${exec_prefix}/lib
pidfile = ${run_dir}/${name}.pid
#panic_action = "gdb %e %p"
# openssl_async_pool_max = 1024
}
#$INCLUDE trigger.conf
+global {
+ $INCLUDE global.d/
+}
modules {
# $INCLUDE mods-enabled/sql
$INCLUDE mods-enabled/
}
-instantiate {
-# dailycounter
-# redundant redundant_sql {
-# }
-}
policy {
$INCLUDE policy.d/
}
eap
}
send Access-Accept {
- update {
- &reply += &session-state
- }
+ &reply += &session-state
# cui
# reply_log
-sql
}
server challenge {
recv Access-Request {
- if (!State) {
- update control {
- Auth-Type := Step1
- Password.Cleartext := "hello"
- }
+ if (!&State) {
+ &control.Auth-Type := Step1
+ &control.Password.Cleartext := "hello"
}
else {
- update control {
- Auth-Type := Step2
- Password.Cleartext := &session-state.Tmp-Integer-0
- }
+ &control.Auth-Type := Step2
+ &control.Password.Cleartext := &session-state.Tmp-Integer-0
}
}
authenticate step1 {
pap
- update session-state {
- Tmp-Integer-0 := "%{randstr:n}"
- }
- update reply {
- Reply-Message := &session-state.Tmp-Integer-0
- }
+ &session-state.Tmp-Integer-0 := "%{randstr:n}"
+ &reply.Reply-Message := &session-state.Tmp-Integer-0
challenge
}
authenticate step2 {
+
+
This virtual server allows EAP-TLS to reject access requests
based on some attributes of the certificates involved.
hit external services such as sql or ldap.
+
Authorize - this is the only section required.
To accept the access request, set Auth-Type = Accept, otherwise
groupmembership_filter = "(&(objectClass=group)(member=%{control.Ldap-UserDn}))"
+
+
Now let's test membership of an LDAP group (the ldap bind user will
need permission to read this group membership):
+
or, to be more specific, you could use the group's full DN:
if (!(Ldap-Group == "CN=Permitted-Laptops,OU=Groups,DC=example,DC=org")) {
-
== Default Configuration
```
server check-eap-tls {
recv Access-Request {
- update config {
- &Auth-Type := Accept
- }
+ &control.Auth-Type := Accept
# if ("%{session-state.TLS-Client-Cert-Common-Name}" == 'client.example.com') {
-# update config {
-# &Auth-Type := Accept
-# }
+# &control.Auth-Type := Accept
# }
# else {
-# update config {
-# &Auth-Type := Reject
-# }
-# update reply {
-# &Reply-Message := "Your certificate is not valid."
-# }
+# &control.Auth-Type := Reject
+# &reply.Reply-Message := "Your certificate is not valid."
# }
# if (&User-Name == "host/%{session-state.TLS-Client-Cert-Common-Name}") {
-# update config {
-# &Auth-Type := Accept
-# }
+# &control.Auth-Type := Accept
# }
# else {
-# update config {
-# &Auth-Type := Reject
-# }
+# &control.Auth-Type := Reject
# }
# ldap
# if (!(Ldap-Group == "Permitted-Laptops")) {
-# update config {
-# &Auth-Type := Reject
-# }
+# &control.Auth-Type := Reject
# }
# files
auth_log
-
Split the string and split into pieces.
Send an update for each session we find.
-
-
NAS-IP-Address
Acct-Session-Id
-
-
-
The subrequest begins empty, so initially copy all attributes
from the incoming request.
-
Remove attributes which will confuse the NAS
The NAS will "helpfully" NAK the packet
Uncomment if the NAS does not expect User-Name
-&User-Name !* ANY
-
+&request -= &User-Name[*]
Call the radius client module instance for the NAS-IP-Address
+
+
Receive a Disconnect request
}
}
recv CoA-Request {
- update control {
-# &Tmp-String-0 := "%{sql:SELECT IFNULL(GROUP_CONCAT(CONCAT(nasipaddress,'#',acctsessionid) separator '|'),'') FROM (SELECT * FROM radacct WHERE ('%{User-Name}'='' OR UserName='%{User-Name}') AND ('%{Acct-Session-Id}'='' OR acctsessionid = '%{Acct-Session-Id}') AND AcctStopTime IS NULL) a}"
-# &Tmp-String-0 := "%{sql:SELECT STRING_AGG(CONCAT(nasipaddress,'#',acctsessionid),'|') FROM (SELECT * FROM radacct WHERE ('%{User-Name}'='' OR UserName='%{User-Name}') AND ('%{Acct-Session-Id}'='' OR acctsessionid = '%{Acct-Session-Id}') AND AcctStopTime IS NULL) a}"
- &Tmp-Integer-0 := 0
- }
+# &control.Tmp-String-0 := "%{sql:SELECT IFNULL(GROUP_CONCAT(CONCAT(nasipaddress,'#',acctsessionid) separator '|'),'') FROM (SELECT * FROM radacct WHERE ('%{User-Name}'='' OR UserName='%{User-Name}') AND ('%{Acct-Session-Id}'='' OR acctsessionid = '%{Acct-Session-Id}') AND AcctStopTime IS NULL) a}"
+# &control.Tmp-String-0 := "%{sql:SELECT STRING_AGG(CONCAT(nasipaddress,'#',acctsessionid),'|') FROM (SELECT * FROM radacct WHERE ('%{User-Name}'='' OR UserName='%{User-Name}') AND ('%{Acct-Session-Id}'='' OR acctsessionid = '%{Acct-Session-Id}') AND AcctStopTime IS NULL) a}"
+ &control.Tmp-Integer-0 := 0
if ("%(explode:&control.Tmp-String-0 |)") {
foreach &control.Tmp-String-0 {
if ("%{Foreach-Variable-0}" =~ /([^#]*)#(.*)/) {
- update control {
- &Tmp-IP-Address-0 := "%{1}"
- &Tmp-String-1 := "%{2}"
- }
+ &control.Tmp-IP-Address-0 := "%{1}"
+ &control.Tmp-String-1 := "%{2}"
subrequest CoA-Request {
- update request {
- &request := &parent.request[*]
- &Acct-Session-Id := &parent.control.Tmp-String-1
- &Event-Timestamp := "%l"
- &Message-Authenticator := 0x00
- }
- filter request {
- &SQL-User-Name !* ANY
- &Acct-Delay-Time !* ANY
- &Proxy-State !* ANY
- }
+ &request := &parent.request
+ &request.Acct-Session-Id := &parent.control.Tmp-String-1
+ &request.Event-Timestamp := "%l"
+ &request.Message-Authenticator := 0x00
+ &request -= &SQL-User-Name[*]
+ &request -= &Acct-Delay-Time[*]
+ &request -= &Proxy-State[*]
switch &parent.control.Tmp-IP-Address-0 {
case "192.0.2.1" {
- update parent.control {
- &Tmp-Integer-0 := %{expr: %{parent.control.Tmp-Integer-0} + 1}
- }
+ &parent.control.Tmp-Integer-0 += 1
radius-originate-coa-192.0.2.1
}
case {
- update parent.control {
- &Reply-Message += "Missing map for NAS: %{parent.control.Tmp-IP-Address-0}"
+ &parent.control += {
+ &Reply-Message = "Missing map for NAS: %{parent.control.Tmp-IP-Address-0}"
}
}
} # subrequest
} # foreach session
}
if (&control.Tmp-Integer-0) {
- update reply {
- &Reply-Message += "Sent updates for %{control.Tmp-Integer-0} active sessions"
+ &reply += {
+ &Reply-Message = "Sent updates for %{control.Tmp-Integer-0} active sessions"
}
ok
} else {
- update reply {
- &Reply-Message += "No active sessions found"
+ &reply += {
+ &Reply-Message = "No active sessions found"
}
reject
}
--- /dev/null
+
+
+
+
+= The cron Virtual Server
+
+The `cron` virtual server is an example of using `cron` style functionality in FreeRADIUS.
+
+## The Virtual Server
+
+This is the `cron` virtual server.
+
+
+namespace:: The protocol / dictionary to use.
+
+The `cron` functionality can be used with any protocol.
+
+
+
+You can have a `radius` subsection here. See the `default`
+virtual server for documentation.
+
+
+
+Create a `cron` listener. Note that leaving off the `cron` name
+will result in the protocol trying to open a socket!
+
+
+type:: What type of packet is being processed.
+
+The `type` should be a valid name for the protocol.
+
+
+
+transport: What kind of cron functionality we are using.
+
+For now, only `crontab` is supported.
+
+
+
+crontab:: Run `crontab` style jobs.
+
+
+timespec:: the `crontab` style time specification.
+
+The fields are:
+
+ * minute (0-59)
+ * hour (0-59)
+ * day of month (1-31)
+ * month of year (1-12)
+ * day of week (0-6)
+
+The allowed values follow the specification given in
+`man 5 crontab`, or https://man7.org/linux/man-pages/man5/crontab.5.html
+
+Multiple values can be given, separated by comma:
+ * 1,2,3
+
+Ranges can be specified
+ * 1-4
+ * `*`
+
+Steps can be given for ranges:
+ * 1-20/4
+
+
+
+filename:: The file which is read, cached, and processed
+
+When the timer hits, the `cron` section processes the attributes
+from this file, as if they had been received from the network.
+
+Nothing is done with the reply packet (if
+anything). The `cron` functionality
+assumes that all of the work necessary for
+`cron` is done inside of the processing
+sections.
+
+
+
+
+
+
+== Default Configuration
+
+```
+server cron {
+ namespace = radius
+ listen cron {
+ type = Access-Request
+ transport = crontab
+ crontab {
+ timespec = "* * * * *"
+ filename = /Users/alandekok/git/wrapper/freeradius-server/user_password
+ }
+ }
+recv Access-Request {
+ ok
+}
+send Access-Accept {
+ ok
+}
+send Access-Reject {
+ ok
+}
+send Do-Not-Respond {
+ ok
+}
+}
+```
-
-
= The default Virtual Server
The `default` virtual server is the first one that is enabled on a
In most cases, those small changes will result in the server being
able to connect to the database, and to authenticate users.
+
+
## The Virtual Server
This is the `default` virtual server.
}
}
}
- listen {
+ listen tcp_auth {
type = Access-Request
type = Status-Server
transport = tcp
}
}
}
- listen {
+ listen udp_acct {
type = Accounting-Request
transport = udp
udp {
# filter_password
# operator-name
# if (&User-Name =~ /@example\.com$/) {
-# update control {
-# &Auth-Type := "proxy-example.com"
-# }
+# &control.Auth-Type := "proxy-example.com"
# }
# cui
# auth_log
# post_proxy_log.post-proxy
#}
send Access-Challenge {
- attr_filter.access_challenge.post-auth
+ attr_filter.access_challenge
handled
}
send Access-Accept {
# if (!&reply.State) {
-# update reply {
-# &State := "0x%{randstr:16h}"
-# }
+# &reply.State := "0x%{randstr:16h}"
# }
- update {
- &reply += &session-state
- }
+ &reply += &session-state
eap
# sqlippool
# cui
-sql
# sql_log
# ldap
-# update request {
-# &WiMAX-MN-NAI = "%{User-Name}"
-# }
+# &request.WiMAX-MN-NAI = "%{User-Name}"
# update reply {
# &Vendor-Specific.WiMAX.FA-RK-Key = 0x00
# &Vendor-Specific.WiMAX.MSK = "%{reply.EAP-MSK}"
# }
# wimax
-# update reply {
-# &Reply-Message += "%{session-state.TLS-Certificate.Serial}"
-# &Reply-Message += "%{session-state.TLS-Certificate.Not-After}"
-# &Reply-Message += "%{session-state.TLS-Certificate.Subject}"
-# &Reply-Message += "%{session-state.TLS-Certificate.Issuer}"
-# &Reply-Message += "%{session-state.TLS-Certificate.Common-Name}"
-# &Reply-Message += "%{session-state.TLS-Certificate.Subject-Alt-Name-Email}"
+# &reply += {
+# &Reply-Message = "%{session-state.TLS-Certificate.Serial}"
+# &Reply-Message = "%{session-state.TLS-Certificate.Not-After}"
+# &Reply-Message = "%{session-state.TLS-Certificate.Subject}"
+# &Reply-Message = "%{session-state.TLS-Certificate.Issuer}"
+# &Reply-Message = "%{session-state.TLS-Certificate.Common-Name}"
+# &Reply-Message = "%{session-state.TLS-Certificate.Subject-Alt-Name-Email}"
# }
# insert_acct_class
# if (&reply.EAP-Session-Id) {
-# update reply {
-# &EAP-Key-Name := &reply.EAP-Session-Id
-# }
+# &reply.EAP-Key-Name := &reply.EAP-Session-Id
# }
remove_reply_message_if_eap
}
}
recv Accounting-Request {
# acct_counters64
-# update request {
-# &FreeRADIUS-Acct-Session-Start-Time = "%{expr: %{%{Event-Timestamp}:-%l} - %{%{Acct-Session-Time}:-0} - %{%{Acct-Delay-Time}:-0}}"
-# }
+# &request.FreeRADIUS-Acct-Session-Start-Time = "%{expr: %{%{Event-Timestamp}:-%l} - %{%{Acct-Session-Time}:-0} - %{%{Acct-Delay-Time}:-0}}"
if (!&Event-Timestamp) {
- update request {
- &Event-Timestamp := "%{expr:%l - &Acct-Delay-Time}"
- }
+ &request.Event-Timestamp := "%{expr:%l - &Acct-Delay-Time}"
}
acct_unique
files
}
}
recv Accounting-Request {
- update request {
- &Acct-Delay-Time := "%{expr:%{%{Acct-Delay-Time}:-0} + %c - %(integer:%{%{Event-Timestamp}:-%{Packet-Original-Timestamp}})}"
- }
+ &request.Acct-Delay-Time := "%{expr:%{%{Acct-Delay-Time}:-0} + %c - %(integer:%{%{Event-Timestamp}:-%{Packet-Original-Timestamp}})}"
ok
}
send Accounting-Response {
See below for the definition of the "mac2ip"
module.
-mac2ip
If the MAC wasn't found in that list, do something else.
You could call a Perl, Python, or Java script here.
server will fall back to determining the type of reply
based on the rcode of this section.
-update reply {
- &Message-Type = Offer
-}
If Message-Type is not set, returning "ok" or
"updated" from this section will respond with a Offer
message.
Other rcodes will tell the server to not return any response.
-ok
The DHCP Server Identifier is set here since it is returned in OFFERs
If the request is not for this server then silently discard it
Response packet type. See Discover section above.
-update reply {
- &Message-Type = Ack
-}
Call a policy (defined in policy.d/dhcp) to set common reply attributes
See below for the definition of the "mac2ip"
module.
-mac2ip
If the MAC wasn't found in that list, do something else.
You could call a Perl, Python, or Java script here.
"handled" will not return a packet, all other rcodes will
send back a NAK.
-ok
Other DHCP packet types
+
+
Add more logic here. Is the lease inactive?
If so, respond with Lease-Unassigned.
-
This next section is a sample configuration for the "passwd"
module, that reads flat-text files. It should go into
radiusd.conf, in the "modules" section.
#client private {
#}
recv Discover {
- update control {
- &Server-Identifier = 192.0.2.1
- }
+ &control.Server-Identifier = 192.0.2.1
dhcp_common
-# update control {
-# &IP-Pool.Name := "local"
-# }
+# mac2ip
+# &control.IP-Pool.Name := "local"
# dhcp_sqlippool
+# &reply.Message-Type = Offer
+# ok
}
recv Request {
- update control {
- &Server-Identifier = 192.0.2.1
- }
+ &control.Server-Identifier = 192.0.2.1
if (&request.Server-Identifier && \
&request.Server-Identifier != &control.Server-Identifier) {
do_not_respond
}
+# &reply.Message-Type = Ack
dhcp_common
-# update control {
-# &IP-Pool.Name := "local"
-# }
+# mac2ip
+# &control.IP-Pool.Name := "local"
# dhcp_sqlippool
if (ok) {
- update reply {
- &Your-IP-Address := "%{%{request.Requested-IP-Address}:-%{request.Client-IP-Address}}"
- }
+ &reply.Your-IP-Address := "%{%{request.Requested-IP-Address}:-%{request.Client-IP-Address}}"
}
+# ok
}
recv Decline {
-# update control {
-# &IP-Pool.Name := "local"
-# }
+# &control.IP-Pool.Name := "local"
# dhcp_sqlippool
ok
}
ok
}
#recv Inform {
-# update reply {
-# Packet-Dst-Port = 67
-# Message-Type = Ack
-# Server-Identifier = "%{Packet-Dst-IP-Address}"
-# Site-specific-28 = 0x0a00
-# }
+# &reply.Packet-Dst-Port = 67
+# &reply.Message-Type = Ack
+# &reply.Server-Identifier = "%{Packet-Dst-IP-Address}"
+# &reply.Site-specific-28 = 0x0a00
# ok
#}
recv Release {
-# update control {
-# &IP-Pool.Name := "local"
-# }
+# &control.IP-Pool.Name := "local"
# dhcp_sqlippool
ok
}
elsif (&Client-Identifier) {
}
else {
- update reply {
- &Message-Type = Lease-Unknown
- }
+ &reply.Message-Type = Lease-Unknown
ok
return
}
if (notfound) {
- update reply {
- &Message-Type = Lease-Unknown
- }
+ &reply.Message-Type = Lease-Unknown
ok
return
}
- update reply {
- &Message-Type = Lease-Unassigned
- }
+ &reply.Message-Type = Lease-Unassigned
}
}
# 00:01:02:03:04:05,192.0.2.100
of the following sections, named after the DHCP packet type.
See dictionary.dhcp for the packet types.
IP Address of the DHCP server
+
IP Address of the DHCP relay (ourselves)
+
IP Address of the DHCP server
+IP Address of the Gateway server
+
+
== Default Configuration
```
interface = eth1
}
dhcp Discover {
- update config {
- &Relay-To-IP-Address := 192.0.2.2
- }
- update request {
- &Gateway-IP-Address := 192.0.2.1
- }
+ &control.Relay-To-IP-Address := 192.0.2.2
+ &request.Gateway-IP-Address := 192.0.2.1
ok
}
dhcp Request {
- update config {
- &Relay-To-IP-Address := 192.0.2.2
- }
- update request {
- &Gateway-IP-Address := 192.0.2.2
- }
+ &control.Relay-To-IP-Address := 192.0.2.2
+ &request.Gateway-IP-Address := 192.0.2.2
ok
}
}
+#### State machine configuration
+
+
+status_code_on_success:: Include a status-code
+option in the packet even when the operation is
+successful (status code 0).
+
+RFC8415 states that the absence of a status-code
+option is identical to a status-code option with
+value (0). This option is included in case
+there are broken DHCPv6 clients that require an
+explicit success notification.
+
+This config item is disabled by default as
+including status-code adds approximately 6 bytes
+per nested message, and some clients are buggy
+and count any status-code option as a failure
+indication.
+
+
+
+send_failure_message:: Concatenate the contents
+of any Module-Failure-Message attribute in the
+request, and include it in the message field
+of the status-code option when status-code is
+not 0 or when `status_code_on_success = yes`.
+
+This is disabled by default as these messages
+may reveal sensitive information about the
+internal state of the server.
+
+It's recommended to only enable this config item
+for debugging, or in conjunction with
+move_failure_message_to_parent where the upsteam
+relay is trusted and secure.
+
+
+
+move_failure_message_to_parent:: Move all
+Module-Failure-Message attributes to the parent
+request.
+
+Attributes are only moved when:
+
+- A parent request is available.
+- The parent request of type DHCPv6.
+- status-code != 0, or `status_code_on_success = yes`
+
+When combined with send_failure_message and
+a secure upstream DHCPv6 relay this provides a
+useful debugging tool where the reason for a
+given allocation failure can be determined from
+packet traces, or trace functionality on the
+upstream relay.
+
+As relays will strip off the outer relay-message
+as the packet moves through them, the contents
+of the Module-Failure-Message will not reach
+the end DHCPv6 client.
+
+
+
Receive a Solicit message
interface = ${...interface}
}
}
+ dhcpv6 {
+# status_code_on_success = no
+# send_failure_message = no
+# move_failure_message_to_parent = yes
+ }
recv Solicit {
ok
}
send Advertise {
- update reply {
- &Server-ID.DUID = UUID
- &Server-ID.DUID.UUID.Value := 0x00000000000000000000000000000000
- }
+ &reply.Server-ID.DUID = UUID
+ &reply.Server-ID.DUID.UUID.Value := 0x00000000000000000000000000000000
}
recv Request {
ok
}
send Offer {
- update reply {
- &Server-ID.DUID = UUID
- &Server-ID.DUID.UUID.Value := 0x00000000000000000000000000000000
- }
+ &reply.Server-ID.DUID = UUID
+ &reply.Server-ID.DUID.UUID.Value := 0x00000000000000000000000000000000
}
recv Information-Request {
ok
}
send Reply {
- update reply {
- &Server-ID.DUID = UUID
- &Server-ID.DUID.UUID.Value := 0x00000000000000000000000000000000
- }
+ &reply.Server-ID.DUID = UUID
+ &reply.Server-ID.DUID.UUID.Value := 0x00000000000000000000000000000000
}
}
```
useless, but it documents the attributes
you need.
-
Copy the IP address of the client from
the request just received
virtual_server defined, then that is used,
and there is no need to define this attribute.
-&FreeRADIUS-Client-Virtual-Server = "something"
-
+&control.FreeRADIUS-Client-Virtual-Server = "something"
Example 2: Look the clients up in SQL.
}
}
new client {
- update control {
- &FreeRADIUS-Client-IP-Address = "%{Packet-Src-IP-Address}"
- &FreeRADIUS-Client-Require-MA = no
- &FreeRADIUS-Client-Secret = "testing123"
- &FreeRADIUS-Client-Shortname = "%{Packet-Src-IP-Address}"
- &FreeRADIUS-Client-NAS-Type = "other"
- }
+ &control.FreeRADIUS-Client-IP-Address = "%{Packet-Src-IP-Address}"
+ &control.FreeRADIUS-Client-Require-MA = no
+ &control.FreeRADIUS-Client-Secret = "testing123"
+ &control.FreeRADIUS-Client-Shortname = "%{Packet-Src-IP-Address}"
+ &control.FreeRADIUS-Client-NAS-Type = "other"
map sql "SELECT nasname,shortname,secret,type,server FROM nas WHERE nasname = '%{Packet-Src-IP-Address}' LIMIT 1" {
&control.FreeRADIUS-Client-IP-Address := 'nasname'
&control.FreeRADIUS-Client-Shortname := 'shortname'
&control.FreeRADIUS-Client-Virtual-Server := 'server'
}
if ("%{ldap:ldap:///OU=Elements,OU=Radius,DC=ACME,DC=COM?ou?sub?cn=%{Packet-Src-IP-Address}}") {
- update control {
- &FreeRADIUS-Client-IP-Address = "%{Packet-Src-IP-Address}"
- &FreeRADIUS-Client-Shortname = "%{ldap:ldap:///OU=Elements,OU=Radius,DC=ACME,DC=COM?l?sub?cn=%{Packet-Src-IP-Address}}"
- &FreeRADIUS-Client-Secret = "%{ldap:ldap:///OU=Elements,OU=Radius,DC=ACME,DC=COM?ou?sub?cn=%{Packet-Src-IP-Address}}"
- }
+ &control.FreeRADIUS-Client-IP-Address = "%{Packet-Src-IP-Address}"
+ &control.FreeRADIUS-Client-Shortname = "%{ldap:ldap:///OU=Elements,OU=Radius,DC=ACME,DC=COM?l?sub?cn=%{Packet-Src-IP-Address}}"
+ &control.FreeRADIUS-Client-Secret = "%{ldap:ldap:///OU=Elements,OU=Radius,DC=ACME,DC=COM?ou?sub?cn=%{Packet-Src-IP-Address}}"
}
ok
}
the final `EAP-Success` packet containing `MPPE` keys.
-
-protected_success:: Send protected success messages
-
-
-
-virtual_server:: Same as for `TTLS`, `PEAP`, etc.
-
-
request_identity:: Send a AKA-Identity message to request
an additional identity to the one from the EAP-Identity-Response.
ephemeral_id_length:: The length of any pseudonyms or
fastauth identities we generate (not including hint byte).
-See sites-available/eap-aka-sim for details on how to trigger
-the generation of pseudonym or fastauth identities.
-
strip_permanent_identity_hint:: Strip the identity hint when
to execute the `load session { ... }` section next. This is
sometimes useful when dealing with non-standard fastauth identities.
+#### Custom identity schemes
+
+Multiple identity privacy schemes have been proposed for
+EAP-SIM/AKA/AKA'. Instead of hard coding implementations in the server
+source we've provided the necessary cryptographic functions for them to be
+implemented in policy.
+
+The notable exception to this is the scheme described in
+3GPP TS 33.234 which is supported via the following expansions functions:
+
+- 3gpp_temporary_id_key_index
+- 3gpp_temporary_id_decrypt
+- 3gpp_temporary_id_encrypt
+
+The rlm_cipher module and the &control.KDF-Identity attribute override
+(see notes below) are provided to allow the "Privacy Protection for EAP-AKA"
+scheme described by 3GPP S3-170116 and the Wireless Broadband Allowance
+document "IMSI PRIVACY PROTECTION FOR WI-FI".
+
### `send Identity-Request { ... }` - Allow user massaging of Identity-Request
If retrieving triplets from the AuC, you should should provide
three sets of the following control attributes:
-- `SIM-KC`:: Authentication value from the AuC.
-- `SIM-RAND`:: User authentication challenge.
-- `SIM-SRES`:: Signing response.
+- `KC`:: Authentication value from the AuC.
+- `RAND`:: User authentication challenge.
+- `SRES`:: Signing response.
If retrieving quintuplets from an AuC, you should provide the
following control attributes:
-- `SIM-AUTN`:: Authentication value from the AuC.
-- `SIM-CK`:: Ciphering Key.
-- `SIM-IK`:: Integrity Key.
-- `SIM-RAND`:: User authentication challenge.
-- `SIM-XRES`:: Signing response.
-- `SIM-SQN`:: (optional)
-- `SIM-AK`:: (optional)
+- `AUTN`:: Authentication value from the AuC.
+- `CK`:: Ciphering Key.
+- `IK`:: Integrity Key.
+- `RAND`:: User authentication challenge.
+- `XRES`:: Signing response.
+- `SQN`:: (optional)
+- `AK`:: (optional)
### Pseudonyms
message, or sent as an AT_IDENTITY value. One such identity privacy
scheme described by 3GPP S3-170116 "Privacy Protection for EAP-AKA",
where the cryptographic identity is the plaintext extracted from
-the encrypted identity blob.
+the encrypted identity blob. The same behaviour is required for the
+evolution of that standard published by the WBA
+"IMSI PRIVACY PROTECTION FOR WI-FI".
+
+Both standards as implemented in iOS and Android violate https://tools.ietf.org/html/rfc4186[RFC 4186],
+https://tools.ietf.org/html/rfc4187[RFC 4187],and https://tools.ietf.org/html/rfc5448[RFC 5448] in requiring that the Identity input to the
+cryptographic function used to derive the MK for the session be set
+to the decrypted identity, not the last value of AT_IDENTITY as
+stated by the original RFCs.
+
+No where is this mentioned in either the original 3GPP proposal or the
+WBA document.
If you need to implement one of these identity privacy schemes, the
cryptographic identity can be specified with `&control.KDF-Identity`.
# protected_success = yes
# }
eap-aka {
-# protected_success = no
-# virtual_server = ""
# request_identity = no
# ephemeral_id_length = 14
# strip_permanent_identity_hint = yes
+
Listen on 192.0.2.1:1812 for Access-Requests
When the server receives a packet, it is processed
secret = testing123
}
recv Access-Request {
- if (&User-Name == 'bob') {
- update control {
- &Password.Cleartext := 'bob'
- }
+ if (&User-Name == "bob") {
+ &control.Password.Cleartext := "bob"
}
reject
}
send Access-Accept {
}
send Access-Reject {
- update reply {
- &Reply-Message = 'This is only an example.'
- }
+ &reply.Reply-Message = "This is only an example."
}
}
```
authentication methods.
If you need to send a reply attribute in the outer session,
-the ONLY safe way is to update the outer session-state.
+the ONLY safe way is to set the outer session-state list.
Attributes that should be provided in the reply should be
copied to the outer.session-state list:
- update outer.session-state {
- ...
- }
+ &outer.session-state.Attribute := <Value>
The default configuration in the outer post-auth "send" section
will copy this to the reply. To copy the entire reply see
send Access-Reject {
-sql
attr_filter.access_reject
- update outer.session-state {
- &Module-Failure-Message := &request.Module-Failure-Message
- }
+ &outer.session-state.Module-Failure-Message := &request.Module-Failure-Message
}
} # inner-tunnel server block
```
and call the `radius` module to send the packet.
-Note that this functionality is configured differently from v3.
+NOTE: This functionality is configured differently from v3.
}
recv Accounting-Request {
subrequest Disconnect-Request {
- update request {
- &User-Name := &parent.request.User-Name
- &Acct-Session-Id := &parent.request.Acct-Session-Id
- &NAS-Identifier := &parent.request.NAS-Identifier
- &NAS-IP-Address := &parent.request.NAS-IP-Addres
- &NAS-IPv6-Address := &parent.request.NAS-IPv6-Address
- &NAS-Port := &parent.request.NAS-Port
- &Framed-IP-Address := &parent.request.Framed-IP-Address
- }
+ &request.User-Name := &parent.request.User-Name
+ &request.Acct-Session-Id := &parent.request.Acct-Session-Id
+ &request.NAS-Identifier := &parent.request.NAS-Identifier
+ &request.NAS-IP-Address := &parent.request.NAS-IP-Addres
+ &request.NAS-IPv6-Address := &parent.request.NAS-IPv6-Address
+ &request.NAS-Port := &parent.request.NAS-Port
+ &request.Framed-IP-Address := &parent.request.Framed-IP-Address
radius.coa
}
} # recv Accounting-Request
# requests for EAP-TTLS and PEAP types.
server proxy-inner-tunnel {
recv Access-Request {
- update control {
- &Proxy-To-Realm := "example.com"
- }
+ &control.Proxy-To-Realm := "example.com"
}
authenticate eap {
eap
# This configuration could be done MUCH more simply if ALL
# packets were written to the detail file. But that would
# involve a lot more disk writes, which may not be a good idea.
-# This file is NOT meant to be used as-is. It needs to be
+# NOTE: This file is NOT meant to be used as-is. It needs to be
# edited to match your local configuration.
home_server home1.example.com {
type = acct
load_factor = 10
}
recv Accounting-Request {
- update control {
- &Proxy-To-Realm := 'acct_realm.example.com'
- }
+ &control.Proxy-To-Realm := "acct_realm.example.com"
}
}
```
+
This is a simple server for the MS SoH requests generated by the
-peap module - see "eap.conf" for more info
+peap module - see "raddb/mods-available/eap" for more info
Requests are ONLY passed through the authorize section, and cannot
current be proxied (in any event, the radius attributes used are
internal).
+
+
client NAKed our request for SoH - not supported, or turned off
client replied; check something - this is a local policy issue!
-
== Default Configuration
```
server soh-server {
recv Access-Request {
if (&SoH-Supported == no) {
- update config {
- &Auth-Type = Accept
- }
+ &control.Auth-Type = Accept
}
else {
if (&SoH-MS-Windows-Health-Status =~ /antivirus (warn|error) /) {
- update config {
- &Auth-Type = Reject
- }
- update reply {
- &Reply-Message = 'You must have antivirus enabled & installed!'
- }
+ &control.Auth-Type = Reject
+ &reply.Reply-Message = "You must have antivirus enabled & installed!"
}
else {
- update config {
- &Auth-Type = Accept
- }
+ &control.Auth-Type = Accept
}
}
}
}
recv Authentication-Start {
-sql
- update control {
- &Auth-Type := &Authentication-Type
- }
+ &control.Auth-Type := &Authentication-Type
}
authenticate PAP {
tacacs_pap
}
send Authentication-Start-Reply {
if (&Authentication-Status == Pass) {
- update reply {
- &Server-Message := "Hello %{User-Name}"
- }
+ &reply.Server-Message := "Hello %{User-Name}"
}
}
recv Authentication-Continue {
}
send Authentication-Continue-Reply {
if (&Authentication-Status == Pass) {
- update reply {
- &Server-Message := "Hello %{User-Name}"
- }
+ &reply.Server-Message := "Hello %{User-Name}"
}
}
recv Authorization-Request {
"%{ArgumentList}"
}
send Authorization-Reply {
- update reply {
- &Authorization-Status := Pass-Add
- &Server-Message := "authorization-response-server"
- &Data := "authorization-response-data"
- &ArgumentList := "key1=var1"
- }
+ &reply.Authorization-Status := Pass-Add
+ &reply.Server-Message := "authorization-response-server"
+ &reply.Data := "authorization-response-data"
+ &reply.ArgumentList := "key1=var1"
}
recv Accounting-Request {
detail
accounting Stop {
}
send Accounting-Reply {
- update reply {
- &Accounting-Status := Success
- &Server-Message := "Success"
- &Data := 0x00
- }
+ &reply.Accounting-Status := Success
+ &reply.Server-Message := "Success"
+ &reply.Data := 0x00
}
}
```
+
This section is run whenever the server needs to write an
entry to the TLS session cache.
+
This section is run whenever the server needs to delete an
entry from the TLS session cache.
+
This section is run after certificate attributes are added
to the request list, and before performing OCSP validation.
+
This section is run after OCSP validation has completed.
It should write the attribute &reply.TLS-OCSP-Cert-Valid
and will just cause the server to emit a warning.
+
== Default Configuration
```
-# TLS-Certificate.Serial
-# TLS-Certificate.Expiration
-# TLS-Certificate.Subject
-# TLS-Certificate.Issuer
-# TLS-Certificate.Common-Name
-# TLS-Certificate.Subject-Alt-Name-Email
+# TLS-Cert-Serial
+# TLS-Cert-Expiration
+# TLS-Cert-Subject
+# TLS-Cert-Issuer
+# TLS-Cert-Common-Name
+# TLS-Cert-Subject-Alt-Name-Email
+# TLS-Client-Cert-Serial
+# TLS-Client-Cert-Expiration
+# TLS-Client-Cert-Subject
+# TLS-Client-Cert-Issuer
+# TLS-Client-Cert-Common-Name
+# TLS-Client-Cert-Subject-Alt-Name-Email
server tls-cache {
namespace = tls_cache
load tls-session {
- update control {
- Cache-Allow-Insert := no
- }
+ &control.Cache-Allow-Insert := no
cache_tls_session
}
store tls-session {
- update control {
- Cache-TTL := 0
- }
+ &control.Cache-TTL := 0
cache_tls_session
}
clear tls-session {
- update control {
- Cache-TTL := 0
- Cache-Allow-Insert := no
- }
+ &control.Cache-TTL := 0
+ &control.Cache-Allow-Insert := no
cache_tls_session
}
load ocsp-state {
- update control {
- Cache-Allow-Insert := no
- }
+ &control.Cache-Allow-Insert := no
cache_ocsp
}
store ocsp-state {
- update control {
- Cache-TTL := "%{expr:&reply.TLS-OCSP-Next-Update * -1}"
- Cache-Allow-Merge := no
- }
+ &control.Cache-TTL := "%{expr:&reply.TLS-OCSP-Next-Update * -1}"
+ &control.Cache-Allow-Merge := no
cache_ocsp
}
}
-Type of VMPS packets to listen for.
+transport::
+
+
+
+type:: Type of VMPS packets to listen for.
+
+
+
+ipaddr:: VMPS sockets only support IPv4 addresses.
+
+
+
+port:: Port on which to listen.
+
+NOTE: 1589 is the default VMPS port.
-VMPS sockets only support IPv4 addresses.
-Port on which to listen.
-Allowed values are:
-integer port number
-1589 is the default VMPS port.
Some systems support binding to an interface, in addition
to the IP address. This feature isn't strictly necessary,
but for sites with many IP addresses on one interface,
-it's useful to say "listen on all addresses for
-eth0".
+it's useful to say "listen on all addresses for eth0".
If your system does not support this feature, you will
get an error if you try to use it.
-interface = eth0
-If you have switches that are allowed to send VMPS, but NOT
-RADIUS packets, then list them here as "client" sections.
-Note that for compatibility with RADIUS, you still have to
-list a "secret" for each client, though that secret will not
-be used for anything.
+You can list multiple "client" sections here in order to define
+clients which apply only to this virtual server. i.e. only for
+the VMPS protocol.
+
This section is called when it receives a Join-Request.
Some requests may not have a MAC address. Try to
create one using other attributes.
+
Do a simple mapping of MAC to VLAN.
-See radiusd.conf for the definition of the "mac2vlan"
+See `raddb/mods-available/mac2vlan` for the definition of the "mac2vlan"
module.
-mac2vlan
+
required VMPS reply attributes
-If you have VLAN's in a database, you can select
+
+NOTE: If you have VLAN's in a database, you can `select`
the VLAN name based on the MAC address.
-&VLAN-Name = "%{sql:select ... where mac='%{Mac}'}"
This section is called when it sends a Join-Response.
udp {
ipaddr = *
port = 1589
+# interface = eth0
}
}
recv Join-Request {
if (!&MAC-Address) {
if (&Ethernet-Frame =~ /0x.{12}(..)(..)(..)(..)(..)(..).*/) {
- update request {
- &MAC-Address = "%{1}:%{2}:%{3}:%{4}:%{5}:%{6}"
- }
+ &request.MAC-Address = "%{1}:%{2}:%{3}:%{4}:%{5}:%{6}"
}
else {
- update request {
- &MAC-Address = &Cookie
- }
+ &request.MAC-Address = &Cookie
}
}
- update reply {
- &Packet-Type = Join-Response
- &Cookie = &MAC-Address
- &VLAN-Name = "please_use_real_vlan_here"
- }
+# mac2vlan
+ &reply.Packet-Type = Join-Response
+ &reply.Error-Code = No-Error
+ &reply.Cookie = &MAC-Address
+ &reply.VLAN-Name = "please_use_real_vlan_here"
+# &reply.VLAN-Name = "%{sql:select ... where mac='%{MAC-Address}'}"
}
send Join-Response {
- ok
+ ok
}
recv Reconfirm-Request {
ok
ok
}
send Do-Not-Respond {
- ok
+ ok
}
}
```