Provided by: freeradius-common_3.2.5+dfsg-3~ubuntu24.04.3_all bug

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 "authorize", "authenticate", "post-auth", "preacct",
       "accounting", "pre-proxy", "post-proxy", and "session".

       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 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.

       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
                   ...

       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) {
                        ...
                   }

       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.  Unlike other languages, "break" here  means  "exit  the  loop  at  the  next
              iteration",  not "exit the loop now".  The result is that any statements after the "break" keyword
              will still be executed.  We recommend using "break" only when  it  is  the  last  statement  in  a
              "foreach" block.

              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 {
                        ...
                   }

       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 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 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
              Update a particular attribute list, based on the attributes given in the current block.

                   update <list> {
                        &Attribute-Reference = value
                        ...
                   }  The  <list>  can  be  one  of  "request",  "reply", "proxy-request", "proxy-reply", "coa",
              "disconnect", "session-state", or "control".  As of Version 3, the <list> can be omitted, in which
              case "request" is assumed.

              The "control" list is the list of attributes maintained internally by the server that controls how
              the server processes the request.  Any attribute that does not go in a packet on the network  will
              generally be placed in the "control" list.

              For  EAP  methods with tunneled authentication sessions (i.e. PEAP and EAP-TTLS), the inner tunnel
              session can also reference "outer.request", "outer.reply", and "outer.control".  Those  references
              allow you to address the relevant list in the outer tunnel session.

              The "coa" and "disconnect" sections can only be used when the server receives an Access-Request or
              Accounting-Request.   Use  "request"  and "reply" instead of "coa" when the server receives a CoA-
              Request or Disconnect-Request packet.

              Adding one or more attributes to either of  the  "coa"  or  "disconnect"  list  causes  server  to
              originate  a  CoA-Request  or  Disconnect-Request  packet.   That  packet is sent when the current
              Access-Request or Accounting-Request has been  finished,  and  a  reply  sent  to  the  NAS.   See
              raddb/sites-available/originate-coa for additional information.

              The  "session-state" list is primarily used for EAP.  Attributes put into the "session-state" list
              are saved for the next packet in the session.  They are  automatically  retrieved  when  the  next
              packet is received.

              The only contents permitted in an "update" section are attributes and values.  The contents of the
              "update" section are described in the ATTRIBUTE REFERENCE and ATTRIBUTE ASSIGNMENT sections below.

       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 update an attribute list.

                   redundant {
                        sql1 # try this
                        sql2 # try this only if sql1 fails.
                        ...
                   }

       load-balance
              This section contains a simple list of modules.  When the section is entered, one module is chosen
              at random 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 will 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 update an attribute list.

                   load-balance {
                        ldap1     # 50% of requests go here
                        ldap2     # 50% of requests go here
                   } In general, we recommend using "redundant-load-balance" instead of "load-balance".

       redundant-load-balance
              This section contains a simple list of modules.  When the section is entered, one module is chosen
              at random 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  will  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 update an attribute list. Please see raddb/radiusd.conf
              "instantiate" section for more configuration examples.

                   redundant-load-balance {
                        ldap1     # 50%, unless ldap2 is down, then 100%
                        ldap2     # 50%, unless ldap1 is down, then 100%
                   }

       return
              Returns from the current top-level section, e.g. "authorize" or "authenticate".  This  keyword  is
              mainly used to avoid layers of nested "if" and "else" statements.

                   authorize {
                        if (...) {
                             ...
                             return
                        }
                        ...  # this is never reached when the "if"
                        ...  # statement is executed
                   }

