Note module return codes
[freeradius.git] / man / man5 / unlang.5
index 39a1297..64ebbba 100644 (file)
@@ -1,4 +1,16 @@
-.TH unlang 5 "12 Jun 2007" "" "FreeRADIUS Processing un-language"
+.\"     # DS - begin display
+.de DS
+.RS
+.nf
+.sp
+..
+.\"     # DE - end display
+.de DE
+.fi
+.RE
+.sp
+..
+.TH unlang 5 "19 May 2010" "" "FreeRADIUS Processing un-language"
 .SH NAME
 unlang \- FreeRADIUS Processing un\-language
 .SH DESCRIPTION
@@ -8,16 +20,45 @@ 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 language is similar to C in some respects, and is also similar to
-Unix shell scripts in other respects.  The keywords for the language
-are "if", "else", "elsif", "switch", "case", and "update".  Subject to some
-limitations below on "switch" and "case", any keyword can appear in
-any context.
+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.
 .SH 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.
+.IP module-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.
+
+.DS
+       chap  # call the CHAP module
+.br
+       sql   # call the SQL module
+.br
+       ...
+.DE
 .IP if
 .br
 Checks for a particular condition.  If true, the block after the
-condition is processed.  Otherwise, the block is ignored.
+condition is processed.  Otherwise, the block is ignored.  See
+CONDITIONS, below, for documentation on the format of the conditions.
 
 .DS
        if (condition) {
@@ -53,8 +94,11 @@ returned false, and if the specified condition evaluates to true.
 .IP switch
 .br
 Evaluate the given string, and choose the first matching "case"
-statement inside of the current block.  No statement other than "case"
-can appear in a "switch" block.
+statement inside of the current block.  If the string is surrounded by
+double quotes, it is expanded as described in the DATA TYPES section,
+below.
+
+No statement other than "case" can appear in a "switch" block.
 
 .DS
        switch "string" {
@@ -65,8 +109,11 @@ can appear in a "switch" block.
 .DE
 .IP case
 .br
-Define a static string to match a parent "switch" statement.  A "case"
-statement cannot appear outside of a "switch" block.
+Define a static string to match a parent "switch" statement.  The
+strings given here are not expanded as is done with the parent
+"switch" statement.
+
+A "case" statement cannot appear outside of a "switch" block.
 
 .DS
        case string {
@@ -75,6 +122,18 @@ statement cannot appear outside of a "switch" block.
 .br
        }
 .DE
+
+A default entry can be defined by omitting the static string.  This
+entry will be used if no other "case" entry matches.  Only one default
+entry can exist in a "switch" section.
+
+.DS
+       case {
+.br
+               ...
+.br
+       }
+.DE
 .IP update
 .br
 Update a particular attribute list, based on the attributes given in
@@ -91,13 +150,110 @@ the current block.
 .DE
 
 The <list> can be one of "request", "reply", "proxy-request",
-"proxy-reply", or "control".  The "control" list is the list of
-attributes maintainted 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.
+"proxy-reply", "coa", "disconnect", or "control".  The "control" list
+is the list of attributes maintainted 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 backwards compatibility with older versions, "check" is accepted
+as a synonym for "control".  The use of "check" is deprecated, and
+will be removed in a future release.
+
+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 only contents permitted in an "update" section are attributes and
+values.  The contents of the "update" section are described in the
+ATTRIBUTES section below.
+.IP 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.
+
+.DS
+       redundant {
+.br
+               sql1    # try this
+.br
+               sql2    # try this only if sql1 fails.
+.br
+               ...
+.br
+       }
+.DE
+.IP 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.
+
+.DS
+       load-balance {
+.br
+               ldap1   # 50% of requests go here
+.br
+               ldap2   # 50% of requests go here
+.br
+       }
+.DE
+
+In general, we recommend using "redundant-load-balance" instead of
+"load-balance".
+.IP 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.
 
-For a detailed description of the contents of the "update" section,
-see the ATTRIBUTES section below.
+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.
+
+.DS
+       redundant-load-balance {
+.br
+               ldap1   # 50%, unless ldap2 is down, then 100%
+.br
+               ldap2   # 50%, unless ldap1 is down, then 100%
+.br
+       }
+.DE
 .SH CONDITIONS
 The conditions are similar to C conditions in syntax, though
 quoted strings are supported, as with the Unix shell.
@@ -108,16 +264,32 @@ conditions
        (foo)
 .DE
 
-Evalutes to true if 'foo' is a non-empty string, or if 'foo' is a
-non-zero number.
+Evalutes 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 comparings 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.
 .IP Negation
 .DS
        (!foo)
 .DE
 
 Evalutes to true if 'foo' evaluates to false, and vice-versa.
-.IP Short
-circuit operators
+.PP
+Short-circuit operators
+.RS
 .br
 .DS
        (foo || bar)
@@ -130,6 +302,7 @@ 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.
+.RE
 .IP Comparisons
 .DS
        (foo == bar)
@@ -139,29 +312,76 @@ 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 "=".
-.SH STRINGS AND NUMBERS
-Strings and numbers can appear as stand-alone conditions, 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.
-.IP Numbers
+.PP
+Conditions may be nested to any depth, subject only to line length
+limitations (8192 bytes).
+.SH 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.
+.IP 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.
 .PP
-"strings"
+word
+.RS
+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.
+
+.DS
+       if (User-Name == "bob") {
+.br
+               ...
+.br
+       if (Framed-IP-Address > 127.0.0.1) {
+.br
+               ...
+.br
+       if (Service-Type == Login-User) { 
+.DE
+.RE
+.IP """strings"""
 .RS
 Double-quoted strings are expanded by inserting the value of any
 variables (see VARIABLES, below) before being evaluated.  If
-the result is a number it can be evaluated in a numerical context.
+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\\" !")
 .RE
 .IP 'strings'
-Single-quoted strings are evaluated as-is.
+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.
 .IP `strings`
-Back-quoted strings are evaluated by executing the 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.
+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 variable 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.
 .IP /regex/i
 These strings are valid only on the right-hand side of a comparison,
 and then only when the comparison operator is "=~" or "!~".  They are
@@ -180,17 +400,39 @@ Run-time variables are referenced using the following syntax
 .DS
        %{Variable-Name}
 .DE
+
+Note that unlike C, there is no way to declare variables, or to refer
+to them outside of a string context.  All references to variables MUST
+be contained inside of a double-quoted or back-quoted string.
+
+Many potential variables 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 variable.  When the server
+receives a packet, it uses the packet contents to look up entries in
+the dictionary, and instantiates variables with a name taken from the
+dictionaries, and a value taken from the packet contents.  This
+process means that if a variable does not exist, it is usually because
+it was not mentioned in a packet that the server received.
+
+Once the variable is instantiated, it is added to an appropriate
+attribute list, as described below.  In many cases, attributes and
+variables are inter-changeble, and are often talked about that way.
+However, variables can also refer to run-time calls to modules, which
+may perform operations like SQL SELECTs, and which may return the
+result as the value of the variable.
 .PP
 Referencing attribute lists
 .RS
 Attribute lists may be referenced via the following syntax
+
 .DS
        %{<list>:Attribute-Name}
 .DE
 
-Where <list> is one of "request", "reply", "proxy-request",
-"proxy-reply", or "control", as described above in the documentation
-for the "update" section.  The "<list>:" prefix is optional, and if
+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.
 
 When a variable is encountered, the given list is examined for an
@@ -203,6 +445,8 @@ string is replaced with the value of that attribute.  Some examples are:
        %{request:User-Name} # same as above
 .br
        %{reply:User-Name}
+.br
+       %{outer.reqest:User-Name} # from inside of a TTLS/PEAP tunnel
 .DE
 .RE
 .PP
@@ -216,36 +460,57 @@ more than 8 parantheses, the additional results will not be placed
 into any variables.
 .RE
 .PP
+Obtaining results from databases
+.RS
+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 variable reference with the
+resulting string returned from the module.
+
+.DS
+       %{module: string ...}
+.DE
+
+The syntax of the string is module-specific.  Please read the module
+documentation for additional details.
+.RE
+.PP
 Conditional Syntax
 .RS
 Conditional syntax similar to that used in Unix shells may also be
 used.
-.IP %{Foo:-bar}
-When attribute Foo is set, returns value of Foo
-When attribute Foo is unset, returns literal string 'bar'
-
-.IP %{Foo:-%{Bar}}
-When attribute Foo is set, returns value of attribute Foo
-When attribute Foo is unset, returns value of attribute Bar (if any)
-
-.IP %{Foo:-%{Bar:-baz}}
-When attribute Foo is set, returns value of attribute Foo
-When attribute Foo is unset, returns value of attribute Bar (if any)
-When attribute Bar is unset, returns literal string 'baz'
+.IP %{%{Foo}:-bar}
+If %{Foo} has a value, returns that value.
+.br
+Otherwise, returns literal string "bar".
+.IP %{%{Foo}:-%{Bar}}
+If %{Foo} has a value, returns that value.
+.br
+Otherwise, returns the expansion of %{Bar}.
+
+These conditional expansions can be nested to almost any depth, such
+as with %{%{One}:-%{%{Two}:-%{Three}}}
 .RE
 .PP
 String lengths and arrays
 .RS
 Similar to a Unix shell, there are ways to reference string lenths,
-and the second or more instance of an attribute in a list.
-Realistically, if you need this functionality, we recommend using a
-real language.
+and the second or more instance of an attribute in a list.  If you
+need this functionality, we recommend using a real language.
 .IP %{#string}
 The number of characters in %{string}.  If %{string} is not
-set, then the length is not set.  This will NOT work for the
-one-character variables defined below.
+set, then the length is not set.
 
 e.g. %{#Junk-junk:-foo} will yeild the string "foo".
+.IP %{Attribute-Name#}
+Will print the integer value of the attribute, rather than a decoded
+VALUE or date.  This feature applies only to attributes of type
+"date", "integer", "byte", and "short".  It has no effect on any other
+attributes.  It is used when the numerical value is needed (e.g. Unix
+seconds), rather than a humanly-readable string.
+
+e.g. If a request contains "Service-Type = Login-User", the expansion
+of %{Service-Type#} will yeild "1".
 .IP %{Attribute-Name[index]}
 Reference the N'th occurance of the given attribute.  The syntax
 %{<list>:Attribute-Name[index]} may also be used.  The indexes start
@@ -267,12 +532,142 @@ member separated by a newline.
 .IP %{#Attribute-Name[index]}
 Expands to the length of the string %{Attribute-Name[index]}.
 .SH ATTRIBUTES
-TBD
+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 VARIABLES
+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.
+
+.DS
+       Attribute-Name = value
+.DE
+.PP
+Attribute names
+.RS
+The Attribute-Name must be a name previously defined in a dictionary.
+If an undefined name is used, the server will return an error, and
+will not start.
+.RE
+.IP Operators
+The operator used to assign the value of the attribute may be one of
+the following, with the given meaning.
+.RS
+.IP =
+Add the attribute to the list, if and only if an attribute of the same
+name is not already present in that list.
+.IP := 
+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.
+.IP +=
+Add the attribute to the tail of the list, even if attributes of the
+same name are already present in the list.
+.RE
+.PP
+Enforcement and Filtering Operators
+.RS
+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.
+.IP -=
+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.
+.IP ==
+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!
+.IP <=
+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
+"+=".
+
+This operator is valid only for attributes of integer type.
+.IP >=
+Keep all attributes having values greater 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
+"+=".
+
+This operator is valid only for attributes of integer type.
+.IP !*
+Delete all occurances of the named attribute, no matter what the
+value.
+.RE
+.IP Values
+.br
+The format of the value is attribute-specific, and is usually a
+string, integer, IP address, etc.  Prior to the attribute being
+instantiated, the value may be expanded as described above in the DATA
+TYPES section, above.  This flexibility means that, for example, you
+can assign an IP address value to an attribute by specifying the IP
+address 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 a variable, 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.
+.SH 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:
+.IP fail
+Cause the request to be treated as if a database failure had occurred.
+.IP noop
+Do nothing.  This also serves as an instruction to the configurable
+failover tracking that nothing was done in the current section.
+.IP 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 faiures are not catastrophic.
+.IP reject
+Causes the request to be immediately rejected
+.SH MODULE RETURN CODES
+When a module is called, it returns one of the following codes to
+"unlang", with the following meaning.
+
+.DS
+       notfound        information was not found
+.br
+       noop            the module did nothing
+.br
+       ok              the module succeeded
+.br
+       updated         the module updated the request
+.br
+       fail            the module failed
+.br
+       reject          the module rejected the request
+.br
+       userlock        the user was locked out
+.br
+       invalid         the configuration was invalid
+.br
+       handled         the module has handled the request itself
+.DE
+
+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.
 .SH FILES
-/etc/raddb/vmpsd.conf,
 /etc/raddb/radiusd.conf
 .SH "SEE ALSO"
 .BR radiusd.conf (5),
-.BR vmps.conf (5)
+.BR dictionary (5)
 .SH AUTHOR
 Alan DeKok <aland@deployingradius.com>