unlang(5)

NAME
unlang - FreeRADIUS Processing un-language

DESCRIPTION
FreeRADIUS supports a simple processing language in its configuration files. We call it an "un-language" because the intention is NOT to create yet another programming language. If you need something more complicated than what is described here, we suggest using the Perl or Python modules rlm_perl, or rlm_python. The goal of the language is to allow simple policies to be written with minimal effort. Those policies are then applied when a request is being processed. Requests are processed through virtual servers (including the default one), in the sections titled "recv Access-Request", "send Access-Accept", "authenticate pap", etc. These policies cannot be used in any other part of the configuration files, such as module or client configuration.

KEYWORDS
The keywords for the language are a combination of pre-defined keywords, and references to loadable module names. We document only the pre-defined keywords here. Subject to a few limitations described below, any keyword can appear in any context. The language consists of a series of entries, each one one line. Each entry begins with a keyword. Entries are organized into lists. Processing of the language is line by line, from the start of the list to the end. Actions are executed per-keyword.

if
    Checks for a particular condition. If true, the block after the condition is processed. Otherwise, the block is ignored. See CONDITIONS, below, for documentation on the format of the conditions.
        if (condition) {
            ...
        }

else
    Define a block to be executed only if the previous "if" condition returned false.
        else {
            ...
        }

elsif
    Define a block to be executed only if the previous "if" condition returned false, and if the specified condition evaluates to true.
        elsif (condition) {
            ...
        }

actions
    Allows for the setting of actions inside of a block. The 'actions' block MUST be the last block in the section. The enclosing block MUST be one of 'group', 'if', 'else', 'elsif', or 'case'. See MODULE RETURN CODES, below, for a description of the actions and their meanings.
        if (&User-Name == 'bob') {
            ...
            actions {
                ok = 1
                fail = return
            }
        }

foreach
    Loops over values of an attribute, running the block for each value. The return value of the block is the return value of the last statement executed. The loop can be exited early by using the "break" keyword. No statements may appear after a "break". Inside of the "foreach" block, the attribute which is being looped over can be referenced as "Foreach-Variable-#". Where "#" is the depth of the loop, starting at "0". e.g. "Foreach-Variable-0". The loops can be nested up to eight (8) deep, though this is not recommended.
        foreach &Attribute-Reference {
            ...
        }

load-balance
    This section contains a simple list of modules. When the section is entered, one module is chosen to process the request. All of the modules in the list should be the same type (e.g. ldap or sql). All of the modules in the list should behave identically, otherwise the load-balance section may return different results for the same request. Load-balance sections can contain only a list of modules, and cannot contain keywords that perform conditional operations (if, else, etc) or which modify an attribute list. Load-balance sections can optionally take a key. The key is expanded at run time, hashed, and the hash used to select a module. If no key is given, a module is chosen at random.
        load-balance &User-Name {
        ldap1    # 50% of requests go here
        ldap2    # 50% of requests go here
        } In general, we recommend using "redundant-load-balance" instead of "load-balance". The main use of the keyed load-balance sections is to perform sharding of data across multiple back-ends, without redundancy. i.e. Requests will always go to one back-end, and if that back-end is not available, the "load-balance" section will return "fail".

module-name[.section-name]
    A reference to the named module. When processing reaches this point, the pre-compiled module is called. The module may succeed or fail, and will return a status to "unlang" if so. This status can be tested in a condition. See the "Simple Conditions" text in the CONDITIONS section, and MODULE RETURN CODES, below. If a section-name is provided, it will cause the module to execute as if it were listed in the named section.
        chap # call the CHAP module
        sql # call the SQL module
        ...

parallel
    This section runs subsections in parallel. Each subsection runs as a child request, which is a clone of the parent request. Policies in the child can modify the original parent request by referencing "parent.request", or "parent.reply". The child requests are required because each subsection is run simultaneously. If each subsection modified xthe original request at the same time, it would be impossible to separate the state of each subsection. Empty child requests can be created by using "parallel empty { ... }" Attributes must then be manually copied from the parent to the child. Detached child requests can be created by using "parallel detach { ... }". These child requests are identical copies of the parent. The child requests will run until they are finished. The return code of the parallel section is the same as if each subsection was run sequentially.
        parallel {
            home_server_1
            home_server_2
            ...
        }