ATTRIBUTE REFERENCES

       Attributes  may  be  referenced  via  the following syntax:      &Attribute-Name      &Attribute-Name:TAG
            &Attribute-Name[NUM]      &<list>:Attribute-Name      &<list>:Attribute-Name:TAG[NUM]  Where  <list>
       is   one   of   "request",   "reply",  "control",  "proxy-request",  "proxy-reply",  or  "outer.request",
       "outer.reply", "outer.control", "outer.proxy-request", or "outer.proxy-reply". just as with the  "update"
       section,  above.   The "<list>:" prefix is optional, and if omitted, is assumed to refer to the "request"
       list.

       The TAG portion is a decimal integer between 1 and 31.  Please see RFC 2868 for  more  information  about
       tags.  Tags can only be used for attributes which are marked in the dictionary as "has_tag".

       The  NUM  portion is used when there are multiple attributes of the same name in a list.  The "Attribute-
       Name" reference will return the first attribute.  Using an array offset allows the policy to refer to the
       second and subsequent attributes.

       If '*' is used in the NUM portion, it evaluates to all instances of the attribute in the request.

       If 'n' is used in the NUM portion, it evaluates to the last instance of the attribute in the request.

       When an attribute name is encountered, the given list is examined for an attribute  of  the  given  name.
       Some examples are:      User-Name
            request:User-Name # same as above
            reply:User-Name
            Tunnel-Password:1
            Cisco-AVPAir[2]
            outer.request:User-Name  #  from inside of a TTLS/PEAP tunnel Note that unlike C, there is no way to
       define new attributes at run-time.  They MUST be declared in a  dictionary  file,  and  loaded  when  the
       server starts.

       All  attributes are defined in the dictionaries that accompany the server.  These definitions define only
       the name and type, and do not define the value of the attribute.  When the server receives a  packet,  it
       uses  the  packet  contents to look up entries in the dictionary, and instantiates attributes with a name
       taken from the dictionaries, and a value taken from the packet contents.  This process means that  if  an
       attribute  does  not  exist,  it  is  usually  because  it  was not contained in a packet that the server
       received.

       Once the attribute is instantiated, it is added to a list.  It can then be referenced, updated, replaced,
       etc.

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.  The operators ":=", "^=" and "=" are assignment operators, and  are  not  allowed
              for comparisons.

              The  operators  "<",  "<=",  ">",  and  ">="  are  also allowed for checking that an IP address is
              contained within a network.  For  example:       if  (<ipaddr>192.0.2.1  <  192.0.2.0/24)  {  This
              comparison succeeds, because the address 192.0.2.1 is contained within the network 192.0.2.0/24.

       Attribute Comparisons
              When  doing  attribute  comparisons,  the data type of the attribute is used to determine the data
              type of the right-hand side argument.       (&User-Name == "foo") Compares the value of the  User-
              Name attribute to the string 'foo', and evaluates to true if the comparison holds true.

              Similarly,       (&Framed-IP-Address  ==  192.0.2.1)  Compares  the value of the Framed-IP-Address
              attribute to the IP address 192.0.2.1.  This IP address does not need to be quoted.

       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 ATTRIBUTE
              REFERENCES, 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/im
              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.  This is usually Posix regular expressions.

              The  trailing 'i' is optional, and indicates that the regular expression match should be done in a
              case-insensitive fashion.

              The trailing 'm' is also optional, and indicates that carrot '^' and  dollar  '$'  anchors  should
              match on new lines as well as at the start and end of the subject string.

              If  the  comparison  operator  is  "=~",  then  parentheses  in the regular expression will define
              variables containing the matching text, as described below in the ATTRIBUTE REFERENCES 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, 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.

       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.

              %{strlen:string}
                     The  number  of  characters  in "string".  If "string" does not exist, then the length also
                     does not exist, instead of being zero.

                     The "string" is expanded before the length is taken.

              %{integer:Attribute-Name}
                     The integer value of the Attribute-Name, instead of the enumerated name.

                     e.g. If a request contains "Service-Type = Login-User", the expansion of %{integer:Service-
                     Type} will yield "1".

              %{hex:Attribute-Name}
                     The hex value of the Attribute-Name, as a series of hex digits.

                     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"

ATTRIBUTE ASSIGNMENTS

       The attribute lists described above may be edited by listing  one  or  more  attributes  in  an  "update"
       section.   Once  the  attributes  have  been  defined,  they  may be referenced as described above in the
       ATTRIBUTE REFERENCES section.

       The following syntax defines attributes in an "update" section.  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

       Attribute Reference
              The  Attribute-Reference  must  be  a  reference (see above), using a name previously defined in a
              dictionary.  If an undefined name is used, the server will return an error, and will not start.

       Operators
              The operator used to assign the value of the attribute may be one of the following, with the given
              meaning.

              =      Add the attribute to the list, if and only if an attribute of the same name is not  already
                     present in that list.

              :=     Add  the  attribute  to  the list.  If any attribute of the same name is already present in
                     that list, its value is replaced with the value of the current attribute.

              +=     Add the attribute to the tail of the list, even if attributes of the same name are  already
                     present  in  the  list.  When  the  right  hand side of the expression resolves to multiple
                     values, it means add all values to the tail of the list.

              ^=     Add the attribute to the head of the list, even if attributes of the same name are  already
                     present  in  the  list.   When  the  right hand side of the expression resolves to multiple
                     values, it means prepend all values to the head of the list.

       Enforcement and Filtering Operators
              The following operators may also be used in addition to the ones listed above.  Their function  is
              to perform enforcement or filtering on attributes in a list.

              -=     Remove  all  matching  attributes from the list.  Both the attribute name and value have to
                     match in order for the attribute to be removed from the list.

              ==     Keep all matching attributes.  Both the attribute name and value have to match in order for
                     the attribute to remain in the list.

                     Note that this operator is very different than the '=' operator listed above!

              !=     Keep all attributes with matching name, and value not equal to the given one.

              <      Keep all attributes having values less than the value given  here.   Any  larger  value  is
                     replaced by the value given here.  If no attribute exists, it is added with the value given
                     here, as with "+=".

              <=     Keep all attributes having values less than, or equal to, the value given here.  Any larger
                     value  is  replaced  by the value given here.  If no attribute exists, it is added with the
                     value given here, as with "+=".

              >      Keep all attributes having values greater than the value given here.  Any smaller value  is
                     replaced by the value given here.  If no attribute exists, it is added with the value given
                     here, as with "+=".

              >=     Keep  all  attributes  having  values greater than, or equal to, the value given here.  Any
                     smaller value is replaced by the value given here.  If no attribute  exists,  it  is  added
                     with the value given here, as with "+=".

              !*     Delete all occurrences of the named attribute, no matter what the value.

              =~     Keep  all  attributes  having  values  which  match  the  given  regular expression.  If no
                     attribute matches, nothing else is done.

              !~     Keep all attributes having values which fail to match the given regular expression.  If  no
                     attribute matches, nothing else is done.

       Values
              The value can be an attribute reference, or an attribute-specific string.

              When the value is an attribute reference, it must take the form of "&Attribute-Name".  The leading
              "&"  signifies  that the value is a reference.  The "Attribute-Name" is an attribute name, such as
              "User-Name" or "request:User-Name".  When an attribute reference is  used,  both  attributes  must
              have the same data type.  For example, "User-Name := &NAS-Port" is invalid, because "User-Name" is
              a string, and "NAS-Port" is an integer.

              We  recommend  using  the form "Attribute-1 = &Attribute-2" for updates, instead of "Attribute-1 =
              "%{Attribute-2}".  The first version will copy the attribute data, no matter what its  form.   The
              second  version  will print the Attribute-2 to a string, and then parse it to create the value for
              Attribute-1.  This second version is slower and more fragile than the first one.

              When the value is an attribute-specific string, it can be a string, integer, IP address, etc.  The
              value may be expanded as  described  above  in  the  DATA  TYPES  section,  above.   For  example,
              specifying  "Framed-IP-Address = 127.0.0.1" will cause the "Framed-IP-Address" attribute to be set
              to the IP address "127.0.0.1".  However, using "Framed-IP-Address :=  module  to  be  run  with  a
              string  "127.0.0.1".   The  output  of the "echo" module will then be parsed as an IP address, and
              placed into the Framed-IP-Address attribute.

              This flexibility means that you can assign an IP address by specifying it directly, or  by  having
              the  address  returned from a database query, or by having the address returned as the output of a
              program that is executed.

              When string values are finally assigned to an attribute, they can have a  maximum  length  of  253
              characters.   This  limit  is due in part to both protocol and internal server requirements.  That
              is, the strings in the language can be nearly 8k in length, say for a long  SQL  query.   However,
              the output of that SQL query should be no more than 253 characters in length.

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
            userlock        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/freeradius/3.0/radiusd.conf

SEE ALSO

       radiusd.conf(5), dictionary(5)

AUTHOR

       Alan DeKok <aland@deployingradius.com>

                                                16 February 2021                                       unlang(5)