redundant
    This section contains a simple list of modules. The first module is called when the section is being processed. If the first module succeeds in its operation, then the server stops processing the section, and returns to the parent section. If, however, the module fails, then the next module in the list is tried, as described above. The processing continues until one module succeeds, or until the list has been exhausted. Redundant sections can contain only a list of modules, and cannot contain keywords that perform conditional operations (if, else, etc) or modify an attribute list.
        redundant {
        sql1    # try this
        sql2    # try this only if sql1 fails.
            ...
        }

redundant-load-balance
    This section contains a simple list of modules. When the section is entered, one module is chosen to process the request. If that module succeeds, then the server stops processing the section. If, however, the module fails, then one of the remaining modules is chosen at random to process the request. This process repeats until one module succeeds, or until the list has been exhausted. All of the modules in the list should be the same type (e.g. ldap or sql). All of the modules in the list should behave identically, otherwise the load-balance section may return different results for the same request. Redundant-load-balance sections can contain only a list of modules, and cannot contain keywords that perform conditional operations (if, else, etc) or modify an attribute list. Please see raddb/radiusd.conf "instantiate" section for more configuration examples. Redundant-load-balance sections can optionally take a key. The key is expanded at run time, hashed, and the hash used to select a module. If no key is given, a module is chosen at random.
        redundant-load-balance {
        ldap1    # 50%, unless ldap2 is down, then 100%
        ldap2    # 50%, unless ldap1 is down, then 100%
        }

return
    Returns from the current section, and stops all processing. This keyword is mainly used to avoid layers of nested "if" and "else" statements.
        recv Access-Request {
            if (...) {
                ...
                return
            }
            ... # this is never reached when the "if"
            ... # statement is executed
        }

subrequest
    The "subrequest" keyword creates an empty subrequest (i.e. child request). Attributes in the child can be copied from the parent by referencing the "parent" list. The packet type and protocol can be changed in a subrequest, by changing the second parameter to the subrequest. That parameter can be: * packet name, e.g. "Access-Request" * protocol followed by packet name, e.g. "dhcpv4.Discover". This configuration allows the server to receive one type of packet, and then create another. For example, the server can receive an Accounting-Request packet, and then create a subrequest that is a Disconnect-Request. That subrequest can then be sent to a NAS. The subrequest is created with no attributes. Any attributes needed by the subrequest should be manually copied from the parent request. The subrequest can also be used to change protocols. For example, the server can receive a RADIUS Access-Request, and then create a DHCPv4 packet of type Discover. Note that when the protocol changes, the attributes in the "subrequest" section are parsed in the context of the new protocol. The original request can be accessed from inside of q "subrequest" section. Simple use "&parent.<ref>" to refer to an attribute in the parent.
        subrequest <type> {
            &request += {
                &User-Name = &parent.request.User-Name
                ...
            }
            ...
        } The purpose of a "subrequest" section is to create a child request which can be edited independently of the parent. The return value of the subrequest is taken from the return value of the subsection being run.

detach
    The "detach" keyword causes a subrequest to be detached from its parent request. The subrequest runs asynchronously to completion. The subrequest immediately returns "noop" to the parent request. The "detach" keyword can only be used inside of a "subrequest" block.

switch
    A "switch" statement takes one argument, and contains a series of "case" statements. When a "switch" statement is encountered, the argument from the "switch" is evaluated in turn against the argument from each "case" statement. The first "case" statement which matches is executed. All other "case" statements are ignored. A default "case" statement can be defined, by omitting its argument. If the argument is a double quoted string (e.g. "%(exec:1 + 2)", it is expanded as described in the DATA TYPES section, below. The match is then performed on the string returned from the expansion. If the argument is an attribute reference (e.g. &User-Name), then the match is performed on the value of that attribute. Otherwise, the argument is taken to be a literal string, and and matching is done via simple comparison. No statement other than "case" can appear in a "switch" block.
        switch <argument> {
            ...
        }

case
    Provides a place-holder which matches the argument of a parent "switch" statement. A "case" statement cannot appear outside of a "switch" block. If the argument is a double quoted string (e.g. "%(exec:1 + 2)", it is expanded as described in the DATA TYPES section, below. The match is then performed on the string returned from the expansion. If the argument is an attribute reference (e.g. &User-Name), then the match is performed on the value of that attribute. Otherwise, the argument is taken to be a literal string, and and matching is done via simple comparison.
        case <argument> {
            ...
        } A default entry can be defined by omitting the argument, as given below. This entry will be used if no other "case" entry matches. Only one default entry can exist in a "switch" section.
        case {
            ...
        }

update
    This keyword has been removed in v4. Please see the new edit syntax.

CONDITIONS
The conditions are similar to C conditions in syntax, though quoted strings are supported, as with the Unix shell.

Simple
    conditions
        (foo) Evaluates to true if 'foo' is a non-empty string (single quotes, double quotes, or back-quoted). Also evaluates to true if 'foo' is a non-zero number. Note that the language is poorly typed, so the string "0000" can be interpreted as a numerical zero. This issue can be avoided by comparing strings to an empty string, rather than by evaluating the string by itself. If the word 'foo' is not a quoted string, then it can be taken as a reference to a named attribute. See "Referencing attribute lists", below, for examples of attribute references. The condition evaluates to true if the named attribute exists. Otherwise, if the word 'foo' is not a quoted string, and is not an attribute reference, then it is interpreted as a reference to a module return code. The condition evaluates to true if the most recent module return code matches the name given here. Valid module return codes are given in MODULE RETURN CODES, below.

Negation
        (!foo) Evaluates to true if 'foo' evaluates to false, and vice-versa.

Short-circuit operators
        (foo || bar)
        (foo && bar) "&&" and "||" are short-circuit operators. "&&" evaluates the first condition, and evaluates the second condition if and only if the result of the first condition is true. "||" is similar, but executes the second command if and only if the result of the first condition is false.

Comparisons
        (foo == bar) Compares 'foo' to 'bar', and evaluates to true if the comparison holds true. Valid comparison operators are "==", "!=", "<", "<=", ">", ">=", "=~", and "!~", all with their usual meanings. Invalid comparison operators are ":=" and "=".

Attribute Comparisons
        (&User-Name == "foo") Compares the value of the User-Name attribute to the string 'foo', and evaluates to true if the comparison holds true. The comparison is done by printing the attribute to a string, and then doing a string comparison of the two sides of the condition.

Inter-Attribute Comparisons
        (&User-Name == &Filter-Id) Compares the value of the User-Name attribute to the contents of the Filter-Id attribute, and evaluates to true if the comparison holds true. Unlike the previous example, this comparison is done in a type-safe way. For example, comparing the IP addresses 1.2.3.4 and 127.0.0.1 as strings will return different results than comparing them as IP addresses. The "&" character in the condition means that the comparison "refers" to the Filter-Id attribute. If left off, it means that the User-Name attribute is compared to the literal string "Filter-Id". Where the left-hand side is an attribute, the "&" can be omitted. However, it is allowed for backwards compatibility. e.g. The comparison "(&User-Name == &Filter-Id)" is equivalent to the example above. We recommend using attribute references instead of printing attributes to a string, e.g. (User-Name == "%{Filter-Id}"). Attribute references will be faster and more efficient. The conditions will check only the first occurrence of an attribute. If there is more than one instance of an attribute, the following syntax should be used:
        (&Attribute-Name[*] == "foo") Using the "[*]" syntax means that it checks all of the instances of the named attribute. If one attribute matches, the condition succeeds. If none match, the condition fails.

Casts
        (<type>foo == bar) The left-hand-side of a condition can be "cast" to a specific data type. The data type must be one which is valid for the dictionaries. e.g. "integer", "ipaddr", etc. The comparison is performed in a type-safe way, as with "Inter-Attribute Comparisons", above. Both sides of the condition are parsed into temporary attributes, and the attributes compared via type-specific methods. The temporary attributes have no other effect, and are not saved anywhere. Casting allows conditions to perform type-specific comparisons. In previous versions of the server, the data would have to be manually placed into an intermediate attribute (or attributes), and then the attribute (or attributes) compared. The use of a cast allows for simpler policies. Casts are allowed only on the left-hand side argument of a condition.

Conditions may be nested to any depth, subject only to line length limitations (8192 bytes).

DATA TYPES
There are only a few data types supported in the language. Reference to attributes, numbers, and strings. Any data type can appear in stand-alone condition, in which case they are evaluated as described in "Simple conditions", above. They can also appear (with some exceptions noted below) on the left-hand or on the right-hand side of a comparison.

numbers
    Numbers are composed of decimal digits. Floating point, hex, and octal numbers are not supported. The maximum value for a number is machine-dependent, but is usually 32-bits, including one bit for a sign value.

word
    Text that is not enclosed in quotes is interpreted differently depending on where it occurs in a condition. On the left hand side of a condition, it is interpreted as a reference to an attribute. On the right hand side, it is interpreted as a simple string, in the same manner as a single-quoted string. Using attribute references permits limited type-specific comparisons, as seen in the examples below.
        if (&User-Name == "bob") {
            ...
        if (&Framed-IP-Address > 127.0.0.1) {
            ...
        if (&Service-Type == Login-User) {

"strings"
    Double-quoted strings are expanded by inserting the value of any attributes (see VARIABLES, below) before being evaluated. If the result is a number it is evaluated in a numerical context. String length is limited by line-length, usually about 8000 characters. A double quote character can be used in a string via the normal back-slash escaping method. ("like \"this\" !")

'strings'
    Single-quoted strings are evaluated as-is. Their values are not expanded as with double-quoted strings above, and they are not interpreted as attribute references.

`strings`
    Back-quoted strings are evaluated by expanding the contents of the string, as described above for double-quoted strings. The resulting command given inside of the string in a sub-shell, and taking the output as a string. This behavior is much the same as that of Unix shells. Note that for security reasons, the input string is split into command and arguments before string expansion is done. For performance reasons, we suggest that the use of back-quoted strings be kept to a minimum. Executing external programs is relatively expensive, and executing a large number of programs for every request can quickly use all of the CPU time in a server. If you believe that you need to execute many programs, we suggest finding alternative ways to achieve the same result. In some cases, using a real language may be sufficient.

/regex/[i][m][s][u][x]
    These strings are valid only on the right-hand side of a comparison, and then only when the comparison operator is "=~" or "!~". They are regular expressions, as implemented by the local regular expression library on the system. Supported regular expression implementations are Posix, libpcre, and libpcre2. The trailing characters after the end of the expression are flags which alter how the expression is interpreted. The 'i' flag indicates that the regular expression match should be done in a case-insensitive fashion. The 'm' flag indicates that carrot '^' and dollar '$' anchors should match on new lines as well as at the start and end of the subject string. The 's' flag causes '.' to match all characters including newlines. The 'u' flag tells the regex engine to assume all input and pattern strings are UTF8 encoded, this affects how the regex engine performs case insensitive matching, and causes it to treat multibyte characters as single atoms. The 'x' flag causes most whitespace characters are ignored, and if a line contains a '#' char, the line content after the '#' is ignored. The primary use of the 'x' flag is to aid readability of complex expressions. Note the 's', 'u', and 'x' flags are only supported when the server is built with libpcre or libpcre2. If the comparison operator is "=~", then parentheses in the regular expression will define variables containing the matching text, as described below in the VARIABLES section.

EXPANSIONS
Attributes are expanded using the ATTRIBUTE REFERENCE syntax described above, and surrounding the reference with "%{...}"
    %{Attribute-Reference} The result will be a string which contains the value of the attribute which was referenced, as a printable string. If the attribute does not exist, the result will be an empty string.

Results of regular expression matches
    If a regular expression match has previously been performed, then the special variable %{0} will contain a copy of the matched portion of the input string. The variables %{1} through %{32} will contain the substring matches, starting from the left-most capture group, onwards. If there are more than 32 capture groups, the additional results will not be accessible. If the server is built with libpcre or libpcre2, the results of named capture groups are available using the "%{regex:capture group}" expansion. They will also be accessible using the variables described above. Every time a regular expression is evaluated, whether it matches or not, the capture group values will be cleared.

Obtaining results from databases
    It is useful to query a database for some information, and to use the result in a condition. The following syntax will call a module, pass it the given string, and replace the string expansion with the resulting string returned from the module.
        %{module:string ...} The syntax of the string is module-specific. Please read the module documentation for additional details. If a literal "}" character is needed inside of an expansion, it should be escaped as "%}". e.g. "%{module:This uses {braces%} as an example}" Many modules will take data that is dynamically expanded, e.g. "%{module:%{Attribute-Name}}". The expansion will be turned into a static string before it is passed to the module.

Conditional Syntax
    Conditional syntax similar to that used in Unix shells may also be used.

    %{%{Foo}:-bar}
        If %{Foo} has a value, returns that value.
        Otherwise, returns literal string "bar".

    %{%{Foo}:-%{Bar}}
        If %{Foo} has a value, returns that value.
        Otherwise, returns the expansion of %{Bar}. These conditional expansions can be nested to almost any depth, such as with %{%{One}:-%{%{Two}:-%{Three}}}

String lengths and arrays
    Similar to a Unix shell, there are ways to reference string lengths, and the second or more instance of an attribute in a list. If you need more than this functionality, we suggest using a real language. e.g. If a request contains "Framed-IP-Address = 127.0.0.1", the expansion of %{hex:Framed-IP-Address} will yield "0x7f000001".

    %{Attribute-Name[#]}
        The number of instances of Attribute-Name. e.g. If a request contains "User-Name = bob", the expansion of %{User-Name[#]} will yield "1".

    %{Attribute-Name[*]}
        All values of Attribute-Name, concatenated together with ',' as the separator.

    %{List-Name.[#]}
        The number of attributes in the named list.

    %{List-Name.[*]}
        All values of attributes in the named-list, concatenated together with ',' as the separator. Use the %(pairs:) xlat to get a list of attributes and values. e.g. If a response contains "Reply-Message = 'Hello', Reply-Message = 'bob' the expansion of "%{reply.Reply-Message[*]} will yield "Hello\nbob"

Other built in expansions

    ${rand:<num>}
        Get random number from 0 to n-1.

    ${randstr:<char_sequence>}
        Get random string built from character classes. Each character in the input char_sequence is substituted for a random character from the specified class. e.g. "%{randstr:CCCC!!cccnnn}" == "IPFL>{saf874"

        c   Lowercase letters - [a-z].

        C   Uppercase letters - [A-Z].

        n   Numbers - [0-9].

        a   Alphanumeric - [a-zA-Z0-9].

        !   Punctuation - [!\"#$%&'()*+,-./:;<=>?@[\]^_`{|}~].

        .   Alphanumeric + punctuation - [a-zA-Z0-9!

        s   Salt - Alphanumeric + "./" - [a-zA-Z0-9].

        o   Characters suitable for OTP (those easily confused omitted) - [469ACGHJKLMNPQRUVWXYabdfhijkprstuvwxyz]

        b   Binary data.

    %{urlquote:<uri>}
        Quote special characters in URI. e.g. "%{urlquote:http://example.org/}" == "http%3A%47%47example.org%47".

    %{urlunquote:<quoted_uri>}
        Unquote URL special characters. e.g. "%{urlunquote:http%%3A%%47%%47example.org%%47}" == "http://example.org/"

    %{tolower:<string>}
        Convert string to lowercase. e.g. "%{tolower:Bar}" == "bar"

    %{toupper:<string>}
        Convert string to uppercase. e.g. "%{toupper:Foo}" == "FOO"

    %{md5:<string>}
        Get the md5 hash of the input string. e.g. "%{md5:foo}" == "acbd18db4cc2f85cedef654fccc4a4d8"

    %{sha1:<string>}
        Get the sha1 hash of the input string. e.g. "%{sha1:foo}" == "0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"

    %{sha224:<string>}
        Get the sha2-224 hash of the input string. e.g. "%{sha224:foo}" == "0808f64e60d58979fcb676c96ec938270dea42445aeefcd3a4e6f8db"

    %{sha256:<string>}
        Get the sha2-256 hash of the input string. e.g. "%{sha256:foo}" == "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae"

    %{sha384:<string>}
        Get the sha2-384 hash of the input string. e.g. "%{sha384:foo}" == "98c11ffdfdd540676b1a137cb1a22b2a70350c9a44171d6b1180c6be5cbb2ee3f79d532c8a1dd9ef2e8e08e752a3babb"

    %{sha512:<string>}
        Get the sha2-512 hash of the input string. e.g. "%{sha512:foo}" == "f7fbba6e0636f890e56fbbf3283e524c6fa3204ae298382d624741d0dc6638326e282c41be5e4254d8820772c5518a2c5a8c0c7f7eda19594a7eb539453e1ed7"

    %{sha3_224:<string>}
        Get the sha3-224 hash of the input string. e.g. "%{sha3_224:foo}" == "f4f6779e153c391bbd29c95e72b0708e39d9166c7cea51d1f10ef58a"

    %{sha3_256:<string>}
        Get the sha3-256 hash of the input string. e.g. "%{sha3_256:foo}" == "76d3bc41c9f588f7fcd0d5bf4718f8f84b1c41b20882703100b9eb9413807c01"

    %{sha3_384:<string>}
        Get the sha3-384 hash of the input string. e.g. "%{sha3_384:foo}" == "665551928d13b7d84ee02734502b018d896a0fb87eed5adb4c87ba91bbd6489410e11b0fbcc06ed7d0ebad559e5d3bb5"

    %{sha3_512:<string>}
        Get the sha3-512 hash of the input string. e.g. "%{sha3_512:foo}" == "4bca2b137edc580fe50a88983ef860ebaca36c857b1f492839d6d7392452a63c82cbebc68e3b70a2a1480b4bb5d437a7cba6ecf9d89f9ff3ccd14cd6146ea7e7"

    %{hmacmd5:&<value_ref> &<key_ref>}
        Generate HMAC-MD5 of input data. e.g. "%{hmacmd5:foo bar}" == "31b6db9e5eb4addb42f1a6ca07367adc"

    %{hmacsha1:&<value_ref> &<key_ref>}
        Generate HMAC-SHA1 of input data. "%{hmacsha1:foo bar}" == "85d155c55ed286a300bd1cf124de08d87e914f3a"

    %(pairs:<list_or_attr>)
        Serialize attributes as a string e.g. "%(pairs:request.[*])" == 'User-Name = "foo"User-Password = "bar"...'

    %(concat:<attr>
        Concatenate the value of multiple attrubute values with an optional separator e.g. "%(concat:%{request.[*]} ', ')" == "foo, bar, ..." Combined with %(pairs:) this can be used to serialise a list of attributes with a separator e.g. "%(concat:%(pairs:request.[*]) ', ')" == "User-Name = 'foo', User-Password = 'bar', ..."

    %(base64.encoded:<string>)
        Encode string as base64. e.g. "%(base64.encode:foo)" == "Zm9v"

    %(explode:&<value_ref> <delim>)
        Split an attribute into multiple new attributes based on a delimiter

    %(nexttime:<epoch>)
        Calculate number of seconds until the end of the next epoch. e.g. if it were 16:18, %(nexttime:1h) would expand to 2520

        <num>h
            Number of seconds remaining in the current hour + <num - 1> * 60 * 60.

        <num>d
            Number of seconds remaining in the current day + <num - 1> * 60 * 60 * 24.

        <num>w
            Number of seconds remaining in the current week + <num - 1> * 60 * 60 * 24 * 7.

        <num>m
            Number of seconds remaining in the current month + if <num> > 1, the number of seconds in the additional months specified.

        <num>y
            Number of seconds remaining in the current year + if <num> > 1, the number of seconds in the additional years specified.

    %(lpad:<string> <rep> <pad>)
        Left-pad a string. e.g. if User-Name is "foo": "%(lpad:%{User-Name} 6 x)" == "xxxfoo"

    %(rpad:<string> <rep> <pad>)
        Right-pad a string. e.g. if User-Name is "foo": "%(rpad:%{User-Name} 5 -)" == "foo--"

ATTRIBUTE ASSIGNMENTS
The attributes described above may be edited by simply assigning a value.. Once the attributes have been defined, they may be referenced as described above in the VARIABLES section. The following syntax defines how to edit an attribute. Each attribute and value has to be all on one line in the configuration file. There is no need for commas or semi-colons after the value.
    &Attribute-Reference = value Please see the HTML documentation for more information.

OTHER KEYWORDS
Other keywords in the language are taken from the names of modules loaded by the server. These keywords are dependent on both the modules, and the local configuration. Some use keywords that are defined in the default configuration file are:

fail
    Cause the request to be treated as if a database failure had occurred.

noop
    Do nothing. This also serves as an instruction to the configurable failover tracking that nothing was done in the current section.

ok  Instructs the server that the request was processed properly. This keyword can be used to over-ride earlier failures, if the local administrator determines that the failures are not catastrophic.

reject
    Causes the request to be immediately rejected

MODULE RETURN CODES
When a module is called, it returns one of the following codes to "unlang", with the following meaning.
    notfound information was not found
    noop the module did nothing
    ok the module succeeded
    updated the module updated the request
    fail the module failed
    reject the module rejected the request
    disallow the user was locked out
    invalid the configuration was invalid
    handled the module has handled the request itself These return codes can be tested for in a condition, as described above in the CONDITIONS section. See also the file doc/configurable_failover for additional methods of trapping and modifying module return codes.

FILES
/etc/raddb/radiusd.conf

SEE ALSO
radiusd.conf(5), dictionary(5)

AUTHOR
Alan DeKok <aland@deployingradius.com>