dacs.exprs

DACS.EXPRS(5)                 DACS Formats Manual                DACS.EXPRS(5)



NAME
       dacs.exprs - DACS expression language

DESCRIPTION
       These files are part of the DACS suite.

       DPL (the DACS programming language) is used in access control rules,
       its revocation list, and in configuration files. This programmability
       gives DACS maximum run-time configurability and flexibility. A DPL
       expression - or even a small program - may appear within predicate,
       allow, and deny elements of an access control rule, for example.  DPL
       is also accessible using the dacsexpr(1)[1] command, which can be used
       for writing scripts even for non-DACS applications.

       DPL, which is gradually evolving in mostly backward-compatible ways, is
       similar in many ways to Perl[2], PHP[3], Tcl[4] and its expressions
       look and behave much like C/C++ expressions. The calling signatures for
       functions are reminiscent of those of Tcl, with literal or string
       arguments used to select a particular mode of operation or specify
       options. The syntaxes used for strings and variables have been
       influenced by various Unix shells. Our intent is for the language to
       feel familiar and be easy to use for the typical tasks at hand. We have
       tried not to be gratuitously different.

           Note
           The philosophy guiding the design of the DACS expression language
           is that its power should be limited to basic operations on
           elementary data types that can be expressed simply and evaluated
           efficiently, along with a collection of utility and higher-level
           functions, targeted for the tasks at hand, that hide complexity.
           This is why the language does not include much in the way of
           control flow statements - our feeling is that complicated
           expressions are more likely to introduce mistakes, which can easily
           result in access control rules not working as intended.

           While fleshing out the language is not a priority, expression
           syntax and the set of functions are being extended as necessary. An
           extensibility mechanism is planned that would let user-defined
           functions be loaded at run-time.

           While there are no immediate plans to do so, replacing the DACS
           expression language with a general-purpose extension language may
           eventually make sense.  Tcl and Perl would be leading contenders.

           Tip
           The dacsexpr(1)[1] utility can be useful for learning, testing, and
           debugging DPL.

   Expression Syntax
       Expression evaluation consists of a lexical analysis stage, in which
       the expression is broken into a sequence of tokens, followed by
       evaluation of the tokens.

       Expression syntax is checked before an expression is evaluated. Any
       syntactic or run-time evaluation error immediately terminates
       evaluation of the top-level expression and returns a False result.

           Note
           Because files containing expressions are local to the DACS site on
           which they appear (i.e., DACS does not copy them), they need not be
           portable across sites. This means that any DACS jurisdiction is
           free to customize or extend these expressions at will since they do
           not have to be understood or executed by any other jurisdiction.

       Comments
           Three comment styles are recognized:

           •   The /* ... */ C style comment syntax, which does not nest;

           •   The // syntax of C++, where the remainder of the line following
               the token is ignored; and

           •   The # syntax of shells and many scripting languages, provided
               the # is either at the beginning of a line or appears after
               whitespace, where the remainder of the line following the token
               is ignored. Note that escaping the # by preceding it with a
               backslash prevents the text that follows from being interpreted
               as a comment. For example, this will result in a syntax error
               if the backslash is omitted:

                   > ${foo:? \#xxx}
                   " #xxx"


           Here are examples of all three styles:

               /*
                * This is a comment
                */

               // This is another comment

               ${x} = 17;  # And one last comment

           Additionally, when expressions are parsed in the context of an XML
           document (such as in an access control rule), the XML comment
           syntax can be used (<!-- A comment -->). Such comments can span
           multiple lines.

               <!--
               Comment out this clause for now...
               <Auth id="authx">
               STYLE "expr"
               CONTROL "sufficient"
               </Auth>
               -->


   Basic Data Types
       The following basic data types are supported:

       integer
       int
           , Integers are represented internally as a C/C++ long int. Maximum
           and minimum values are platform dependent. Integers are written in
           the C-style syntax; for example, -1958, 0377 (octal), and 0xABC
           (hexadecimal, upper or lower case).

       real
       double
           , Reals are represented internally as a C/C++ double. Maximum and
           minimum values are platform dependent. A real constant is an
           optional sequence of decimal digits (possibly signed) followed by a
           period and 1) at least one digit or 2) an 'e' or 'E' followed by at
           least one digit.

       string
           A string is a sequence of characters enclosed between matching
           single or double quotes (e.g., 'Hello world'). Interpolation of
           variables occurs within double quotes but not single quotes.
           C-style character escape codes and octal numeric escape codes are
           understood (e.g., "\t", "\010") and either quote character (e.g.,
           'It\'s here') and the backslash character (e.g., "\\") can be
           quoted. An unrecognized quoted character is mapped to that
           character (e.g., "\x" is "x"). Character strings are limited in
           length by available memory and are represented internally as a
           null-terminated vector.

               Note
               •   Because a string is null-terminated, it cannot contain a
                   NUL character. Also, functions that deal with strings
                   usually do not expect (most) ASCII control characters to
                   appear in a string. Therefore a string that contains an
                   unprintable character (a character that is not a tab,
                   newline, carriage return, and that does not satisfy
                   isprint(3)[5]) automatically becomes a bstring (see below).

               •   Because DACS configuration files are XML documents,
                   characters special to XML must be properly escaped within
                   them. In particular, an ampersand character must always be
                   written as &amp; and a < character must be written as &lt;.
                   For example, the query string a=1&b=2 might be used as

                       ${Foo::QUERY_STRING} = "a=1&amp;b=2"

           Variable references may occur within a (double-quoted) string; the
           value of the variable reference is interpolated at that point. If
           ${Foo::bar} is "hello", then the value of "${Foo::bar}, world" is
           "hello, world".


               Note
               The first expression is invalid and must be written as the
               second:

                   foo"baz"
                   foo."baz"

       binary
       bstring
           , A binary string is a sequence of bytes, limited in length by
           available memory. Most language operators cannot be applied to data
           of this type without converting it to another type (e.g., two
           bstring values cannot be added using the + operator). A binary
           string is not necessarily portable across systems.

               > "\0\1\2"
               "000102"


       bareword
           This type is a "literal word" much like Perl's barewords. A
           bareword consists of an initial alphabetic character, followed by
           any number of alphanumerics and underscores. The resulting lexical
           token must have no other interpretation in the language and is
           treated as if it were a quoted string. This syntactic convenience
           makes these two function calls equivalent:

               file(test, "-e", foo)
               file("test", "-e", "foo")

           These two expressions are equivalent and yield "foobaz":

               foo."baz"
               foo.baz


       bool
           The boolean values True and False are either the result of
           evaluating certain expressions or are implicit argument values.
           This is really a pseudo-type because it is represented internally
           as an integer. In the former case, the integer 1 is the canonical
           "true" value and 0 is considered "false". In the latter case, there
           are several possibilities. If the argument is an integer or real,
           any non-zero value is considered True and 0 is considered False.
           For the string data type, both the empty string (i.e., "") and the
           string "0" are considered False and anything else is considered
           True. A binary string is equivalent to False if and only if its
           length is zero. An empty list of either variety ("[]" or "{}") is
           False, while any non-empty list or alist is True.

       Automatic type conversion is performed when necessary and possible. In
       general, a "lower" type is promoted to a "higher" type (e.g., an
       integer is converted to a real when it is added to a real) and the
       result is of the higher type. Arguments to function calls are
       automatically coerced to the required types. A printable binary string
       (one not containing any "troublesome" control characters) can be
       converted into a string without loss; other binary strings are
       converted into a hexadecimal string representation for assignment or
       display.

       The C/C++ unary cast operation is available for explicit type
       conversion. Not all conversions are supported (e.g., integer to binary
       and binary to string). These type names are case sensitive.

       The language includes the concept of the void type, which cannot be
       stored in a variable, used as an operand, or printed. Some functions
       are void, print()[6] for example. A value can be cast[7] to void.

           Note
           Support for binary data is only partially implemented.

   Variables and Namespaces
       Every variable exists within a namespace. Namespaces exist so that the
       same variable name can exist safely and without ambiguity in different
       contexts. They also serve to group together and name a set of closely
       related variables, and they make it easy for all variables in the set
       to be assigned a characteristic (such as being read-only). For example,
       CGI parameter values are automatically put in the Args namespace and
       variables automatically created by DACS are put in the DACS namespace.
       Namespaces address the problem of a parameter name that happens to have
       the same name as a variable created by DACS, for example. They also
       allow intermediate results to be stored in their own namespace, also
       avoiding the problem of clashing variable names.

       Variables are not declared in advance. The value of an uninitialized
       variable is the empty string, which is invalid in a numerical context,
       but variables should always be initialized before being used. Some
       variables are created automatically by DACS from the execution context
       (e.g., the value of a CGI parameter value, the identity of the client,
       an environment variable), as a side-effect of function evaluation, or
       by an assignment operator.

       The interpreter tries to maintain the natural type of a variable when
       possible, to avoid conversions to and from the string type.

       Variable Syntax
           A variable reference may have either of the following syntaxes:

               ${[namespace::]variable-name[:flags]}
               $[namespace::]variable-name

           For instance, the following refers to the value of a variable
           called JURISDICTION_NAME within the namespace called Conf:

               ${Conf::JURISDICTION_NAME}

           A variable called JURISDICTION_NAME within a different namespace
           could exist and would be completely distinct.

           A namespace must begin with an alphabetic character and can be
           followed by any number of alphabetics, digits, dashes, and
           underscores. By convention, predefined namespaces begin with an
           upper case letter.

           If the namespace is omitted from a variable reference, a default
           namespace is implied (see below).

           A variable name consists of any number of alphanumeric characters
           (upper and lower case), and characters from this set:

               -_.!~*'()

           Additionally, a "%" character that is followed by two hexadecimal
           characters (upper and lower case) is acceptable.

           If instead of a variable name the character "#" appears, the number
           of variables in the namespace is returned. If the namespace does
           not exist, 0 is returned. For example, the value of this variable
           reference is the number of variables in the Conf namespace:

               ${Conf::#}

           When the syntax with braces is used, a variable name may be
           followed by a colon and then one or more modifier flags that affect
           the processing of the variable. Referencing an invalid variable
           name or unknown namespace, or using an undefined modifier flag[8]
           is an error. Referencing an undefined variable yields the empty
           string.

           Variable names are case sensitive by default; namespaces are always
           case sensitive.

           User-defined variables and namespaces are not persistent. They
           disappear when their execution context terminates.

               Tip
               A variable reference may not contain any whitespace except when
               it appears after a ?  or +modifier flag[8].

               Tip
               Because many variable references do not include flags or use
               punctuation characters in the variable name, as a convenience
               the braces that surround a variable reference may be omitted in
               certain cases. This is only possible if the variable name
               begins with an alphabetic or an underscore, which can be
               followed by alphanumerics and underscores. A namespace may be
               specified, but flags are not permitted, although the special
               "#" construct is also allowed. The variable name ends with the
               first invalid character. For example, these pairs of variable
               references are equivalent:

                   ${myvar}
                   $myvar

                   ${foo::baz}
                   $foo::baz

               Note that the variable reference ${foo-17} has a valid but
               different interpretation if the braces are omitted.

       Variable Modifier Flags
           A variable reference may include one or more modifier flags that
           control how the reference is to be interpreted.

           The following modifier flags are recognized:

           e
               Exists: The "e" modifier flag is used to test whether the
               variable exists (has been defined). Instead of returning the
               value of the variable or causing an error, the value of the
               variable reference is the string "1" if the variable is
               defined, the empty string otherwise (equivalent to False).

           i
               Insensitive: When looking up the name of a variable, the
               default is to use a case-sensitive comparison for the variable
               name. To use a case-insensitive comparison instead, an "i" flag
               is used (e.g., ${FOO::i}). The namespace lookup is always case
               sensitive.

           n
               Non-empty: The "n" modifier flag tests whether the variable
               exists (has been defined) and is not the empty string (i.e.,
               has zero length). Instead of returning the value of the
               variable or causing an error, the value of the variable
               reference is the string "1" if the variable is defined and is
               not the empty string, otherwise it is the empty string
               (equivalent to False).

           z
               Zero: The opposite of the "n" flag, instead of returning the
               value of the variable or causing an error, the value of the
               variable reference is the string "1" if the variable is
               undefined or the empty string, otherwise it is the empty string
               (equivalent to False).

           ?
               Default: The "?" modifier flag must appear last if it is used.
               The flag is immediately followed by zero or more characters.
               Its purpose is to associate a default value with the variable
               reference. If the variable is defined and is not empty, then
               the result of the variable reference is the value of the
               variable; otherwise, the result is the evaluation of the
               characters that follow the "?" flag. If no character follows
               the "?" flag, the empty string is indicated. The default may
               itself contain variable references, embedded spaces, etc., and
               is evaluated left to right. Any "}" characters appearing in the
               string before the last closing brace must be escaped by being
               preceded by a backslash.

           +
               Substitute: The "+" modifier flag must appear last if it is
               used. The flag is immediately followed by zero or more
               characters. Its purpose is to associate a substitute value with
               a variable reference. If the variable is defined and is not the
               empty string, then the result of the variable reference is the
               evaluation of the characters that follow the "+" flag; if the
               variable is undefined or is the empty string, the value of the
               variable reference is the empty string. If no character follows
               the "+" flag, the empty string is indicated. The substitute may
               itself contain variable references, embedded spaces, etc., and
               is evaluated left to right. Any "}" characters appearing in the
               string before the last closing brace must be escaped by being
               preceded by a backslash.
           The i can be combined with any other flag, but it must appear
           first. All other flags are mutually exclusive. Repetitions of a
           flag are ignored. An unrecognized flag raises an error condition.

           Consider these examples:

               ${Args::SCALE:?17}
               ${Foo::bar:i?${Bar::baz\}baz}
               "${DACS::QUERY:+?}${DACS::QUERY:?}"

           In the first example, if ${Args::SCALE} is undefined or empty, the
           value of the variable reference is "17" instead of the value of
           ${Args::SCALE}. In the second example, if ${Foo::bar} (case
           insensitive) is defined, the result is its value, otherwise the
           result is the value of the string "${Bar::baz}baz". In the third
           example, if ${DACS::QUERY} is defined and not empty, the value of
           the expression will be a question mark followed by the value of
           ${DACS::QUERY}. If ${DACS::QUERY} is undefined or empty, the value
           will be the empty string.

       Reserved Namespaces
           The following namespaces are predefined by DACS and reserved for
           particular uses. Some are read-only, which means that only DACS can
           create a variable or change the value of a variable in the
           namespace, except in certain contexts.

           Args
               Instantiated from query string arguments and the POST data
               stream (if the content type is
               application/x-www-form-urlencoded or multipart/form-data). This
               namespace is read-only.

           Argv
               Instantiated by dacsexpr from the command line flags passed to
               the script. The value of ${Argv::0} is the name of the file
               being processed, with - signifying the standard input. The next
               argument, if any, will be ${Argv::1}, and so on. This namespace
               is read-only.

           Auth
               Used by dacs_authenticate(8)[9] during authentication
               processing.

           Conf
               Instantiated with configuration directive variables, this
               namespace is made read-only after configuration processing. See
               dacs.conf(5)[10].

           Cookies
               This namespace is instantiated with HTTP cookies that were
               submitted with a request. For security reasons, those
               associated with DACS credentials are excluded. This is a
               read-only namespace. If a cookie named foo is sent by a user
               agent, an access control rule can access the cookie value as
               ${Cookies::foo}.

           DACS
               Instantiated with DACS-specific variables. It is read-only. See
               dacs_acs(8)[11].

           Env
               For web services, instantiated with the standard Apache
               environment variables; for other programs, instantiated from
               the execution environment (environ(7)[12]). It is read-only.

           ExecEnv
               Used by exec()[13].

           LDAP
               Used by local_ldap_authenticate.

           Temp
               Unless disabled or redefined at build-time, variable references
               that do not include a namespace are associated with this
               namespace as a convenience. The following three expressions are
               therefore equivalent:

                   ${foo} = 17
                   ${Temp::foo} = 17
                   $foo = 17

               In a future release, this mechanism may be generalized to
               provide a run-time means of selecting the default namespace.

   Lists, Alists, and Arrays
       DPL supports more complicated data structures based on lists and
       associative lists. These types may also be combined and composed so
       that programmers can create lists of lists, and so on.

       Lists
           A list is composed of zero or more basic data types or sub-lists. A
           list is created using the following syntax:

               LIST     -> "[" "]" | "[" LIST-ELS "]"
               LIST-ELS -> EL | EL "," LIST-ELS
               EL       -> BASIC-DATA-TYPE | LIST

           A list can also be created through the list()[14] function.

           Here is a list consisting of four elements:

               [1, "one", 1.000, ["one sublist"]]

           The length()[15] function returns the number of elements in a list.

           A list can be assigned to a variable:

               $mylist = [1, 2, 3, 4, 5, 6]
               $mylist_copy = $mylist


               Note
               These two statements are equivalent:

                   $mylist = ["one", "two"]
                   ${mylist} = ["one", "two"]

               And so are these two:

                   $mylist[0]
                   ${mylist}[0]

               Modifier flags therefore do not apply to list elements, only
               the list variable.

           A list or element can be appended to another list using the "."
           ("dot") concatenation operator. List elements can be rotated using
           the ">>" ("shift left") or "<<" ("shift right") operators. The
           compound assignment operator versions of these operators may also
           be used.

               > $mylist=[orange, apple, grape]
               [orange,apple,grape]
               > $mylist . banana
               [orange,apple,grape,banana]
               > $mylist .= [prune,plum]
               [orange,apple,grape,prune,plum]
               > $mylist .= [[lime]]
               [orange,apple,grape,prune,plum,[lime]]
               >$mylist << 1
               [apple,grape,banana,prune,plum,[lime],orange]

           A list element can be referenced using a subscript between zero and
           one less than the number of elements in the list:

               > $mylist = [1, 2, 3, 4, 5, 6]; length($mylist)
               6
               > $mylist[0]
               1

           It is an error to reference a non-existent list element using a
           subscript. (Note: additional syntax may be introduced to provide a
           way to declare lists and arrays.)

           The values of one or more list elements are selected by a list
           reference, which includes the simple subscript case just described.
           The value of a list reference is either a basic data type or a
           list.

               LIST-REFERENCE       -> "[" LIST-REFERENCE-ELS "]"
               LIST-REFERENCE-ELS   -> EMPTY | LIST-REFERENCE-EL | LIST-REFERENCE-EL "," LIST-REFERENCE-ELS
               LIST-REFERENCE-EL    -> EXP | LIST-REFERENCE-SLICE
               LIST-REFERENCE-SLICE -> EXP ".." EXP

               LIST-REFERENCE-SEQ   -> LIST-REFERENCE | LIST-REFERENCE LIST-REFERENCE-SEQ

           An EXP must evaluate to a non-negative integer value. The ".."
           ("dotdot") range operator specifies a sequence of subscripts
           between the value to its left and the value to its right,
           inclusive. The left value must not be greater than the right value.
           If "#" appears to the right of the ".." operator, the number of
           elements in the list variable or the intermediate list computation
           is implied. A "#" may not appear to the left of ".." and may not be
           used in an expression (e.g., "#-2" is invalid). As in a function's
           argument list, a comma is not treated as the comma operator in this
           context. Note that it is not an error to specify non-existent
           elements in a slice; therefore it is possible for the value of a
           list reference to be the empty list.

               > $i=1, $mylist[$i]
               2
               > $mylist[1,3,5]
               [2,4,6]
               > $mylist[0..2,4]
               [1,2,3,5]
               > $mylist[2..#]
               [3,4,5,6]
               > $mylist[0..3]
               [1,2,3,4]

           The dotdot operator can also be used to construct an element of a
           list or alist:

               > $a = [1, 4..8, 10, 12, 13]
               [1,4..8,10,12,13]
               > length($a)
               5
               > $b = [0..2,4]; listref($a, $b)
               [1,4..8,10,13]

           Whether a "[" ... "]" sequence introduces a list constructor or
           list reference depends on the context; if it appears to the right
           of a list variable, list constructor, a function that returns a
           list, or another list reference, it is treated as a list reference.

           List references can be composed as a right-associative operation.
           For example:

               > $a = [[1,2,3], [4,5,6], [7,8,9]]
               [[1,2,3], [4,5,6], [7,8,9]]
               > $a[1][1]
               5
               > $a[0..1][1..2]
               [[4,5,6]]
               > $a[0..1][1..2][0][2]
               6


               Tip
               Individual characters and sequences of characters of a
               string-valued expression can be selected using strchars()[16],
               which uses a similar syntax.

               Note
               •   The list constructor and list reference syntax has not yet
                   been integrated with the expression grammar[17].

               •   A list value can also be assigned to a subscripted
                   variable; only a single subscript is allowed, however, and
                   the referenced element must already exist:

                       > $a = [1, 2, 3]
                       [1,2,3]
                       > $a[2] = 17
                       17
                       > $i = 1
                       1
                       > $a[$i] = [10, 11]
                       [10,11]
                       > $a
                       [1,[10,11],17]


       Alists
           DPL's associative list, or "alist", is similar to Perl's hashes. An
           alist is composed of zero or more pairs. The first element of each
           pair is a case-sensitive key, unique within the alist, that is used
           to index the element. The second element of a pair is its value,
           which may be any data type. The key element of a pair, or all the
           keys in an alist, can be obtained using keysof()[18]. Similarly,
           valuesof()[19] yields the value element or a list of value
           elements.

           Unlike a regular list, elements within an alist are not ordered.
           Two alists can only be compared for equality (or inequality); they
           are equal if they contain exactly the same pairs.

           An alist has the following syntax:

               ALIST       -> "{" "}" | "{" ALIST-PAIRS "}"
               ALIST-PAIRS -> ALIST-PAIR | ALIST-PAIRS "," ALIST-PAIR
               ALIST-PAIR  -> KEY-EL "," VALUE-EL
               KEY-EL      -> STRING
               VALUE-EL    -> BASIC-DATA-TYPE | LIST | ALIST

           An alist can also be created through the alist()[20] function.

           Here is an alist consisting of four elements:

               {"red", 0, "blue", 2, "green", 5, "black", 7}

           The length()[15] function returns the number of pairs of elements
           in an alist.

           An alist can be assigned to a variable:

               $myalist = {1, 2, 3, 4, 5, 6}
               $myalist_copy = $myalist

           An alist can be appended to another alist using the "." ("dot")
           concatenation operator. The compound assignment operator version of
           this operator may also be used.

               > $myalist={sunny, 3}
               {"sunny", 3}
               > $myalist . {rainy, 11}
               {"sunny", 3, "rainy", 11}
               > $myalist .= {"snowy", 13}
               {"sunny", 3, "snowy", 13}

           An alist element or pair is referenced using a string subscript. A
           sequence of string subscripts can be used to select multiple pairs.
           If the subscript (or subscripts) are within brackets, then a
           successful result will be a basic data type or a list. If the
           subscript (or subscripts) are within braces, then a successful
           result will always be an alist. Note that because an alist
           subscript is not automatically converted to the string type, a
           numeric subscript is illegal.

               > $myalist = {a, 2, b, 4, c, 6}; length($myalist)
               3
               > $myalist["a"]
               2
               > $myalist{"b"}
               {"b", 4}
               > $myalist{"c", "a"}
               {"c", 6, "a", 2}

           It is an error to reference a non-existent alist element. (Note:
           additional syntax may be introduced to provide a way to declare
           lists and arrays.)

           Like regular lists, alist references can be composed as a
           right-associative operation:

               > $myalist = {a, [1, 2], b, [3, 4], c, [5, 6]}; length($myalist)
               3
               > $myalist["a"]
               [1, 2]
               > $myalist{"b"}
               {"b", [3, 4]}
               > $myalist{"b"}[1]
               4

           It is possible to convert an alist to a regular list, or vice
           versa; see the cast[7] operator.

               Note
               There is currently no way to delete an alist pair.

   Expression Grammar
       The following grammar is used to construct an expression (EXP) or
       sequence (S) of expressions.

           Note
           The syntax is very similar to that of the C programming language.
           It differs with respect to data types, variables, compile-time
           operators, and on some minor aspects of grammar.

       A sequence of statements (or simply a sequence) is two or more
       expressions, with a ";" character separating them. The ";" is
       unnecessary following the last statement in a sequence of statements
       (and is therefore unnecessary if there is only one expression). The
       statements are evaluated in the order in which they appear. The value
       of a sequence is that of the last expression, unless an exit or return
       function is invoked, in which case the value of the sequence is the
       value returned by the function call. An error condition will also
       terminate evaluation of the sequence and yield a result of False. A
       sequence within curly braces is called a block.

       Figure 1. Expression Grammar

           S    -> E    | E ";" | E ";" S
           E    -> E2   | E2 "," E
           E2   -> E3   | VAR ASSIGN_OP E2 | IF_ELSEIF_ELSE
           E3   -> E4   | E4 "?" E ":" E
           E4   -> E5   | E5 OR E5
           E5   -> E6   | E6 AND E5
           E6   -> E7   | E7 "|" E7
           E7   -> E8   | E8 "^" E8
           E8   -> E9   | E9 "&" E9
           E9   -> E10  | E10 EQ_OP E10
           E10  -> E11  | E11 REL_OP E11
           E11  -> E12  | E12 "." E12
           E12  -> E13  | E13 "<<" E13 | E13 ">>" E13
           E13  -> E14  | E14 "+" E14  | E14 "-" E14
           E14  -> E15  | E15 "*" E15  | E15 "/" E15 | E15 "%" E15
           E15  -> E16  | E16 "^" E14  | E16 "**" E14
           E16  -> E17  | NOT E16 | "~" E16 | "++" VAR | "--" VAR
                        | "+" E | "-" E | "(" type ")"
           E17  -> "(" E ")" | VAR "++" | VAR "--" | FUNCTION_CALL | PRIMARY

           ASSIGN_OP -> "=" | "+=" | "-=" | "*=" | "/=" | "%=" | ">>="
                            | "<<=" | "&=" | "^=" | "|=" | ".="

           PRIMARY -> a number | a string | VAR
           OR      -> "||" | "or"
           AND     -> "&&" | "and"
           NOT     -> "!"  | "not"
           EQ_OP   -> "==" | "!=" | "eq" | "ne"
           REL_OP  -> "<"  | "<=" | ">" | ">=" | "lt" | "le" | "gt" | "ge"
           VAR     -> a variable reference
           FUNCTION_CALL -> FUNCTION_NAME "(" ARG_LIST ")"
           ARG_LIST -> EMPTY | E2 | ARG_LIST "," E2
           EMPTY    ->

       Keywords and function names are case sensitive.

       The production VARASSIGN_OPE in the grammar refers to assignment of the
       evaluation of E to a variable using the given assignment operator
       (ASSIGN_OP). For example,

           ${a} += 17

       Provided ${a} has been initialized to an integer value, this expression
       increments it by 17.

       The production IF_ELSEIF_ELSE represents a familiar if statement with
       zero or more elseif components and an optional else component:

           if (expression) {
             sequence
           }
           [elseif (expression) {
             sequence
           }] ...
           [else {
             sequence
           }]

       Each block is an optional sequence of statements. Braces are mandatory.

           Tip
           An if_elseif_else statement has a value: it is either that of the
           last statement executed in the selected block, or the empty string
           if no statement is executed. In this example, ${a} is set to either
           33 or ${b} - 1, depending on whether ${b} is greater than eight:

               ${a} = if (${b} > 8) {${b}++; 33;} else {${b} - 1}

           The value of this expression is the string "hello, world":

               "hello, " . (if (0) {b . y . e} else {"world"})

           Note
           As in C, function calls, nested assignment operators, and increment
           and decrement operators cause side effects where the value of a
           variable is changed during expression evaluation. Because exactly
           when such side effects take place is left unspecified, programmers
           should avoid writing code with these kinds of dependencies on
           evaluation ordering.

   Operators
       The operators that appear in the grammar have the following semantics.
       They are listed in order of increasing precedence (which is very close
       to ISO C's), with operators in the same section having equal
       precedence. The result of applying an operator is one of the supported
       data types[21], or an error. Parentheses can be applied to
       subexpressions in the usual way.

       Whenever it makes sense, intermediate values are automatically
       converted to an appropriate type by an operator. So, for example,
       adding an integer and a real will cause the integer to automatically be
       converted to a real, yielding a real value. Adding a string and a
       number will work only if the string can be successfully converted to a
       number. In situations where an integer is required, a real value
       (including a string that represents a valid real number) will be
       truncated to an integer. For logical comparison operators, the operands
       will both be converted to integers, reals, or strings as necessary. A
       string value that is an illegal number will always be treated as a
       string.

           Note
            id="note11" xreflabel="dacsexpr prompts".PP In the examples that
           follow, the '>' character at the beginning of an input line is a
           prompt from dacsexpr(1)[1].

       ,
           This is the C/C++ comma operator. A pair of expressions separated
           by a comma is evaluated left to right, and the type and value of
           the result are the type and value of the right operand.

       =, +=, -=, *=, /=, %=, >>=, <<=, &=, ^=, |=, .=
           Assignment is done using a simple or compound assignment operator,
           each of which has right to left associativity. In the case of a
           compound assignment operator, the left hand side is evaluated only
           once. The type and value of an assignment is that of its right hand
           side. A variable reference is expected on the left side of the
           operator. Modifier flags are not permitted. The variable, which is
           created if it does not exist. The syntax of the variable reference
           includes the initial "${" and terminating "}" character (so it's
           similar to Perl's syntax).

               > ${foo::bar} = "hello"
               "hello"
               > ${foo::bar} .= ", world"
               "hello, world"
               > ${a} = [1, 2]
               [1,2]
               > ${a} .= [3, 4]
               [1,2,3,4]


       ?:
           This is equivalent to the C/C++ conditional expression, which has
           right to left associativity. If the first expression is True, the
           result is the value of the second expression (the third is not
           evaluated). If the first expression is False, the result is the
           value of the third expression (the second is not evaluated).

       or, ||
           This is the C/C++ logical OR operator, which yields 1 (True) if
           either operand is True, otherwise it yields 0 (False). Evaluation
           is from left to right and and stops as soon as the truth or
           falsehood of the result is known. The two tokens are synonymous.

       and, &&
           This is the C/C++ logical AND operator, which yields 1 (True) if
           both operands are True, otherwise it yields 0 (False). Evaluation
           is from left to right and and stops as soon as the truth or
           falsehood of the result is known. The two tokens are synonymous.

               Note
               When expressions are parsed as XML attribute values, an '&'
               character must be encoded as the five characters '&amp;'.

       |
           This is the C/C++ bitwise inclusive OR operator. Both operands must
           be integers.

       ^
           This is the C/C++ bitwise exclusive OR operator. Both operands must
           be integers.

       &
           This is the C/C++ bitwise AND operator. Both operands must be
           integers.

               Note
               When expressions are parsed as XML attribute values, an '&'
               character must be encoded as the five characters '&amp;'.

       ==, !=, eq, ne, eq:i, ne:i
           These operators compare their arguments and return 1 if the
           relation is true, 0 otherwise. If both arguments are lists,
           corresponding elements of both lists are compared, recursively. If
           both arguments are alists, the number of pairs in both lists is
           compared and, if necessary, pairs in the first list are looked up
           in the second list for matching values (note that the
           case-insensitive variant applies only to the value component of a
           pair, not the key component). For other valid arguments an attempt
           is first made to coerce both arguments to numbers and do a numeric
           comparison. If that fails, a lexicographic comparison is performed.
           Operators having a :i modifier are like their counterparts without
           the modifier except they do case-insensitive string comparisons.

           If either argument is of type bstring, however, the comparison is
           done differently than explained above. Two bstring arguments are
           equal if and only if they are byte-wise identical. If one argument
           is a bstring and the other is a string, the latter is treated as a
           bstring of length(string) bytes. The case flag is ignored if at
           least one argument is a bstring.

       <, <=, >, >=, lt, le, lt:i, le:i, gt, ge, gt:i, ge:i
           These operators compare their arguments and return 1 if the
           relation is true, 0 otherwise. An attempt is first made to coerce
           both arguments to numbers and do a numeric comparison. If that
           fails, a lexicographic comparison is performed. Operators having a
           :i modifier are like their counterparts without the modifier except
           they do a case-insensitive comparison.

               Note
               When expressions are parsed as XML attribute values, the '<'
               character must be encoded as the four characters '&lt;'; the
               same applies to the "greater than" symbol.
           If either argument is of type bstring, however, the comparison is
           done differently than explained above. If two bstring arguments are
           compared, the shorter bstring is "less than" the other argument and
           they are equal if and only if they are byte-wise identical. If one
           argument is a bstring and the other is a string, the latter is
           treated as a bstring of length(string) bytes. The case flag is
           ignored if at least one argument is a bstring.

       .
           The "dot" operator (not in ISO C) concatenates its right operand to
           its left operand. If both arguments are of type bstring, the result
           is also of type bstring. If the left operand is a list and the
           right operand is a basic data type, the right operand is appended
           to the list. If the left operand is a list and the right operand is
           also a list, the elements of the right operand are appended to the
           left operand. A list may not appear as the right operand if the
           left operand is not a list. In all other cases, both arguments are
           coerced to string (an error occurs if this cannot be done) before
           the left operand is appended to the right.

               > "hello" . ", world"
               "hello, world"
               > "hello" . (16 + 1)
               "hello17"
               > 17 . (16 + 1)
               "1717"
               > [1, 2, 3] . 4
               [1,2,3,4]
               > [1, 2, 3] . [4, 5, 6]
               [1,2,3,4,5,6]
               > [1, 2, 3] . [[4]]
               [1,2,3,[4]]


               Note
               A period will be recognized as a decimal point in a real number
               context rather than as the dot operator, so the input:

                   4.5

               will be scanned as a number whereas, for example, the input:

                   "4".5

               will evaluate to the string "45".

       <<, >>
           These are the C/C++ bitwise left shift and right shift operators,
           respectively. The first operand may be an integer or a list, the
           second operand must be an integer. When shifting an integer, these
           operators are implemented using the corresponding C/C++ operators.
           In the case of right shifting, the behaviour with respect to
           arithmetic vs. logical shifts will be platform dependent.

       +, -
           These are the (binary) addition and subtraction operators,
           respectively. Both arguments are coerced to numbers. An error
           occurs if this cannot be done. Also, unary + and - operators may
           precede an arithmetic-valued expression.

       *, /, %
           These are the multiplication, division, and remainder operators,
           respectively. Both arguments are coerced to numbers. An error
           occurs if this cannot be done, such as attempting to divide by
           zero. For the remainder operator, both operands must be integers.

       **
           This is the exponentiation operator (not in ISO C). Both arguments
           are coerced to numbers (either both integers or both reals). An
           error occurs if this cannot be done, such as attempting to raise to
           a negative power.

               > 2**10
               1024


       +, -, not, !, ~, ++VAR, --VAR, (type)
           The + and - operators are the (unary) arithmetic plus and minus
           operators, respectively. These may precede an arithmetic-valued
           expression. Both arguments are coerced to numbers. An error occurs
           if this cannot be done.

           The logical NOT operator (not, or equivalently, !) yields a result
           of zero when applied to a non-zero numeric value and non-zero when
           applied to an operand of zero. The result of applying this operator
           to a non-empty string is zero and it is non-zero when applied to an
           empty string string. These two tokens are synonymous.

           The ~ operator is the one's complement (bitwise not) unary
           operator.

           The ++VAR and --VAR operators are the prefix increment and
           decrement operators, respectively. These operators are followed by
           a variable reference. The variable must have an integer value.

               > ${foo} = 17, ++${foo}
               18

           An explicit type conversion can be forced by using a cast. The
           syntax for this type coercion is:

               (type) expression

           The type must be a recognized data type name: integer or int (for
           an integer), real or double (for a real), bool (for a boolean value
           as a long integer), string (for a character string), bstring or
           binary (for a binary string), list, alist, or void.

           A list can be cast to an alist, provided it has no elements or an
           even number of elements and if no key would appear more than once
           in the alist. A namespace can be cast to an alist; the operand
           specifies the namespace, either as a literal or a string. An alist
           can be cast to an list; the ordering of the pairs in the resulting
           list is unspecified. A void type can only be cast to void, which is
           a no-op. Here are some examples:

               > (int) 3.4
               3
               > (int) "3.6"
               3
               > (bool) 17
               1
               > (bool) ""
               0
               > (string) (4 * 3)
               "12"
               > ${x} = "17"; (int) ((real) ${x} + (bool) 1965)
               18
               > (bstring) "abc"
               "abc"
               > (bstring) 4.4
               "4.400000"
               > (bstring) "\0\1\2"
               ""
               > bstring("\0\1\2",3) . bstring("\3\4", 3)
               "0001020304"
               > (void) ($b=$x)
               >
               > (alist) [a, 1, "b", 2, 3, 3]
               {"a", 1, "b", 2, "3", 3}
               > (list) { red, first, blue, second, white, third }
               ["blue", "second", "white", "third", "red", "first"]
               > $env = (alist) Env; $env["HOME"]
               "/home/bobo"
               > $env{HOME}
               {"HOME","/home/bobo"}


       VAR++, VAR--, primary
           The VAR++ and VAR-- operators are the postfix increment and
           decrement operators, respectively. These operators are preceded by
           a variable reference. The variable must have an integer value.

           A primary is a basic data type[21] (i.e., an integer or real
           number, string, bareword, or binary string), or a variable
           reference[22].

   Functions
       A function call is written as a function name, optionally followed by
       whitespace, a left parenthesis, zero or more comma-separated arguments,
       and a right parenthesis. A function name begins with either an
       alphabetic character or an underscore, followed by any number of
       alphanumerics and underscores. Additionally, a pair of colons may
       appear exactly once within the name (except at the beginning or end of
       the name). The number of arguments and their expected types depends on
       the particular function being called. The order in which the arguments
       to a function are evaluated is undefined. There is no mechanism for
       creating user-defined functions yet (they will eventually be available
       on some platforms through dynamically linked libraries).

       The result of a function call is one of the supported data types[21],
       or an error. An invalid function call, including those that fail during
       execution, yields a False result.

       Function Index:ack: notice acknowledgement processing

       •   alist: create an alist

       •   alistref: create an alist reference

       •   bstring: convert a string to binary

       •   contains_any: count elements common to two lists

       •   counter: persistent integer counters

       •   dacs_admin: test if user is an administrator

       •   dacs_approval: create or test a signed authorization

       •   dacs_meta: get or update metadata

       •   dacsauth: perform authentication tests

       •   dacscheck: perform authorization tests

       •   debug: control debugging output

       •   decode: convert from a text representation

       •   digest: cryptographic hash functions

       •   encode: convert to a text representation

       •   eval: evaluate a string

       •   exec: execute a program

       •   exit: terminate current evaluation

       •   expand: variable interpolation

       •   file: perform an operation on a file

       •   file_group: test if user is associated with file's group

       •   file_owner: test if user is associated with file's owner

       •   from: test where the current request comes from

       •   get: read the contents of a file or VFS object

       •   hash: fast hashes

       •   hmac: secure keyed-hashes

       •   http: invoke an HTTP request

       •   index: search a string or list

       •   info: information about namespaces and variables

       •   keysof: extract keys from an alist

       •   ldap: extract a component from an LDAP name

       •   length: string length

       •   list: create a list

       •   listref: dereference a list

       •   on_success: evaluate an expression if authentication or
           authorization succeeds

       •   password: compute or check a password hash

       •   pathname: filename-based string interpolation

       •   pbkdf2: password-based key derivation

       •   print: display a string

       •   printf: display a formatted string

       •   random: generate random values

       •   redirect: redirect user after access is denied

       •   regmatch: string matching

       •   regsub: string substitution

       •   request_match: compare the current request to a URI

       •   return: terminate current evaluation

       •   rule: recursive authorization checking

       •   setvar: operations on namespaces

       •   sizeof: basic data type sizes

       •   sleep: suspend execution temporarily

       •   source: read and evaluate external expressions

       •   sprintf: format a string

       •   strchars: select characters from a string

       •   strchop: delete characters from the end of a string

       •   strftime: format the current date and time

       •   strptime: parse a date and time

       •   strrstr: locate the last instance of a substring

       •   strstr: locate the first instance of a substring

       •   strtolower: map uppercase to lowercase

       •   strtoupper: map lowercase to uppercase

       •   strtr: character transliteration

       •   subset: test if one set is a subset of another

       •   substr: extract a substring

       •   syntax: perform a syntax check on a string

       •   time: local time and date

       •   transform: filter text through rule-based transformations

       •   transform_config: set options for transform

       •   trim: delete trailing characters

       •   typeof: get or test data type

       •   undef: an undefined value

       •   user: test current user's identity

       •   ustamp: generate a unique stamp

       •   valuesof: extract values from an alist

       •   var: operations on individual variables

       •   vfs: perform a VFS operation

       ack(notice-uri[, ...][, EXACT_MATCH | ALL_MATCH])
           This function is associated with notice acknowledgement processing.
           The function indicates that the current service request has one or
           more notices associated with it (identified by a sequence of
           notice-uri arguments), each one represented by a URI that will
           return the text of a notice that must be acknowledged by the user.
           Following the last URI is an optional mode argument. The
           EXACT_MATCH mode is the default mode and requires a single
           acknowledgement to address all of the specified notices. The
           ALL_MATCH argument specifies a less stringent matching mode and
           requires any set of acknowledgements to collectively address all of
           the specified notices. See dacs_notices(8)[23].

       alist([key, value [, ...])
           This function is equivalent to the alist construction operator[24].
           There must be an even number of arguments, or no arguments. If the
           first argument of each pair (the key) is not a string or literal,
           it will be converted to a string, if possible.

               alist(cars, 2, bikes, 5)

           is equivalent to the expression:

               {"cars", 2, "bikes", 5}

           And the call:

               alist(2, xx, [0, 1], yy)

           yields:

               {"2", xx, "[0,1]", yy}


       alistref(list)
           This function creates a new list that is equivalent to that of the
           special "brace syntax" subscript used to dereference an alist. This
           is currently useful only in conjunction with listref()[25].

               listref({"a", 1, "b", 2, "c", 3}, alistref(["b"]))

           is equivalent to the expression:

               {"a", 1, "b", 2, "c", 3}{"b"}

           the value of which is:

               {"b", 2}


       bstring(string, length)
           This function converts the first length characters of string (which
           may also be a bstring and which is converted to a string if
           necessary) into the binary type. The length argument may be less
           than the actual length of string; if it is zero, then actual length
           is computed, and if length is greater than the actual length, the
           actual length is used. The implicit null character on the end of
           string is not considered part of it.

               > bstring("\0\1\2", 4)
               "000102"
               > bstring("\0\1\2", 2)
               "0001"


       contains_any(format, test-set, target-set[, nocase])
           This function returns a count of the number of elements of test-set
           that appear in target-set at least once. Duplicate elements may
           appear in test-set and are considered to be distinct. The format
           indicates how to parse the set arguments. It can be the space, tab,
           or newline character, or any punctuation character. For both sets,
           it is currently interpreted as the character that separates
           elements. If the optional nocase literal argument is given, then
           set elements are compared case-insensitively. The greatest possible
           return value is the number of distinct elements in the third
           parameter.

               contains_any(",", ${Args::LAYERS:i}, "Nests,Secret_roads,Heritage")
               contains_any(",", "a,a,b,z", "a,a,a,b,b,b,a,z,z")

           The first expression returns 3 if every element in the third
           parameter appears at least once (case insensitive) in the second
           parameter, otherwise the value of the expression is 0. The second
           expression returns 4.

       counter(op, vfs-ref, counter_name [,value])
           This function is used to manage persistent integer counters, which
           can be useful for a variety of purposes, such as counting the
           number of logins for a particular identity, limiting the number of
           logins, or restricting the number of times a resource can be
           accessed. Internally, counter values are integers[21].

           The first argument specifies an operation and is case-insensitive.
           The second argument identifies a filestore (typically a file or
           database). It must be an indexed filestore scheme, such as
           dacs-kwv-fs or dacs-db (see VFS[26]). The third argument is the
           name of the counter, which acts as a key. The meaning of the fourth
           argument depends on the operation, but if present it must be an
           integer.

               Note
               The current implementation has a limitation; a counter name
               (key) can be any printable string but cannot contain a space
               character. You can work around this limitation by encoding all
               keys every time they are used in a filestore operation.

            1. counter(set, vfs-ref, counter_name, new-value)

               This is used to create a new counter or reset an existing
               counter. The counter's value will be new-value, which must be
               an integer, and is the return value.

            2. counter(create, vfs-ref, counter_name, initial-value)

               This is used to create a new counter if it does not already
               exist. The new counter's value will be initial-value, which
               must be an integer. If the counter exists, its value will not
               be changed and is returned.

            3. counter(del[ete], vfs-ref, counter_name)

               This operation deletes an existing counter. The operation can
               be del or delete.

            4. counter(exists, vfs-ref, counter_name)

               This operation returns 1 if a counter exists, 0 otherwise.

            5. counter(get, vfs-ref, counter_name)

               This operation returns the current counter value.

            6. counter(inc|dec, vfs-ref, counter_name[, amount])

               This operation increments or decrements an existing counter by
               amount, which must be an integer. If amount is not given, 1 is
               used. The updated counter value is returned.

            7. counter(decdel, vfs-ref, counter_name[, amount])

               This operation decrements an existing counter by amount, which
               must be an integer. If amount is not given, 1 is used. If the
               resulting value is zero or negative, the counter is deleted and
               zero is returned. If the counter is not deleted, its updated
               value is returned.

            8. counter(list, vfs-ref)

               This operation returns a list of counters as a string, newline
               separated, each with its current value.

           Operations that set or change the counter value return the new
           value.

           For filestores that support locking, read-only operations obtain a
           shared lock while the other operations obtain an exclusive lock.

           It is an error to reference a counter that does not exist unless
           the operation is set or exists.

               Note
               To some extent, this function is a poor substitute for a more
               general Perl-like tie() function. Such a function is being
               considered.

               Modifications to counters are not atomic. Amongst other things,
               this means that a crash may cause counter updates to be lost.
           A counter would typically be created by running dacsexpr(1)[1]:

               % dacsexpr -e 'counter(set, "dacs-kwv-fs:/usr/local/dacs/counters/logins", "EXAMPLE::EX:bob", 1)'

           The counter's value might then be tested in the revocation list[27]
           or by an access control rule[28], for instance:

               counter(exists, "dacs-kwv-fs:/usr/local/dacs/counters/logins", ${DACS::IDENTITY})

           The counter might be conditionally updated using the
           on_success()[29] function, or the AUTH_SUCCESS[30] or
           ACS_SUCCESS[31] directives, using an expression like:

               counter(decdel, "dacs-kwv-fs:/usr/local/dacs/counters/logins", ${DACS::IDENTITY})


       dacs_admin()
           This predicate returns True if the user making a service request
           has any credentials that match any specified by the
           ADMIN_IDENTITY[32] configuration directive.

       dacs_approval(op[, ...])
           This function is used to create an approval stamp[33] or inspect or
           validate one.

           The following operations are available:

           dacs_approval(approval, dacs64-approval-message, namespace)
               This operation parses the dacs64-approval-message (the value of
               DACS_APPROVAL), setting variables in namespace, after first
               dacs64 decoding[34] the argument. If namespace exists, its
               contents are deleted. Variables set are: j (jurisdiction name),
               h (hash/digest name), s (stamp), u (URI), m (HTTP method), and
               i (user identity). See dacs_acs(8)[33]. The signature is not
               checked. The function returns True (1) if the approval message
               is syntactically correct, otherwise False (0).

           dacs_approval(check, dacs64-approval-message)
               The dacs64-approval-message is decoded and parsed, and the
               signature is validated. The function returns True (1) only if
               the signature is correct, otherwise False (0).

               In the current implementation, the signature can only be
               validated by the jurisdiction that signed the message. This
               deficiency will be addressed in a future release and a web
               service will also supply this functionality. Ideally, for
               maximum convenience, availability, efficiency, and simplicity,
               the recipient of an approval message should be able to validate
               it directly if it has the appropriate public key, invoke a web
               service at any jurisdiction in the federation if public keys
               are distributed and kept current, or at the jurisdiction that
               signed the message.

           dacs_approval(create, uri, method, ident, digest-name)
               Create and return a dacs64-approval-message (as described above
               and in dacs_acs(8)[33]), formed from the given arguments and
               signed by the current jurisdiction.


       dacs_meta(op[, ...])
           This function returns information associated with the current
           federation, current jurisdiction, or other jurisdictions in the
           current federation. See dacs_list_jurisdictions(8)[35] for
           additional information.

           The following operations are available:

           dacs_meta(federation, namespace)
               Return metadata for the current federation, setting variables
               in namespace. If namespace exists, its contents are deleted.
               Variables set are: federation, domain, fed_id (if available),
               and fed_public_key (if available, in PEM format).

           dacs_meta(jname, jurisdiction-name, namespace)
               Return metadata for the jurisdiction named jurisdiction-name in
               the current federation. If namespace exists, its contents are
               deleted. Variables set are: jname, name, alt_name, dacs_url,
               authenticates, prompts, auxiliary (if available), and
               public_key (if available, in PEM format).

           dacs_meta(jurisdiction, namespace)
               This is equivalent to the jname operation with
               jurisdiction_name set to the name of the current jurisdiction.

           dacs_meta(list_jurisdictions)
               Return a newline-separated list of all jurisdiction names in
               the current federation. A local copy of the metadata is used.

           dacs_meta(update_jurisdiction, jname [,url])
               Not implemented. Intended to update the local metadata for the
               jurisdiction name jname. If url is absent, then the current
               jurisdiction must already have the correct dacs_url attribute
               in its entry for jname. If url is given, it is assumed to be
               the URL for dacs_list_jurisdictions and it is used instead of
               one formed from dacs_url for the jurisdiction.

           dacs_meta(update_jurisdictions, jname)
               Not implemented. Intended to update the local metadata for all
               of the jurisdictions. If jname looks like a URL (i.e., it
               begins with either "http" or "https", then it is assumed to be
               the URL for dacs_list_jurisdictions and it is used to obtain a
               fresh copy of the metadata; otherwise, jname is assumed to be a
               jurisdiction name for which the current jurisdiction already
               has a correct dacs_url attribute and metadata is retrieved from
               that jurisdiction.


       dacsauth(dacsauth-flags)
       dacsauth(arg1, arg2[, ...])
           This function provides an interface to dacsauth(1)[36]. In the
           first usage, the single string argument is parsed into space or tab
           separated flags. Single or double quotes are allowed. In the second
           usage, each flag is a separate string or literal argument and is
           not parsed.

           An alist is returned that has the following three elements:

           result
               An integer: 1 if authentication succeeded, 0 if it failed or
               was not requested, and -1 if an error occured.

           identity
               A string: if authentication was requested and succeeded, this
               is the corresponding identity, otherwise it is the empty
               string.

           roles
               A string: if roles were requested (and authentication
               succeeded, if requested), this is the role descriptor string,
               otherwise it is the empty string.


               Important
               This function should be considered experimental. Use it with
               caution. In version 1.4.25 and earlier, this function returned
               an integer value (the result).

               Security
               Like dacsauth and dacs_authenticate, if a built-in module is
               used to perform authentication, this function must be run by a
               setuid or setgid process to obtain sufficient privileges to
               access the required files; this is true for Unix password
               authentication, for example.
           Examples: .sp .if n  .RS 4 . .nf > dacsauth("-m unix suff -user
           bobo -p apassword") {"result",0,"identity","","roles",""} >
           dacsauth("-m", "unix", "suff", "-user", "bobo", "-p", "bpassword")
           {"result",1,"identity","EXAMPLE::FEDROOT:bobo","roles",""} >
           dacsauth("-r unix
           -DVFS='[federation_keys]dacs-fs:/usr/local/dacs/federations/federation_keys'
           -u bobo") {"result",0,"identity","","roles","bobo,wheel,www,users"}
           .fi .if n  .RE . .sp

       dacscheck(dacscheck-flags)
       dacscheck(arg1, arg2[, ...])
           This function provides an interface to dacscheck(1)[37], returning
           1 if access is granted, 0 if access is denied, and -1 if an error
           occurs. In the first usage, the single string argument is parsed
           into space or tab separated flags. Single or double quotes are
           allowed. In the second usage, each flag is a separate string or
           literal argument and is not parsed.

               Important
               This function should be considered experimental. Use it with
               caution.

       debug(type, value)
           This function enables, disables, or adjusts the amount of debugging
           output produced by the interpreter. Output type type is set to
           value, which may be "on", "off", or a non-negative integer level
           (the meaning of which depends on type.

           The following type names are recognized: TBD

       decode(encoding-type, string)
           This function performs the inverse of encode()[38] for the same
           encoding-type. The result is a bstring. The function will fail if
           its argument is not properly encoded.

           For the hex encoding type, alphabetic characters may be upper case
           or lower case.

       digest(msg, msg-len [, digest-name])
           This function computes a cryptographic hash[39] of msg (a string or
           bstring). The msg-len is the length of msg in bytes; if it is 0,
           its length is implicitly the entire length of msg. The hash
           algorithm can be any function provided by OpenSSL and may be
           specified as digest-name, case insensitively, otherwise "sha1" is
           used. The list of available digest algorithms is subject to change,
           but is likely to include "md5" (the 128-bit MD5 Message-Digest
           Algorithm[40]), "sha" (the deprecated 160-bit SHA-0 algorithm),
           "sha1" (the 160-bit SHA-1 Secure Hash Algorithm), "sha224",
           "sha256", "sha384", and "sha512". Algorithms "sha224" (SHA-224),
           "sha256" (SHA-256), "sha384" (SHA-384), and "sha512" (SHA-512)
           (224, 256, 384, and 512 bit values, respectively) comprise SHA-2.
           The function value is a bstring. If cryptographic strength is not
           required, see hash()[41].

               > digest("foo", 0, "md5")
               "acbd18db4cc2f85cedef654fccc4a4d8"
               > digest("Hello, world", 0, "SHA256")
               "4ae7c3b6ac0beff671efa8cf57386151c06e58ca53a78d83f36107316cec125f"


       encode(encoding-type, arg)
           This function converts arg, a string or bstring, into a printable
           text representation that depends on encoding-type. Applying
           decode()[42] with the same encoding-type to the output of this
           function will produce a value equivalent to the original arg. The
           result is a string.

           Note that encoding is only a representational or formatting change.
           If secrecy, authentication, or verification of integrity are
           required, use a cryptographic method.

           The following encoding types are recognized:

           encode(ascii85, arg)
               This encoding, also known as radix-85[43], uses nearly every
               printable character to obtain a compact encoding. But note that
               the resulting strings may be problematic in many contexts
               without additional encoding, which can largely defeat the
               reason for selecting this encoding in the first place. The
               start-of-data ("<~") and end-of-data ("~>") indicators that are
               sometimes used with this encoding are not included.

                   > encode(ascii85, decode(hex, "123456789a"))
                   "&i<X6RK"


           encode(cescape, arg)
               This encoding converts its argument into a C-style escaped
               string. Character escape codes are used when possible, numeric
               escape codes are used for other non-printable characters, and
               all other characters map to themselves.

                   > encode(cescape, bstring("hi\0\1\2\3\012", 7))
                   "hi\0\001\002\003\n"


           encode(dacs64, arg)
               This encoding type produces a base-64 encoding of arg using
               upper- and lower-case alphabetics, digits, '-', and '_'. It is
               similar to the mime encoding except that '-' and '_' are used
               in the encoding character set instead of '+' and '/'. This
               encoding is better suited for use in paths and URIs, for
               example, and is used extensively within DACS. It is sometimes
               referred to as "the dacs64 encoding" or just "dacs64" in the
               DACS documentation.

                   > encode(dacs64, bstring("\0\0\0\1", 4))
                   "_____-"


           encode(hex, arg)
               This encoding converts each byte in arg into a hexadecimal
               character pair.

                   > encode(hex, "Hello")
                   "48656c6c6f"


           encode(mime, arg)
               This encoding applies the MIME base-64 encoding function (RFC
               2045[44], Section 6.8) to its argument and returns the result.

                   > encode(mime, bstring("\0\0\0\1", 4))
                   "AAAAAQ=="


           encode(url, arg)
               This returns the URL-encoding of the argument (RFC 1738[45],
               RFC 2396[46] (Section 2.4), and RFC 3986[47]).

                   > encode(url, bstring("a\0b", 3))
                   "a%00b"



       eval(expression)
           This function evaluates its string argument and returns the result.

           The call:

               > eval("length(\"abc\")")
               3

       exec(prog, ...)
           The exec function executes prog, waits (indefinitely) for it to
           terminate, and returns the program's standard output. A trailing
           newline in the output is deleted. Optionally, command line
           arguments to prog may be given; they are automatically converted to
           strings. By default, no environment variables are passed to the
           program; if the namespace ExecEnv exists, however, its contents are
           used as the executed program's environment variables. The exit
           status of prog is made available as the value of ${DACS::status}.
           The program is executed using the execv(3)[48] function, not a
           command shell.

           On POSIX systems, this call returns the string "1\n" on Thursdays,
           "0\n" on any other day:

               > exec("/bin/sh", "-c", "date | grep -c ^Thu")
               "0"


               > ${ExecEnv::PATH} = "/usr/bin";
               "/usr/bin"
               > exec("/bin/sh", "-c", "printenv");
               "PATH=/usr/bin"


               Security
               The program is executed as the same user and group IDs as the
               DACS program that calls exec(). Take appropriate precautions to
               prevent unauthorized users from modifying or replacing DACS
               configuration files, access control rules, and so on.

       exit(result)
           Equivalent to return, this function causes evaluation of the
           expression, block, or program being evaluated to terminate and
           returns result as the value of the expression or the program's exit
           status.

       expand(string)
           The argument, a string, is returned with variable references
           expanded. An undefined variable expands to the empty string.

               > ${a} = 17
               17
               > "${a}"
               "17"
               > '${a}'
               "${a}"
               > expand('${a}')
               "17"
               > ${b} = 1999, ${c} = expand('${a}, \${b}')
               "17, ${b}"
               > expand(${c})
               "17, 1999"


       file(op [,arg-list])
           This function performs various operations on files and filenames
           according to op, which is one of the following operation names,
           followed by command-specific arguments. All arguments must either
           be strings or literal words.

            1. file(basename, string [,suffix])

               This is used to extract the last component of a pathname and is
               equivalent to the basename(1)[49] command. It deletes any
               prefix that ends with the last slash character in string, after
               first stripping trailing slashes, and a suffix, if present. The
               suffix is not stripped, however, if it is identical to the
               remaining characters in string. A non-existent suffix is
               ignored. The value is the resulting string.

                   > file(basename,"/a/b/c")
                   "c"
                   > file(basename,"/a/b/c.c")
                   "c.c"
                   > file(basename,"/a/b/c.c", ".c")
                   "c"
                   > file(basename,"/a/b/c.c", "c")
                   "c."
                   > file(basename,"/a/b/c.c", "c.c")
                   "c.c"
                   > file(basename,"/a/b/c.c//", "c.c")
                   "c.c"


            2. file(chmod, abs-mode, file)

               Change the mode of file to abs-mode, which is an absolute
               (octal) file mode (note, however, that DACS always set the
               process umask to 07).

                   file(chmod, "0755", "/usr/local/dacs/tmp/foofile")

            3. file(dirname, string)

               Equivalent to the dirname(1)[50] command, its value is the
               string that remains after deleting the filename portion of
               string (a pathname), beginning with the last slash character to
               the end of string, after first stripping trailing slashes.

                   > file(dirname,"/usr/local/dacs/bin/dacsexpr")
                   "/usr/local/dacs/bin"
                   > file(dirname,"/usr/local/dacs///")
                   "/usr/local"


            4. file(extension, pathname)

               The returned value is all of the characters in pathname after
               and including the last dot in the last element. If there is no
               dot in the last element of pathname, the value is the empty
               string.

                   > file(extension,"acl-myapp.0")
                   ".0"


            5. file(lstat, fmt, file)

               This is like the stat[51] operation, except in the case where
               the named file is a symbolic link, in which case lstat returns
               information about the link, while stat returns information
               about the file the link references.

            6. file(mkdir, directory [,abs-mode])

               Create directory. If an absolute (octal) mode is given, the new
               directory will have that mode (note, however, that DACS always
               set the process umask to 07).

            7. file(readlink, file)

               If file is a symbolic link, print its contents.

            8. file(remove, file)

               Remove (delete) file.

            9. file(rename, source-file, target-file)

               Rename (mv) source-file to target-file.

           10. file(rmdir, directory)

               Remove (delete) directory, which must be empty.

           11. file(stat, fmt, file)

               Similar to the stat(1)[52] command available on some systems,
               this makes the functionality of the stat(2)[53] system call
               available. The fmt argument is a printf(3)[54]-type descriptor
               that indicates what file status information is wanted and how
               it is to be printed. Non-formatting characters, including \n,
               \t, and \\, are copied to the output verbatim.

               The following format specifiers are understood:

               •   %d

                   The value of st_dev.

               •   %i

                   The value of st_ino.

               •   %m

                   The value of st_mode in octal.

               •   %M

                   The value of st_mode as text.

               •   %l

                   The value of st_nlink.

               •   %u

                   The value of st_uid in decimal.

               •   %U

                   The value of st_uid as text.

               •   %g

                   The value of st_gid in decimal.

               •   %G

                   The value of st_gid as text.

               •   %r

                   The value of st_rdev.

               •   %s

                   The value of st_size.

               •   %b

                   The value of st_blksize.

               •   %n

                   The value of the file argument.

               •   %N

                   If the argument is a symbolic link, print the contents of
                   the link, otherwise print the file argument.

               •   %ta

                   The value of st_atime in decimal.

               •   %tA

                   The value of st_atime as text.

               •   %tm

                   The value of st_mtime in decimal.

               •   %tM

                   The value of st_mtime as text.

               •   %tc

                   The value of st_ctime in decimal.

               •   %tC

                   The value of st_ctime as text.

               •   %f

                   The name of the host (fileserver) where the file is stored.

               •   %%

                   A literal '%' character.

               This excerpt from an access control rule limits access to
               authenticated users for every file greater than 999 bytes in
               length that it DACS-wraps:

                   <allow>
                     user("auth")
                   </allow>

                   <allow>
                     user("any") and file(stat, "%s", ${DACS::FILENAME}) lt 1000
                   </allow>


           12. file(test, op [, args])

               Most of the file-testing predicates of the test(1)[55] command
               are available.

               •   -bfile

                   True if file exists and is a block special file.

               •   -cfile

                   True if file exists and is a character special file.

               •   -dfile

                   True if file exists and is a directory.

               •   -efile

                   True if file exists, regardless of its type.

               •   -ffile

                   True if file exists and is a regular file.

               •   -gfile

                   True if file exists and its set group ID flag is set.

               •   -kfile

                   True if file exists and its sticky bit is set.

               •   -pfile

                   True if file exists and is a named pipe (FIFO).

               •   -rfile

                   True if file exists and is readable (access(file, R_OK) ==
                   0).

               •   -sfile

                   True if file exists and has a size greater than zero bytes.

               •   -ufile

                   True if file exists and its set user ID flag is set.

               •   -wfile

                   True if file exists and is writable (access(file, W_OK) ==
                   0).

               •   -xfile

                   True if file exists and is executable (access(file, X_OK)
                   == 0).

               •   -Lfile

                   True if file exists and is a symbolic link.

               •   -Ofile

                   True if file exists and its owner matches the effective
                   user id of this process.

               •   -Gfile

                   True if file exists and its group matches the effective
                   group id of this process.

               •   -Sfile

                   True if file exists and is a socket.

               •   -ntfile1file2

                   True if file1 and file2 exist and the former is newer than
                   the latter.

               •   -otfile1file2

                   True if file1 and file2 exist and the former is older than
                   the latter.

               •   -effile1file2

                   True if file1 and file2 exist and refer to the same file.

           13. file(touch, file [, abs-mode])

               If file does not exist, it is created; if an absolute (octal)
               mode is given, the new file will have that mode (note, however,
               that DACS always set the process umask to 07). If the file
               exists, its modification time will be set to the current date
               and time.


       file_group([path])
           Test if path (defaults to ${DACS::FILENAME}, which is equivalent to
           Apache's SCRIPT_FILENAME or REQUEST_FILENAME variables) has a group
           ownership with which the user making the request is associated.
           This is effectively the same as:

               file(test, "-e", ${DACS::FILENAME})
               and
               user("%" . ${Conf::JURISDICTION_NAME} . ":" \
                 . file(stat, "%G", ${DACS::FILENAME}))

           This predicate provides a simple way of limiting access to a file
           to its group membership with respect to file system permissions:

               <allow>
                 file_group()
               </allow>

           For example, if the user requesting access has been assigned the
           following roles by the current jurisdiction (e.g., through
           local_unix_roles):

               wheel,www,users

           and the resource being requested is the file:

               -rw-r--r--  1 bobo     www  75 Apr 11 12:41 htdocs/foo.html

           then this predicate would return True because the file has group
           ownership www and the user is associated with that role.

           There is an implicit assumption that the file in question is
           associated with the current jurisdiction; this might be problematic
           if more than one jurisdiction can claim this association.

       file_owner([path])
           Test if path (defaults to ${DACS::FILENAME}, which is equivalent to
           Apache's SCRIPT_FILENAME or REQUEST_FILENAME variables) is owned by
           the user making the request. This is effectively the same as:

               file(test, "-e", ${DACS::FILENAME})
               and
               user(${Conf::JURISDICTION_NAME} . ":" . file(stat, "%U", ${DACS::FILENAME}))

           This predicate provides a simple way of limiting access to a file
           to its owner with respect to file system permissions:

               <allow>
                 file_owner()
               </allow>

           There is an implicit assumption that the file in question is
           associated with the current jurisdiction; this might be problematic
           if more than one jurisdiction can claim this association.

       from(string)
           This predicate is used to test where a request comes from, based on
           the values of REMOTE_ADDR and REMOTE_HOST. These environment
           variables are passed to DACS from Apache. The supported argument
           types are similar to those recognized by the Apachemod_access[56]
           module's allow and deny directives. If either REMOTE_HOST or
           REMOTE_ADDR are needed to evaluate the argument but are not
           available, the result will be False.

           The string argument may be:

            1. a full or partially matching domain name:

                   from("metalogic.example.com")

               Here, the function yields True if the given domain name matches
               REMOTE_HOST or is a subdomain of REMOTE_HOST. Case-insensitive
               matching is performed (RFC 1035[57]). Only complete components
               are matched, so the above example will match
               foo.metalogic.example.com but not foonmetalogic.example.com. If
               REMOTE_ADDR is available but not REMOTE_HOST, a reverse DNS
               lookup will be performed on the domain name and all IP
               addresses that result will be tested against REMOTE_ADDR; if
               this lookup results in an error (i.e., it fails), then the
               function raises an error condition.

            2. a full IPv4 address in standard dot notation:

                   from("10.0.0.123")

            3. a partial IPv4 address (the first one, two, or three bytes) in
               standard dot notation:

                   from("10.0")

            4. a network/netmask pair:

                   from("10.0.0.0/255.255.0.0")

            5. a network/nnn pair using CIDR notation[58] (RFC 1338[59]):

                   from("10.0.0.0/8")

            6. a full or partial IPv4 address in standard dot notation where
               any address element can be a decimal number (0 through 255) or
               a range specification[60], similar to that used with
               strchars()[16]; note that the range separator in this context
               is ":" instead of "..": :

                   from("10.0.[0:100,255]")

               In the example above, the two high-order octets of
               ${DACS::REMOTE_ADDR} must be 10 and 0, the value of the next
               octet must be between 0 and 100 (inclusive) or be 255
               (decimal), and the value of the fourth octet is unimportant.
               The following expressions are equivalent:

                   from("10")
                   from("10.")
                   from("[10]")
                   from("[10].")
                   from("10.0.0.0/8")
                   from("10.0.0.0/255.0.0.0")


            7. "all" (always yields True and is included for compatibility
               with Apache):

                   from("all")

           An alternative method is to perform a regular expression match
           against ${DACS::REMOTE_ADDR} using regmatch()[61].

               Tip
               To test where a client authenticated from, which is not
               necessarily the same as the place from which a request is sent,
               use the user()[62] function.

       get(vfs-ref [,key])
           The file or item specified by vfs-ref, which may be followed by a
           key if it is an indexed filestore, is read and returned. The
           vfs-ref may be an absolute pathname, an item type, or a
           vfs_uri[26], except if called from a standalone application without
           a key argument, in which case vfs-ref may also be a relative
           pathname.

               Note
               A proper I/O subsystem does not exist yet, but until then you
               may use the special item type stdin to read the standard input
               until end of file. This function will probably not work if a
               special file is used (e.g., /dev/stdin).

       hash(msg, msg-len [,hash-name])
           This function computes a fast hash of msg, a string or bstring. The
           msg-len is the length of msg in bytes; if it is 0, its length is
           computed. The hash-name can be the 32-bit hash "hash32" (the
           default) or the 64-bit hash "hash64". The result is a string.
           Although the algorithms have been used extensively with very good
           results, they should not be used for cryptographic purposes; see
           digest()[63].

               > hash("Hello, world", 0)
               "3696529580"
               > hash("Hello, world", 0, hash64)
               "462009511995194717"


       hmac(msg, msg-len, key, key-len [, digest-name])
           This function computes a cryptographic message authentication
           code[64] - specifically, the Keyed-Hash Message Authentication Code
           (HMAC)[65] - of msg (a string or bstring), using key (a string or
           bstring). The msg-len is the length of msg in bytes; if it is 0,
           its length is computed. Similarly, key-len is the length of key in
           bytes and if it is 0, its length is computed. Any of the available
           Secure Hash Standard functions[66], as well as MD5 (RFC 2104)[67],
           may be specified as digest-name (case insensitively), otherwise
           SHA1 is used. The list of available digest algorithms is subject to
           change, but is likely to include md5, sha1, sha224, sha256, sha384,
           and sha512. The function value is a bstring. Note that the function
           is not commutative; the key is the third argument, not the first.
           Although the MD5 hash function is deprecated for some purposes, it
           is still considered adequate in some applications and is required
           by many older protocols that are still in widespread use.

               > hmac("Sample #2", 0,
                 decode(hex, "303132333435363738393a3b3c3d3e3f40414243"), 0)
               "0922d3405faa3d194f82a45830737d5cc6c75d24"


       http(url, [method [,arglist]])
           This function sends an HTTP request to url, using a given method
           (GET, POST, HEAD, PUT, DELETE, or OPTIONS, case insensitively), and
           optionally passing parameters. If no method is given (and no
           arguments), GET is assumed. The value of the function is the
           message returned by the request. The url is in the usual syntax and
           must use either the http or https scheme (case insensitive). The
           argument list, if present, consists of some number of pairs, the
           first being the name of the parameter and the second the value of
           the parameter.

           The first statement sends an HTTP request to example.com and sets
           the variable to the message body (if any) that is returned. The
           second statement makes a GET request to port 8443 of example.com
           over SSL, passing it two parameters, FOO=17 and FOO=2:

               > ${x} = http("http://example.com")
               > http("https://example.com:8443/cgi-bin/dacs_prenv.cgi", "GET", "FOO", 17,
                     "BAZ", 1+1)


       index(string, character-class [, nocase])
       index(list, search_operand [, nocase])
           If the first argument is a string, this function returns the first
           position in string (counting from 1) where the first character in
           character-class was found, or 0. Case-sensitive character
           comparison is used unless the optional nocase literal argument is
           present.

           If the first argument is a list, the position of element
           search_operand (counting from 1) in list is returned, or 0 if it is
           not found. During comparison, types are automatically converted as
           necessary. Case-sensitive character comparison is used unless the
           optional nocase literal argument is present.

           Examples:

               > index("abcdef", "abc")
               1
               > index("abcdef", "e")
               5
               > index("zzz", "abc")
               0
               > index([a, b, c, d, e], d)
               4
               > index(["hello", world, 2009, qUAKe], "quake", nocase)
               4
               > index([1.0, 2.2, 3.3, 4.4, 5.0, 6.6], "1")
               1
               > index(["apple", ["orange", "banana"], ["peach", "mango"]], "orange")
               0
               > index(["apple", ["orange", "banana"], ["peach", "mango"]], ["orange", "banana"])
               2


       info(namespaces)
       info(namespace, namespace-name)
           Return a string containing information about variables and
           namespaces. The first form returns a comma-separated list of known
           namespaces. The second form returns a list containing all variables
           in the given namespace and their values, one per line. This can be
           useful for debugging.

           Examples:

               info(namespaces)
               info(namespace, "Conf")


       keysof(alist)
           If its argument is a single pair, the pair's key is returned. If
           there is more than one pair in the argument, a list of keys is
           returned. To get the value component of a pair or set of pairs, use
           valuesof()[19].

           Examples:

               > keysof({red, 17})
               "red"
               > keysof({red, 17, blue, 100})
               ["red", "blue"]


       ldap(dn_length, dn-string)
       ldap(dn_index, dn-string, nth)
       ldap(rdn_length, rdn-string)
       ldap(rdn_index, rdn-string, nth)
       ldap(rdn_attrtype, rdn-string [, nth])
       ldap(rdn_attrvalue, rdn-string [, nth])
           The ldap function is used to extract components of LDAP names. Its
           first argument, a literal, determines the operation mode to be used
           and the semantics of the following arguments. Distinguished Name
           (DN) and Relative Distinguished Name (RDN) strings are as defined
           in RFC 2253[68].

           The dn_length mode returns the number of RDN components in its DN
           argument; -1 is returned if the argument is not a valid DN. The
           dn_index mode returns the nthRDN component of the DN, where nth is
           an integer greater than zero. If nth is greater than the number of
           components, the last component is returned.

           The rdn_length mode returns the number of AttributeTypeAndValue
           elements in its RDN argument; -1 is returned if the argument is not
           a valid RDN. The rdn_index mode returns the
           nthAttributeTypeAndValue component of the RDN, where nth is an
           integer greater than zero. If nth is greater than the number of
           components, the last component is returned.

           The rdn_attrtype mode returns the AttributeType of the
           nthAttributeTypeAndValue component of the RDN, where nth is an
           integer greater than zero. If nth is missing, it is taken to be 1.
           If nth is greater than the number of components, the last component
           is selected. The rdn_attrvalue mode is similar except that it
           returns the AttributeValue.

           The first and second expressions below return 2, the third
           expression returns Administrator:

               ldap(dn_length, "dc=example,dc=com")
               ldap(rdn_length, "foo=bar+bar=baz")
               ldap(rdn_attrvalue, ldap(dn_index, \
                   "CN=Administrator,CN=Users,DC=example,DC=com", 1))


       length(string)
       length(bstring)
       length(list)
       length(alist)
           This function returns the length, in characters, of string, the
           number of bytes in binary string bstring, the number of elements in
           list, or the number of pairs in alist.

       list([value [, ...])
           This function is equivalent to the list construction operator[69].

               list(1, 2, [hello, world], 5)

           is equivalent to the expression:

               [1, 2, [hello, world], 5]


       listref(list, list-ref [, ...])
           This function provides an alternate syntax to the language's
           list/array notation. For example, the function call:

               listref([1, 2, [3, 4], 5], 2, 1)

           is equivalent to the expression:

               [1, 2, [3, 4], 5][2][1]

           Note that a list reference may follow a list-valued expression
           (e.g., a list constructor, a list-valued variable, a function that
           returns a list) this syntax is valid:

               ($a . $b)[0]

           The parentheses are necessary here because the subscript binds more
           tightly than the concatenation operator. This expression can also
           be written as:

               listref($a . $b, 0)


       on_success(list-name [, expr])
           The list-name argument must be either acs or auth (case
           insensitive) to select the post-authorization list or the
           post-authentication list, respectively. For the former case, if
           authorization is successful, the expr argument (a string) will be
           evaluated by dacs_acs immediately after any ACS_SUCCESS[31]
           directive, and just prior to program termination. These expressions
           are not evaluated if authorization is denied, an authorization
           processing error occurs, or a DACS_ACS argument prevents execution
           of the request. For the latter case, if authentication is
           successful, the expr argument (a string) will be evaluated by
           dacs_authenticate(8)[9] immediately after any AUTH_SUCCESS[30]
           directive, and just prior to program termination. These expressions
           are not evaluated if authentication fails or an authentication
           processing error occurs.

           Once added to either list, an entry cannot be removed. The
           expressions are evaluated in the order in which on_success() was
           called. The values returned by the expressions are discarded and
           errors are ignored.

           If no expr is given, the current list of expressions is returned,
           one per line, in order of evaluation. With an expression argument,
           it returns the number of expressions in the list after any
           addition.

       password(op [, op-args])
           This function performs a variety of read-only operations on DACS
           accounts and their passwords. See dacspasswd(1)[70] and directives
           PASSWORD_DIGEST[71] and PASSWORD_SALT_PREFIX[72] for additional
           information.

           The following operations are available:

           password(check, given-password, password-digest [,alg-name])
               With the check operation, the digest of given-password is
               computed (as computed by the hash operation) and compared to
               password-digest, which was previously generated by the hash
               operation of this function, retrieved by the getdigest
               operation, or obtained using dacspasswd. This algorithm is
               identical to the one used by local_passwd_authenticate[73] to
               validate passwords. If alg-name is given, it names the digest
               algorithm to use instead of the one specified within
               password-digest. If given-password is correct (i.e., the same
               passwords were used to generate the two digest values), True
               (1) is returned, otherwise False (0) is returned.

           password(getdata, username [,vfs-ref])
               The getdata operation returns the private data associated with
               the account for username. The result is a bstring. If there is
               no private data, the length of the result will be zero (the
               length of the empty string is one). If a vfs-ref is given, it
               identifies the virtual filestore to use, otherwise the item
               type passwds is used. It is an error if the account does not
               exist, so a test operation will often be performed first.

           password(getdigest, username [,vfs-ref])
               The getdigest operation is similar to getdata except that the
               digest string for the account is returned; this digest string
               can be used with the check operation.

           password(hash, plain-password [,alg-name])
               With the hash operation, a digest of the string plain-password
               is returned as a printable string. The password hashing
               algorithm is identical to the one used by dacspasswd(1)[70]. If
               alg-name is given (see digest()[63]), it names the digest
               algorithm to use instead of the configured default.

           password(list [, vfs-ref])
               The list operation returns a list of account names, one per
               line. An empty string is returned if there are no accounts. If
               a vfs-ref is given, it identifies the virtual filestore to use,
               otherwise the item type passwds is used. To test if a password
               file exists, use vfs()[74].

           password(syntax, password [,constraints])
               The syntax operation tests if password satisfies the
               constraints argument, if provided, otherwise the value of the
               PASSWORD_CONSTRAINTS[75] directive. The constraints are
               specified in the same syntax as the PASSWORD_CONSTRAINTS
               directive. The function returns True (1) if the constraints are
               satisfied, otherwise False (0).

           password(test, test-op, username [,vfs-ref])
               The test operation applies test-op to the account entry for
               username in the virtual filestore vfs-ref (or item type
               passwds). It is an error if the password file does not exist or
               is unreadable. It returns True if the test is successful,
               otherwise the result is False. The recognized values of test-op
               are (case insensitively): data (to test if the account exists
               and has private data), disabled (to test if the account exists
               and is disabled), enabled (to test if the account exists and is
               enabled), or exists (to test if the account exists).

           Examples:

               > password(hash, "bobo")
               "2|XYZZYxBhU/7VgJAt2lc.G|HL4RQ2vo0uNoXlXnv.GcY3Vlf9."
               > password(check, "bobo", "2|XYZZYxBhU/7VgJAt2lc.G|HL4RQ2vo0uNoXlXnv.GcY3Vlf9.")
               1


       pathname(path, hostname, port)
           Perform string interpolation on path based on the other arguments.
           For details, please see dacs.conf(5)[76] (where hostname is
           SERVER_NAME).

       pbkdf2(password, salt, count, dklen)
           Apply a pseudorandom function (HMAC-SHA-1) to password and salt
           (both binary strings, or converted as required), modified by count
           iterations, returning a binary string of length dklen bytes. For
           details, please see RFC 2898[77] and RFC 3962[78].

               > pbkdf2("password", "ATHENA.MIT.EDUraeburn", 1200, 32)
               "5c08eb61fdf71e4e4ec3cf6ba1f5512ba7e52ddbc5e5142f708a31e2e62b1e13"
               > pbkdf2("password", decode(hex,"1234567878563412"), 5, 16)
               "d1daa78615f287e6a1c8b120d7062a49"


       print(...)
           Each argument is converted to a string, the strings are
           concatenated, a newline is appended, and the result is printed. The
           return type is void. If called from dacsexpr(1)[1], the string is
           printed to the standard output; otherwise, it is printed to the
           DACS log file (or stderr), which can be useful for debugging
           purposes. These log messages are associated with the user class
           (see the LOG_FILTER[79] directive).

       printf(fmt, ...)
           This is a slightly scaled-down version of the printf(3)[54] library
           function. If called from dacsexpr(1)[1], the string is printed to
           the standard output; otherwise, it is printed to the DACS log file
           (or stderr), which can be useful for debugging purposes. These log
           messages are associated with the user class (see the LOG_FILTER[79]
           directive). This can be useful for debugging purposes. If necessary
           and possible, arguments are converted to the type requested by a
           formatting specification. The return type is void.

       random(bytes, nbytes)
       random(uint, lo, hi)
       random(string, nbytes [, spec])
       random(stringc, nbytes, spec)
           The various forms of this function, distinguished by the first
           argument, return cryptographically strong pseudo-random values[80]
           in various formats. The starting point (seed value) for the
           pseudo-random sequence cannot be set, meaning that the sequence
           cannot be (intentionally) reproduced.

           The bytes operation requests nbytes bytes of random material. The
           result is a bstring of that length.

           The uint operation requests an unsigned random integer between lo
           and hi (both unsigned integers), inclusive. It is an error if lo is
           not greater than hi. The result is an (unsigned) integer.

           The string operation requests nbytes of random material, returned
           as a hex-encoded string. If a spec argument is present, it uses the
           character specification syntax of strtr()[81] to indicate the
           characters that can be used to encode the result. Only printable
           characters, excluding the space, are allowed in the result,
           regardless of the spec argument. Example:

               > random(string,12,"a-zA-Z0-9")
               "LgROshy6SMMH"
               > random(string,12,"a-z")
               "kehhvwydhhbk"

           The functionality of the stringc operation is identical to that of
           the three-argument instance of the string operation except that the
           sense of the spec argument is complemented to indicate those
           characters that may not be used in the encoding of the result.

       redirect(error-code, target)
       redirect(target)
           Permitted only within the context of an access control rule's deny
           clause, this function causes expression evaluation and rule
           processing to stop immediately, access to be denied, and the client
           to be redirected to target, a URL that may contain a query
           component. If the error-code is present, it must be an ACS error
           name or number (see the ACS_ERROR_HANDLER[82] directive), otherwise
           "BY_REDIRECT" is used.

               Note
               The URL must be properly escaped if it appears within an XML
               document, such as an access control rule; for example, if an
               ampersand occurs in the query component in a context where it
               must be escaped, it must appear as the five characters "&amp;".
           The target string is expected to have one of the syntaxes of the
           document component of Apache'sErrorDocument directive[83]. In
           essence, this function causes an ACS_ERROR_HANDLER directive to be
           created and triggered. The function returns the target string,
           although because of the function's run time behaviour the value
           cannot be used.

               Tip
               One application of this function is to create a short link,
               which is a relatively concise URL that acts as an "alias" for
               another, usually much longer URL (here, the target). The short
               link is made public. It must be DACS-wrapped; the target does
               not need to be. Any attempt to access the short link is denied
               by its rule, but the rule uses the redirect() function,
               probably with BY_SIMPLE_REDIRECT as the error-code (see
               dacs.conf(5)[82]), to redirect the user agent to the target.

               The following rule demonstrates how this can be done:

                   <acl_rule status="enabled">
                    <services>
                     <service url_pattern="/id/*"/>
                    </services>

                    <rule order="allow,deny">
                     <deny>
                       setvar(split, "X", ${Env::REQUEST_URI}, "/");
                       ${x} = var(get, X, ${X::#} - 1);
                       redirect(BY_SIMPLE_REDIRECT, "https://example.com/docs/${x}.html");
                     </deny>
                    </rule>
                   </acl_rule>

               With this rule in place, a request like:

                   https://example.com/id/17795821

               would result in a redirect to this target:

                   https://example.com/docs/17795821.html

               The target URL can depend on contextual elements, and it is
               straightforward to do things like make the target URL depend on
               the time of day, identity of the user, and so on. The technique
               can also be used with Rlinks[84].

               Because the rule associated with the short link can be changed
               at any time, this feature can be used to implement smart
               permalinks[85].

       regmatch(string, regex [, namespace] [, nocase])
           This is a pattern matching function. The first two arguments are
           coerced to strings, with the second one taken to be the regular
           expression, with a "^" (the start-of-string anchor) implicitly
           prepended. The string argument is then matched against the regular
           expression, which may contain subexpressions enclosed between '('
           and ')' (or '\(' and '\)'). If the match fails, the result is 0. If
           the match succeeds there are several possibilities:

           •   if there are no subexpressions in regex, the result is an
               integer that is the number of characters matched.

           •   if there is at least one subexpression in regex but no
               namespace (a string argument) is given, the result is the
               substring of string that was matched by the entire regular
               expression.

           •   if there is at least one subexpression in regex and a namespace
               argument is given, the result is an integer that is the number
               of characters matched by the entire regular expression. The
               value of the first matching subexpression is assigned to the
               variable named "1" in the namespace, the value of the second
               subexpression is assigned to a variable named "2" in the
               namespace, and so on up to the ninth subexpression. The
               variable named "0" in the namespace is assigned the substring
               of string that was matched by the entire regular expression.
               Following function evaluation in the context of ACL rule
               processing, namespace is accessible only within the predicate,
               allow, or deny element in which it appears.

           If the optional nocase literal argument is given, then matching is
           done case-insensitively. Only one parenthesized pair can be used.
           IEEE Std 1003.2 ("POSIX.2") "extended" regular expressions are
           supported (regex(3)[86], re_format(7)[87]).

           Examples:

               > ${X} = "abfoo"
               "abfoo"
               > regmatch(${X}, ".*foo", nocase)
               5
               > regmatch("abcdefgzz", "(.*)g")
               "abcdefg"
               > regmatch("foo", "(bar)|(baz)|(foo)")
               "foo"
               > regmatch("abcdefgzz", "ab(.*)efg(.*)", "x")
               9
               > ${x::0}
               "abcdefgzz"
               > ${x::1}
               "cd"
               > ${x::2}
               "zz"
               > $addr = "192.168.7.3"
               "192.168.7.3"
               > regmatch($addr, "192\\.168\\.(.*)\\..*", "X")
               11
               > ${X::1}
               "7"


       regsub(string, regex, replacement [, nocase] [,repeat])
           This function matches regex against string, like regmatch()[61]
           does, and returns the string that results when the substitution
           specified by replacement is applied to the matched text. This is
           similar to the ed/vi/sed command "s/regex/replacement/" applied to
           string. If no match is found, the empty string is returned.

           The optional repeat literal argument causes the replacement to be
           applied to all matches; i.e., like the ed/vi/sed command
           "s/regex/replacement/g".

           Examples:

               > regsub("hello world", "world", "auggie")
               "hello auggie"
               > regsub("hello world", "auggie", "world")
               ""
               > regsub("hello", ".*", "& &")
               "hello hello"
               > regsub("one two three", "(.*) (.*) (.*)", "\${3} \${2} \${1}")
               "three two one"
               > regsub("one two three", "(.*) (.*) (.*)", '${3} ${2} ${1}')
               "three two one"
               > strtr(regsub("https://BOB.Example.com",
                   "\([^:]*\)://\([^.]*\)\\.\(.*\)", '${1}-${2}@${3}'),
                     "A-Z", "a-z")
               "https-bob@example.com"
               > regsub("one, bone, cone, hone", "one", "two", repeat)
               "two, btwo, ctwo, htwo"


       request_match(uri-string)
           This function is used to inspect the current request. The argument
           is either a valid URI or a path component that begins with a slash.
           In the latter case, the scheme and authority components of the
           current request are effectively prepended to the given path. The
           path component is like the url_pattern attribute used in access
           control rules[88] in that it can either specify an exact match or,
           by ending in "/*", a wildcard match. A query component is allowed
           but ignored. The function returns 0 if uri-string does not match
           the current request, otherwise it returns the number of path
           components of uri-string that match the current request. If the
           scheme and authority components are given in uri-string, they count
           as one naming component.

           Assuming that the current request is
           http://example.com:18123/a/b/c, we get:

               > request_match("http://example.com:18123/a/b/c")
               4
               > request_match("https://example.com:18123/a/b/c")
               0
               > request_match("http://example.com:18123/a/b/c/d")
               0
               > request_match("http://example.com:18123/a/b")
               0
               > request_match("http://example.com:18123/a/b/*")
               4
               > request_match("http://example.com:18123/*")
               2
               > request_match("http://example.com:18123")
               0
               > request_match("http://example.com")
               0
               > request_match("http://example.com/*")
               2
               > request_match("/*")
               1
               > request_match("/a/b/c")
               3
               > request_match("/a/b/*")
               3
               > request_match("/")
               0


       return(result)
           Equivalent to exit, this function causes evaluation of the
           expression to terminate and returns result as the value of the
           expression.

       rule(object, ruleset_vfs)
           The rule predicate is an interface to the DACS rule processing
           engine. It is used to test if the rule set ruleset_vfs authorizes
           object, much as dacscheck(1)[37] does. The object argument is the
           name to match against the services specified in access control
           rules and can either be a URI or an absolute pathname (one that
           begins with a slash character). It can have an optional query
           string component attached. An absolute pathname path is mapped
           internally to a URI as file://path; e.g., /myapp is interpreted as
           file:///myapp (see RFC 1738[45]).

           One application of this predicate is for a rule associated with a
           program to check that the user requesting access is entitled to use
           a data file needed by the program.

               Note
               Only the path component of the URI is considered when DACS
               matches an object's name against the url_pattern of an access
               control rule. At present, the object name is not automatically
               canonicalized or resolved (see RFC 3986[47]), as is usually
               done by a web server, so relative path components such as "."
               and ".." should be avoided.
           The ruleset_vfs is a URI in the syntax of the VFS[26] configuration
           directive.

           The various components of the URI that names the object are
           available as DACS variables and environment variables (see below).
           If a query string is given, it is parsed and the individual
           arguments are made available to rules through the Args namespace,
           just as for DACS-wrapped web services.

           Many variables normally set by a web server are instantiated based
           on the object name and the execution environment. These variables
           are available in the DACS namespace. For example, if the object
           name is https://example.com:8443/myapp/edit-menu?entry=item1, the
           following variables will be set as indicated:

               ${DACS::HTTPS}=on
               ${DACS::SERVER_NAME}=example.com
               ${DACS::SERVER_ADDR}=142.179.101.118
               ${DACS::HTTP_HOST}=example.com:8443
               ${DACS::SERVER_PORT}=8443
               ${DACS::REQUEST_URI}=/myapp/edit-menu
               ${DACS::DOCUMENT_ROOT}=/
               ${DACS::REQUEST_METHOD}=GET
               ${DACS::SERVER_SOFTWARE}=dacsexpr-1.4.14
               ${DACS::QUERY_STRING}=entry=item1
               ${DACS::ARG_COUNT}=1
               ${DACS::CURRENT_URI}=/myapp/edit-menu?entry=item1
               ${DACS::CURRENT_URI_NO_QUERY}=/myapp/edit-menu

           The value of ${Args::entry} will be item1. The request method is
           always GET. The variable ${DACS::REMOTE_USER} will be set if
           credentials are available in the execution environment.

           For example, assuming that the file
           /usr/local/exams/acls/acl-exams.17 contains:

               <acl_rule status="enabled">
                 <services>
                   <service url_pattern="/exam1.html"/>
                 </services>

                 <rule order="allow,deny">
                   <precondition><predicate>
                     ${Args::user} eq "teacher"
                   </predicate></precondition>

                   <allow>
                     time(hour) eq 17
                   </allow>
                 </rule>
               </acl_rule>

           The following call would only return True (1) any day between
           5:00pm and 5:59pm:

               rule("/exam1.html?user=teacher", "dacs-fs:/usr/local/exams/acls");


               Note
               •   Since any rule can call the rule function, take care to
                   avoid infinite recursion.

               •   Although this function is similar in concept to the
                   dacscheck(1)[37] command, there are some significant
                   differences, particularly with respect to the context
                   available during rule evaluation.

               •   The Env namespace is not reinitialized or altered during
                   evaluation of rules processed by rule. That is, the Env
                   namespace is the same as the outer-most one.

       setvar(op, dst-namespace [, args ...])
           This function, which performs various operations on namespaces, has
           several different syntaxes. The first argument always specifies the
           operation (case insensitively) and determines the meaning of the
           arguments that follow it. The second argument always specifies a
           namespace that is created or modified. If successful, the function
           returns the number of variables created (or replaced) in
           dst-namespace.

           The dst-namespace cannot be a read-only namespace[89]. Unless
           otherwise specified, if dst-namespace exists, variables are added
           to it, with any existing variable assigned its new value.

           The following operations are recognized:

           setvar(authorization, dst-namespace, auth-str)
               The auth-str argument, which is the value of an Authorization
               HTTP request header, is parsed into its component fields and
               assigned to variables in the destination namespace
               dst-namespace. If dst-namespace exists, its contents are
               deleted first. Corresponding to the field names used in RFC
               2617[90] Section 3.2.2, the following variables are created:
               AUTH_SCHEME, USERNAME, PASSWORD, REALM, NONCE, DIGEST_URI,
               RESPONSE, ALGORITHM, CNONCE, OPAQUE, MESSAGE_QOP, NONCE_COUNT,
               and AUTH_PARAM. Any variable that corresponds to a non-existent
               field is assigned the empty string.

               The following call sets ${Foo::AUTH_SCHEME} to Basic,
               ${Foo::USERNAME} to Bobo, and ${Foo::PASSWORD} to myPassWord.

                   setvar(authorization, Foo, "Basic Qm9ibzpteVBhc3NXb3Jk")


           setvar(copy, dst-namespace, src-namespace)
               With the copy operation, all variables in an existing namespace
               src-namespace are copied to dst-namespace. If the latter
               exists, its contents are deleted, otherwise the namespace is
               created.

           setvar(delete, dst-namespace)
               The delete operation is used to delete dst-namespace and its
               contents.

           setvar(kwv, dst-namespace, assign-char, sep-chars, string)
               For the kwv operation, string is parsed, creating (or
               replacing) variables in dst-namespace. The string consists of
               zero or more keyword/value pairs. The keyword, which is used as
               the variable name, is separated by the value by the character
               assign-char. A keyword/value pair is separated from the next by
               any character that appears in sep-chars. Here is an example:

                   setvar(kwv, "Foo", "=", ", ", "a=b, c=d, e=f")

               The value of this call is 3 and it sets ${Foo::a} to "b",
               ${Foo::c} to "d", and ${Foo::e} to "f".

           setvar(load, dst-namespace, filename)
           setvar(load, dst-namespace, item_type, key)
           setvar(load, dst-namespace, vfs-ref, key)
               The contents of a text object, which can be specified using a
               filename, as an item_type, or using a vfs-ref (see vfs()[74]),
               is split into newline separated lines. The first line is
               assigned index 0 in dst-namespace, the second index 1, and so
               on.

               Consider the following example:

                   > setvar(load, PASSWD, "/etc/passwd")
                   25
                   > ${PASSWD::2}
                   "root:*:0:0:Charlie &amp;:/root:/bin/csh"

               Here, there are 25 lines in /etc/passwd and the third line is
               printed.

           setvar(loadi, dst-namespace, vfs-ref)
               Each item in the indexed text object specified by vfs-ref (an
               absolute pathname, an item type, or a VFS URI[26]) is copied to
               dst-namespace, with the same index. The index must be a valid
               variable-name.

                   > setvar(loadi, PASSWD, "dacs-kwv-fs:/etc/passwd")
                   23
                   > ${PASSWD::root}
                   "*:0:0:Charlie &amp;:/root:/bin/csh"
                   > ${PASSWD::bobo}
                   "bobo:*:1001:1001:Bobo &amp;:/home/bobo:/bin/tcsh"

               Here, 23 items are copied into the PASSWD namespace (the first
               two lines in this particular /etc/passwd are ignored because
               they are comments that are not recognized as items). The lines
               indexed by the keys root and bobo are printed.

           setvar(merge, dst-namespace, src-namespace)
               The merge operation is similar to copy[91] except that if
               dst-namespace exists its contents are not deleted.

           setvar(post, dst-namespace [, content-type, string])
               Like query[92], this operation parses its input into arguments
               in dst-namespace. The function reads its standard input, unless
               a string argument is given. The input is expected to be a
               correctly formatted application/x-www-form-urlencoded or
               multipart/form-data content type. If the standard input is
               read, both the CONTENT_TYPE and CONTENT_LENGTH environment
               variables must be set (as they are when Apache runs a script
               that is passed an entity-body).

               The form that takes string is not yet implemented.

           setvar(query, dst-namespace, query-string)
               For the query operation, query-string is parsed, creating
               variables in dst-namespace. This uses the same parsing
               algorithm employed by cgiparse(8)[93]. In the case of a
               malformed query string, like "a&b", variables will be created
               but will have the empty string as their value. If successful,
               the function returns the number of variables created. The
               following call returns 3 and sets ${Foo::a} to "b", ${Foo::c}
               to "d", and ${Foo::e} to "f":

                   setvar(query, "Foo", "a=b&c=d&e=f")

               One application of this function it to distinguish query
               arguments (which are part of the requested resource's URI and
               made available through the environment variable QUERY_STRING)
               from arguments supplied in the body of a POST method (or other
               such method). For example:

                   setvar(query, "Qargs", "${Env::QUERY_STRING}")
                   if (${Qargs::foo:e}) {
                       /* "foo" is a query argument */
                   }
                   else {
                       /* "foo" is not a query argument */
                   }

                   if (${Args::foo:e} and not ${Qargs::foo:e}) {
                       /* "foo" is a POST argument */
                   }
                   else {
                       /* "foo" is not a POST argument */
                   }


           setvar(regsplit, dst-namespace, string, delimiter-regex [,limit])
               The regsplit operation is similar to split[94] except that
               substrings are separated by the regular expression
               delimiter-regex. IEEE Std 1003.2 ("POSIX.2") "extended" regular
               expressions are used (regex(3)[86]).

           setvar(rename, dst-namespace, src-namespace)
               The rename operation deletes dst-namespace, if it exists, and
               changes the name of src-namespace to dst-namespace. The two
               namespace arguments must be different.

           setvar(split, dst-namespace, string, delimiter [,limit [,dflag]])
               The split operation extracts substrings from string. Substrings
               are separated by the string delimiter. For example, this call
               separates a composite role string into individual basic roles:

                   setvar(split, "ROLES", ${DACS::ROLES}, ",")

               If the variable reference ${DACS::ROLES} has the value
               "root,wheel,www,users", then the example would return 4 and set
               ${ROLES::0} to "root", ${ROLES::1} to "wheel", and so on.

               If a limit is given, it is an integer that specifies the
               maximum number of substrings to extract. Once the maximum has
               been reached, the remainder of string that has not been split
               will be assigned to the last element. A limit of zero is
               equivalent to the default, which is for there to be no maximum.
               For instance, setvar(split, X, "a,b,c,d", ",", 2) will assign
               "a" to ${X::0} and "b,c,d" to ${X::1}.

               Here is another example:

                   > setvar(split, "X", "a\nb\nc\n", "\n")
                   "3"
                   > ${X::0}
                   "a"
                   > ${X::#}
                   "3"

               This function can be used to break a pathname into its
               individual components. For instance, the following call results
               in ${X::0} set to the empty string, ${X::1} set to "a", ${X::2}
               set to "long", and ${X::3} set to "path":

                   > setvar(split, "X", "/a/long/path", "/")
                   4

               (You may need to first remove redundant slashes in string using
               strtr()[81].)

               A dflag argument may follow the limit argument to indicate
               whether delimiter should not be included in substrings (dflag
               == 0, which is the default behavior), whether it should be
               included at the start of substrings with the possible exception
               of the first one (dflag > 0), or whether it should be included
               at the end of substrings with the possible exception of the
               last one (dflag < 0).

                   > setvar(split, P, "/a/long/path", "/", 0, 1)
                   3
                   > ${P::0}
                   "/a"
                   > ${P::1}
                   "/long"
                   > ${P::2}
                   "/path"
                   > setvar(split, P, "/a/long/path", "/", 0, -1)
                   4
                   > ${P::0}
                   "/"
                   > ${P::1}
                   "a/"
                   > ${P::2}
                   "long/"
                   > ${P::3}
                   "path"


           setvar(uri, dst-namespace, uri)
               The given uri, a URI conforming to RFC 2396[46] or RFC
               3986[47], is parsed into its components. Variables in
               dst-namespace are set accordingly: SCHEME (mapped to lower
               case), HOST (mapped to lower case), AUTHORITY, PORT, SERVER,
               USERINFO, PATH, QUERY, and FRAGMENT. If a component is absent
               from uri, the corresponding variable will not be defined.

                   Security
                   It is possible for USERINFO to include a plaintext
                   password.
               In addition, the URI's path component is split into its
               slash-delimited pieces. The variable PATH_LENGTH is set to the
               number of such pieces (it will be zero if there are none), and
               variables PATH_0, PATH_1, and so on are set to the first,
               second, and successive pieces. An "empty" path component is
               treated as a piece consisting of the empty string.

                   > setvar(uri, "X", "https://bar@foo.example.com:8443/cgi-bin/prog?a=17")
                   11
                   > info(namespace,X)
                   "SCHEME="https"
                   AUTHORITY="bar@foo.example.com:8443"
                   HOST="foo.example.com"
                   PORT="8443"
                   SERVER="foo.example.com:8443"
                   USERINFO="bar"
                   PATH="/cgi-bin/prog"
                   PATH_COUNT="2"
                   PATH_0="cgi-bin"
                   PATH_1="prog"
                   QUERY="a=17"
                   "



       sizeof(typename)
           This function returns the amount of memory in bytes, as an integer,
           used by typename, the name of a basic data type[21]. For the string
           and binary types, the returned value is the number of bytes used by
           each element of that type (1, typically). To find the number of
           elements in string or binary data, use length()[15].

               > sizeof(real)
               8


       sleep(seconds)
           The process is suspended for approximately seconds seconds, or
           until a signal is received and caught or the process terminated. It
           returns the "unslept" number of seconds, which will be zero if the
           process slept for the requested interval. This is an interface to
           sleep(3)[95]. It can be useful for inserting delays in conjunction
           with error handlers, for instance.

       source(vfs-ref [,key])
           The expressions in the file or item specified by vfs-ref, which may
           be followed by a key if it is an indexed filestore, are read and
           evaluated as a block. The vfs-ref can be an absolute pathname, an
           item type, or a VFS URI[26]. The value returned is that of the
           evaluated block. The following two expressions are essentially
           equivalent:

               source("/usr/local/dacs/scripts/script17")
               eval(get("/usr/local/dacs/scripts/script17"))

           This function is handy when a lengthy expression is needed but one
           does not want to clutter a configuration file or a rule.

       sprintf(fmt, ...)
           This is a slightly scaled-down version of the sprintf(3)[96]
           library function. If necessary and possible, arguments are
           converted to the type requested by a formatting specification. The
           formatted string is returned.

               ${a} = sprintf("Hello") . ", world."
               "Hello, world."
               length(sprintf("Hello") . ", world.")
               13


       strchars(str, range-spec [,...])
           This function returns a new string by selecting characters from str
           according to a sequence of one or more range specifications (each
           one a range-spec). A range-spec is a string argument that
           determines the indexes of characters to select within str. Indexes
           start at zero. The result of each successive range specification is
           appended to the previous result.

           A range-spec is an unordered set of one or more comma-separated
           elements, each of which is either an index or a range. An index may
           either be a non-negative integer or "#", which means "all indexes".
           A range represents a sequence of indexes and has the syntax:

               range-start ".." range-end

           A range-start may be a non-negative integer, the character "#"
           (which means "from the beginning"), or may be elided (also meaning
           "from the beginning"). A range-end may be a non-negative integer
           (not less than range-start, if it is also a non-negative integer),
           the character "#" (which means "to the end"), or may be omitted
           (also meaning "to the end").

               > $a = "abcdef"
               "abcdef"
               > strchars($a, 2)
               "c"
               > strchars($a, "1..4", "0")
               "bcdea"
               > strchars($a . $a, "5..#")
               "fabcdef"
               > strchars($a, "#")
               "abcdef"
               > strchars($a, "#..#")
               "abcdef"
               > strchars($a, "#..3")
               "abcd"
               > strchars($a, "..3")
               "abcd"
               > strchars($a, "..3", "#")
               "abcdabcdef"


       strchop(str, del-spec)
           This function deletes from the end of str a continuous run of any
           characters in del-spec.

               > strchop("foo4.859", ".56789")
               "foo4"
               > strchop("foo7.859", ".5679")
               "foo7.8"
               > strchop("hello    ", " ")
               "hello"
               > strchop("dogs rule\n\n", "\n")
               "dogs rule"


       strftime(format)
           This function is an interface to the strftime(3)[97] function. It
           is applied to the current date and time.

       strptime(date-str, date-format, namespace)
       strptime(namespace)
           This function is an interface to the strptime(3)[98] function. The
           date-str argument is a string representation of a date and/or time,
           with date-format describing its syntax. If the parse of date-str
           succeeds, the following elements of namespace are set from the
           corresponding fields of struct tm: tm_sec, tm_min, tm_hour,
           tm_mday, tm_mon, tm_year, tm_wday, tm_yday, tm_isdst, tm_zone, and
           tm_gmtoff. Additionally, a variable named clock is set to the Unix
           time that corresponds to the parsed date and time. Any existing
           elements of namespace are not modified. If date-str does not fully
           describe a date and time, it is taken to be relative to the current
           date and time (e.g., if only a time is given, "today's date" is
           used).

           In the single-argument usage, the current date and time are parsed
           and namespace is assigned values as previously described.

           The return value is the "Unix time" equivalent of the resulting
           time and date.

               > strptime("6 Dec 2001 12:33:45", "%d %b %Y %H:%M:%S", tm)
               1007670825
               > "${tm::tm_mon} ${tm::tm_mday} ${tm::tm_hour} ${tm::tm_min}"
               "11 6 12 33"
               > ${tm::clock}
               1007670825


       strrstr(string, substring [, nocase])
           Return the start of the last occurrence of substring within string.
           The empty string is returned if string is empty or if no occurrence
           of substring is found. If substring is empty, string is returned.
           The optional nocase literal argument requests case-insensitive
           comparison.

               > strrstr("afoofoofooz", "foo")
               "fooz"
               > strrstr("afOOfoofooz", "FooF", nocase)
               "foofooz"
               > strrstr("afOOfoofooz", "ofoo",nocase)
               "ofooz"


       strstr(string, substring [, nocase])
           Return the start of the first occurrence of substring within
           string. The empty string is returned if string is empty or if no
           occurrence of substring is found. If substring is empty, string is
           returned. The optional nocase literal argument requests
           case-insensitive comparison.

               > strstr("foobazbar", "baz")
               "bazbar"
               > strstr("foobazbar", "")
               "foobazbar"
               > strstr("foobazbar", "zzz")
               ""
               > strstr("", "zzz")
               ""
               > strstr("afoofoofooz", "foo")
               "foofoofooz"
               > strstr("fooZbar", "Ozb", nocase)
               "oZbar"


       strtolower(string)
           A new string is returned where each uppercase character in string
           is mapped to lowercase and all other characters are mapped to
           themselves. These two expressions are equivalent and have the value
           "hello, world 2008":

               strtolower("Hello, World 2008")
               strtr("Hello, World 2008", "A-Z", "a-z")


       strtoupper(string)
           A new string is returned where each lowercase character in string
           is mapped to uppercase and all other characters are mapped to
           themselves. These two expressions are equivalent and have the value
           "HELLO, WORLD 2008":

               strtoupper("Hello, World 2008")
               strtr("Hello, World 2008", "a-z", "A-Z")


       strtr(input-string, string1, [string2 [,cds]])
           This function performs string transliteration, like the tr(1)[99]
           command and Perl's tr and y operators. The result is the
           transliterated string. The first argument is the input string to be
           transliterated (stdin in the tr command). The second argument is
           the search list ("string1" in the tr command). The third argument
           is the (possibly empty) replacement list ("string2" in the tr
           command); it may be omitted if no flag string argument follows.

           The fourth, optional argument is a literal flag string made of the
           characters 'c', 'd', and 's' (in any order), which correspond to
           the flags of the same name in the tr command:

           c
               Complement the set of values in string1.

           d
               Delete characters in string1 from the input string.

           s
               Squeeze multiple occurrences of the characters listed in the
               last operand (either string1 or string2) in the input into a
               single instance of the character. This occurs after all
               deletion and translation is completed.


               > strtr("AbCdEf", "A-Z", "a-z")
               "abcdef"
               > strtr("/a//b///c", "/", "", "s")
               "/a/b/c"


       subset(format, purported-subset, superset [, nocase])
           This function returns True if every element of the purported-subset
           appears in superset. The format indicates how to parse the set
           arguments. It can be the space, tab, or newline character, or any
           punctuation character. It is currently interpreted as the character
           that separates elements. If the optional nocase literal argument is
           given, then set elements are compared case-insensitively.

           Example:

               subset(",", ${Args::LAYERS:i}, "RELIEF:Foundation,GTOPO30:Foundation")

           This call returns True if every element of the LAYERS parameter
           (case insensitive) appears in the given list, otherwise the
           expression is False.

       substr(string, start-position, length)
           This function returns the substring of string beginning at
           start-position with length at most length characters. The first
           character is in position one. If start-position is negative, the
           position is relative to the end of string (-1 specifies the last
           character in string). If the effective starting position is outside
           of string, an empty string is returned. If length is negative, it
           means "the remainder of the string". It is an error if either
           numeric argument is zero. It is not an error if length exceeds the
           actual number of characters returned.

               > substr("foozle", 3, 4)
               "ozle"
               > substr("foobar", -3, 2)
               "ba"
               > substr("foobar", -5, -1)
               "oobar"
               > substr("foobar", 10, -1)
               ""
               > substr("foobar", -10, 3)
               ""


       syntax(type, name [, flag])
           This function performs a syntax test, specified by type, on name.
           It returns 0 if the test fails, 1 or a type-dependent, non-zero
           value if the test is successful. It can be useful for testing,
           catching errors, recognizing when a string must be mapped, and for
           learning about DACS. Note that these are purely syntactical checks.
           They do not test whether an object called name exists or is
           configured.

           The following tests are recognized:

           syntax(charset, name, charset_spec)
               Test if each of the characters in name is specified by
               charset_spec, which is a character set specification as used by
               strtr()[81] ("the search list").

           syntax(dacsname, name)
               Test if name is valid as a DACS name[100]. If the string is
               recognized, one of the following values is returned to classify
               it:

               •   1 if it is a DACS identity

               •   2 if it is a group name

               •   3 if it is a jurisdiction name

               •   4 if it is a federation name

               •   5 if it is an IP address in numeric dot notation


           syntax(emailaddr, name)
               Test if name is a syntactically valid RFC 822[101] email
               address. A successful test does not imply that a message can be
               delivered to the address.

                   Note
                   The implementation does not currently recognize valid
                   addresses where the local-part (the substring to the left
                   of the '@' character) contains a quoted-string component.

           syntax(expr, name)
               Test if name is a syntactically valid expression. The
               expression is not actually evaluated. A successful test does
               not imply that evaluation of the expression will necessarily be
               successful or error-free.

           syntax(domainname, name)
               Test if name is a syntactically valid domain name (RFC
               952[102]). A successful test does not imply that name exists or
               has a DNS entry.

           syntax(federation, name)
               Test if name is valid as a federation name (e.g., as the value
               of FEDERATION_NAME[103]).

           syntax(group, name)
               Test if name is valid as a group name.

           syntax(hostname, name)
               Test if name is valid as a host name (an alphanumeric, followed
               by any number of alphanumerics and hyphens, but not ending with
               a hyphen; see RFC 952[102] and RFC 1123[104]).

           syntax(ipaddr, name)
               Test if name is a valid Class C IPv4 address (RFC 790[105]).

           syntax(jurisdiction, name)
               Test if name is valid as a jurisdiction name (e.g., as the
               value of JURISDICTION_NAME[106]).

           syntax(namespace, name)
               Test if name is valid as the name of a namespace[22].

           syntax(role, name)
               Test if name is valid as a role descriptor string[100].

           syntax(uri, name)
               Test if name is a valid URI (RFC 2396[46], but partially RFC
               3986[47]). It must consist of a scheme, authority component,
               path component, and optional query and fragment components.

           syntax(username, name)
               Test if name is valid as a username (e.g., as the value of the
               USERNAME argument to many DACS web services).

           syntax(variable, name)
               Test if name is valid as a variable reference[22]. This does
               not test if the named variable exists.

           syntax(varname, name)
               Test if name is a syntactically correct variable name[22], with
               or without a namespace. This does not test if the named
               variable exists.

               > syntax(federation, "FOO")
               1
               > syntax(dacsname, "FOO::BAZ:bar")
               1
               > syntax(dacsname, "FOO::")
               4
               > syntax(charset, "bobo17+", "a-z0-9")
               0
               > syntax(expr, '1 + 1 + 1')
               1
               > syntax(variable, '${1$}')
               0
               > syntax(variable, '${Foo::baz:z}')
               0
               > syntax(varname, 'Foo::baz')
               1
               > syntax(varname, "17")
               1
               > syntax(username, "/bobo/")
               0
               > syntax(group, "blop")
               1
               > syntax(group, "%blop")
               0
               > syntax(dacsname, "%blop:flop")
               1
               > syntax(uri,"https://foo.example.com:8443/cgi-bin/prog?a=17")
               1


       time(format [, timeval])
       time(format, namespace)
           This function returns time and date information, as specified by
           the first argument. The second argument, if present, either
           specifies the "Unix time" from which to obtain the time and date or
           a namespace that was returned by strptime()[107]. If the second
           argument is absent, the result is the same as if a second argument
           were given as time("now"). The localtime(3)[108] library function
           is used internally to perform the date calculations.

           The format argument, which is treated case-insensitively, can be
           any of the following:

           •   If the argument is "now", the function's value is the current
               "Unix time" (the value of time in seconds since 0 hours, 0
               minutes, 0 seconds, January 1, 1970, Coordinated Universal
               Time). If the second argument is present, however, it is the
               function's value.

           •   If the argument is "sec" or "secs" or "seconds", the function's
               value is the system clock's seconds reading.

           •   If the argument is "min" or "mins" or "minutes", the function's
               value is the system clock's minutes reading.

           •   If the argument is "hour", the function's value is the system
               clock's hour reading (0 - 23).

           •   If the argument is "mday", the function's value is the day of
               the month (1 - 31).

           •   If the argument is "ismdaylast", the function's value is
               non-zero if this is the last day of the month.

           •   If the argument is "mon" or "month", the function's value is
               the month of the year (0 - 11).

           •   If the argument is "year", the function's value is the year
               (from 1900 onward).

           •   If the argument is "isleapyear", the function's value is
               non-zero if this is a leap year.

           •   If the argument is "wday", the function's value is the day of
               the week (Sunday is 0).

           •   If the argument is "yday", the function's value is the day of
               the year (0 - 365).

           •   If the argument is "isdst", the function's value is non-zero if
               daylight saving time is in effect.

           •   If the argument is "zone", the function's value is system
               clock's time zone, abbreviated. If the time zone is not known,
               the value will be the empty string.

           •   If the argument is "gmtoff", the function's value is the offset
               (in seconds) of the system clock's time represented from UTC,
               with positive values indicating east of the Prime Meridian.


               Note
               A more powerful function is planned to test whether the current
               time and date satisfy a predicate. It might, for example,
               understand arguments such as "Tuesday" (True on any Tuesday),
               "last day of the month", "between midnight and 8:30am",
               "January 30, 2004 at 1:23pm", "between March 2 and April 1",
               "the second Tuesday of the month", or "within 15 days of April
               30".

       transform(input,name,rules,docs [,idents])
       transform(input,config,name,rules,docs [,idents])
           This function provides a simplified API for dacstransform(1)[109] -
           refer to its description for additional details. The first form of
           the function uses compile-time defaults, unless they are overridden
           by configuration variables (e.g., ${Conf::transform_prefix}). The
           second form passes a configuration object returned by
           transform_config()[110]. The input argument is the text to be
           passed through the function. The name argument is equivalent to the
           value of the dacstransform-name flag, rules is equivalent to the
           value of the -r flag, docs is equivalent to the value of the -docs
           flag, and the optional idents argument is a whitespace-separated
           list of identities in the concise user syntax[111]. The function
           returns the transformed input.

       transform_config(flags)
           This function returns a configuration object that is passed to
           subsequent calls to transform()[112] so that defaults can be
           overridden. The single string argument is parsed into
           whitespace-separated words. If a flag is repeated, the right-most
           occurrence is used.

           The following flags are recognized:

           •   -prefix prefix-string: The string used to introduce a
               directive, which must appear at the beginning of a line.

           •   -suffix suffix-string: The string used to end a directive.

           •   -rprefix regex-prefix: A line whose beginning matches the
               specified regular expression introduces a directive.

           •   -rsuffix regex-suffix: The end of a directive is found by
               matching the specified regular expression.


       trim(string, delete-set [,limit])
           Delete each character in delete-set that appears at the end of
           string, up to limit characters. The delete-set is a search list
           specification as used by strtr()[81]. If limit is missing or zero,
           all of the characters in string can potentially be deleted (leaving
           the empty string). The new string is returned.

               > trim("abceffff", "f")
               "abce"
               > trim("abceffff", abf)
               "abce"
               > trim("a\n\n\n", "\n")
               "a"
               > trim("a", "a-z")
               ""


       typeof([typename,] expression)
           If there are two arguments and the first is a recognized data type
           name[21], the return value is 1 (True) if expression has that type
           and 0 (False) otherwise. If there is one argument, the function
           yields a string that is the data type name of the evaluated
           expression.

               > typeof(4.5)
               "real"
               > typeof(integer, 4.5)
               0


       undef()
           This function returns a special value that represents the
           "undefined" value. It is used in certain circumstances to undefine
           a symbol. See dacs.conf(5)[10].

       user(string)
           This function compares its argument against each set of current
           credentials and returns the number of credentials that match. The
           argument is a user filter expression that must evaluate to True for
           a set of credentials for those credentials to match. See
           dacs(1)[100] for information about naming.

               Note
               In typical usage, each user will have only one set of
               credentials or will be unauthenticated. One should keep in
               mind, however, that multiple concurrent identities are allowed,
               subject to ACS_CREDENTIALS_LIMIT[113].
           The string argument (EXP) has the following syntax:

           Figure 2. User Filter Expression Grammar

               EXP -> E1
               E1  -> E2 | E2 OR E2
               E2  -> E3 | E3 AND E2
               E3  -> E4 | NOT E3
               E4  -> primary | "(" E1 ")"

               OR  -> "or"  | "||"
               AND -> "and" | "&&"
               NOT -> "not" | "!"

           Whitespace (spaces and tabs) is permitted before and after lexical
           elements. Keywords are case sensitive except when otherwise stated.

           A primary, which evaluates to True or False, is one of the
           following:

           username
               True if the DACS identity username matches.

                   user("METALOGIC:auggie")
                   user(":bobo")

               If the jurisdiction name or federation name components are
               omitted, the current federation and jurisdiction[100] are
               implied. The jurisdiction name component may be specified as
               "*" (e.g., *:username), in which case it will match any
               jurisdiction name in the current federation. In addition, both
               the federation name and the jurisdiction name components may be
               specified as "*" (e.g., *::*:username), in which case it will
               match any federation name and any jurisdiction name.

           jurisdiction
               True if jurisdiction matches the name of the jurisdiction that
               created the credentials.

                   user("METALOGIC:")
                   user("DEMO::METALOGIC:")


           federation
               True if federation matches the name of the federation that
               created the credentials.

                   user("DEMO::")


           address
               Given an argument acceptable to the from()[114] predicate, the
               result is True if the credentials were generated by a user
               apparently located at address.

                   user("10.0.0.123")
                   user("10.0.0.0/24")
                   user("example.com")


           group
               True if the identity is a member of group, which is a DACS
               group.

                   user("%METALOGIC:admin")

               A group name may reference an explicit group membership list or
               a role-based group. Also, it is possible for an explicit group
               membership list to have the same name as a role-based group; if
               the name is referenced in a rule, the rule processing engine
               will first check if the user is associated with the role. If
               he's not, it will go on to check for an explicit group
               membership list with the same name. This allows an
               administrator to easily supplement the membership associated
               with a role-based group. Refer to dacs.groups(5)[115].

           namespace ns
               The value of each element in ns (a namespace) is evaluated as a
               primary. The order in which the list is evaluated is
               unspecified. Processing of the list terminates with the first
               primary that evaluates to True or when the list is exhausted.
               This primary can appear in an element (so that one list can
               reference other lists) but beware of infinite recursion.

               For example, if /usr/local/dacs/app_users consists of
               usernames, one per line, an access control rule can grant
               permission to any of the users by having an allow element
               containing the statements:

                   setvar(load, APP_USERS, "/usr/local/dacs/app_users");
                   user("namespace APP_USERS")


           style style-list
               The keyword style is followed by a list of one or more
               comma-separated, case-insensitive style keywords, described
               below. Each style keyword may be abbreviated up to the
               indicated minimum number of initial characters. Every set of
               credentials has one or more styles[116] associated with it that
               indicate which authentication method or methods were
               successfully applied and how (by what means) the credentials
               were generated within DACS. A primary is True if the tested
               credentials satisfy all of the keywords in the style-list.

               For example, this expression tests if both the passwd and
               certificate styles are associated with it:

                   user("style passwd,cert")

               This is equivalent to the following expression, which tests if
               the user was authenticated via a username/password style of
               authentication and a valid X.509 client certificate was
               presented:

                   user("style passwd") and user("style CERT")

               The following style keywords are understood:

               acs
                   True if the credentials were created during an
                   authorization check by dacs_acs

               admin
                   True if the credentials were created for use internal to
                   DACS.

               alien
                   True if the credentials were imported by
                   dacs_auth_agent(8)[117] in its "alien" mode, or by
                   dacs_auth_transfer(8)[118].

               cas
                   True if the user was authenticated using CAS.

               cert[ificate]
                   True if the user authenticated using an X.509 certificate.

               digest
                   True if the user authenticated using RFC 2617[90] Digest
                   authentication.

               expr
                   True if the user was authenticated using an expression.

               gen[erated]
                   True if the credentials were generated by a DACS utility
                   (e.g., dacscookie(1)[119]).

               import[ed]
                   True if the credentials were imported by
                   dacs_auth_agent(8)[117] or dacs_auth_transfer(8)[118].

               infocard
                   True if the user was authenticated using an InfoCard.

               nat[ive]
                   True if the user was authenticated using the native
                   authentication style.

               managed_infocard
                   True if the user was authenticated using a managed
                   InfoCard.

               pass[word]
               passwd
                   True if the user authenticated using a password.

               prompt[ed]
                   True if the user was authenticated using the prompted
                   authentication style.

               rlink
                   True if the user was authenticated using an Rlink[84].

               selfissued_infocard
                   True if the user was authenticated using a self-issued
                   InfoCard.

               simple
                   True if the user authenticated without using a password.

               This test can be used as part of a risk-based authentication
               configuration; a user with credentials obtained through an
               authentication style deemed not to be sufficiently secure with
               respect to a resource could be forced to reauthenticate using a
               stronger authentication method. See dacs_authenticate(8)[9] for
               additional information.

           importedby jurisdiction
               The keyword importedby is followed by the name of a
               jurisdiction within the current federation; the result is True
               if the credentials were imported using
               dacs_auth_transfer(8)[118] at that jurisdiction.

                   user("importedby METALOGIC")


           version protocol-version
               The keyword version is followed by a DACS protocol version
               number (every release of DACS defines this as the value of the
               compile-time symbol DACS_VERSION_NUMBER); the result is True if
               the credentials match that protocol version number.

                   user("version 1.4")


           authenticated, unauthenticated
               Either of two keywords: authenticated (or simply auth) or
               unauthenticated (or simply unauth). The former is True if the
               user is authenticated, while the latter is True if the user is
               not authenticated. A case-insensitive string comparison is used
               to match these special names.

                   user("auth")
                   user("unauth")


           mine
               The keyword "mine" (case insensitive) is True if the user was
               authenticated by the current jurisdiction.

                   user("mine")


           any
               The keyword "any" (case insensitive) is always True.

                   user("any")


           none
               The keyword "none" (case insensitive) is always False.

                   user("none")


           By default, an exact string comparison (case sensitive) is used to
           match name components other than the special names; this default
           behaviour can be overridden using the NAME_COMPARE configuration
           directive (dacs.conf(5)[10]). The method used to compare federation
           names, jurisdiction names, and usernames can also be specified by
           following the primary with a mode. If the value of mode (which is
           itself case insensitive) is case, then case-sensitive comparisons
           are used, if its value is nocase, then case-insensitive comparisons
           are used, and if its value is default, then the value of the
           NAME_COMPARE directive will be used if present, otherwise the
           application default is used (either case or the value selected by
           the application).

               Important
               Keep in mind that user() can return False because no
               credentials matched the user filter expression and because
               there are no credentials at all (i.e., the user is
               unauthenticated). For example,

                   user("not METALOGIC:rmorriso")

               will return True if the user's identity is not
               METALOGIC:rmorriso, even if the user is not authenticated. It
               may therefore be necessary to explicitly test for an
               authenticated user:

                   user("not METALOGIC:rmorriso and auth")
           Here are examples of the user() function. Note that any non-zero
           expression value implies True.

            1.

                   user("METALOGIC:")

               Return True if the client was authenticated by the jurisdiction
               METALOGIC in this federation

            2.

                   user("METALOGIC:rmorriso")

               Return True if the client was authenticated as the user
               METALOGIC:rmorriso

            3.

                   user("DEMO::METALOGIC:rmorriso")

               Return True if the client was authenticated by the given
               federation and jurisdiction as rmorriso

            4.

                   user("%METALOGIC:admin")

               Return True if the client is a member of the group
               METALOGIC:admin

            5.

                   user("*:rmorriso")

               Return True if the client was authenticated as the username
               rmorriso by any jurisdiction in this federation

            6.

                   user("auth")

               Return True if the client was authenticated anywhere

            7.

                   user("UnAuthenticated")

               Return True if the client is not authenticated

            8.

                   user("10.0.0.123")

               Return True if the client was authenticated through a request
               from a host having the IP address 10.0.0.123

            9.

                   user("not 10.0.0.123")

               Return True if the client is unauthenticated or was not
               authenticated through a request from a host having the IP
               address 10.0.0.123 (use user("auth and not 10.0.0.123") to
               remove the unauthenticated case)

           10.

                   user("ANY")

               Always return True

           11.

                   user("any") gt 1

               Return True if the client has more than one set of current
               credentials (i.e., has authenticated as two or more identities)

           12.

                   user(":rmorriso")

               Return True if the client was authenticated as rmorriso by this
               jurisdiction

           13.

                   user(":rmorriso nocase")

               Return True if the client was authenticated as rmorriso,
               case-insensitively, by this jurisdiction

           14.

                   user("metalogic:RMORRISO nocase")

               Return True if the client was authenticated as the user
               metalogic:RMORRISO, but comparing the jurisdiction name,
               username, and implied federation name case-insensitively

           15.

                   user("METALOGIC:rmorriso default")

               Equivalent to user("METALOGIC:rmorriso"), return True if the
               client was authenticated as the user METALOGIC:rmorriso, but
               comparing the jurisdiction name, username, and implied
               federation name according to the NAME_COMPARE directive,
               otherwise using the application's default


               Tip
               The following two tests are not equivalent:

                   user("auth")
                   user("DSS:auth")

               The first is True if the user making the request has been
               authenticated; it does matter which jurisdiction authenticated
               the user or what the username is. The second test requires the
               user making the request to have a specific identity; she must
               have been authenticated by the jurisdiction DSS as the username
               auth.

       ustamp(op, vfs-ref [,args ...])
           This function generates a string called a stamp that is globally
           unique and sequenced, with high probability. It has the following
           syntax:

               h=hostid, s=seqno

           A hostid consists of one or more characters from the same set used
           for a DACS username[120]. A seqno consists of two elements,
           separated by a colon, each of which is an unsigned decimal value.

           The first component of a stamp, the hostid, is intended to be
           uniquely associated with the host that generates the stamp. By
           default, it is a 128-bit, cryptographically strong pseudo-random
           value. This value is stored in vfs-ref, which may be an absolute
           pathname, an item type, or a VFS URI[26]. If vfs-ref does not
           exist, it is created and a new value is stored in it.

           Note that by default, hostid identifies a host, not a jurisdiction.
           If required, it is possible to configure unique stamps for each
           jurisdiction on a host.

           The second component (seqno) is a sequence number string relative
           to hostid. Sequence numbers should never repeat with respect to a
           host and always increase in value so that any two sequence numbers
           created by the same host must be different. Successive sequence
           numbers need not increase by uniform steps. If stamp1 compares less
           than stamp2, then stamp1 was created before stamp2. Comparison of
           sequence numbers is performed on matching elements numerically,
           left to right. Two hostid components are compared case
           insensitively. No ordering is necessarily implied by stamps created
           by different hosts.

           Sequence number state information is stored in a file that must be
           specified using the configuration variable ${Conf::ustamp_seqno};
           e.g.,

               EVAL ${Conf::ustamp_seqno} = "${Conf::DACS_HOME}/seqno"

           The variable must be set to the absolute pathname of a file that is
           readable and writable by any process that needs to generate a
           stamp. If this file is deleted, the sequence will be reinitialized.
           Note that updates to the state information are unlikely to be
           atomic, which means that in the event of a system crash the state
           information should be deleted so that a new stream of sequence
           numbers is generated.

           One application of these stamps is to provide an efficient way to
           detect replayed messages. A recipient may only need to keep track
           of the stamp sent with the last message received from a
           jurisdiction to detect an invalid stamp in any subsequent message.
           Cryptographic techniques can be employed to prevent a stamp from
           being altered or forged.

           The following operations are recognized:

           ustamp(clock, vfs-uri)
               The host's system clock is used for the stamp's sequence
               number. Its first element is the number of seconds since the
               start of the epoch and the second is a counter value. Note that
               if the system clock is reset to an earlier time, sequence
               numbers may repeat with unpredictable consequences; a future
               version of this function may detect a reset clock.

           ustamp(ntpclock, vfs-uri, ntp_host)
               This operation is not implemented. Rather than using the system
               clock, this operation obtains the current time from ntp_host,
               which is assumed to be more reliable than the system clock in
               that it will never be reset to an earlier time. The ntp_host
               argument is a hostname or IP address. The default port number
               (123) may be overridden by appending a colon and the port
               number to use.

           ustamp(user, vfs-uri, seqno)
               Instead of incorporating the current time into the stamp's
               sequence number, this operation uses a user-supplied string
               that is assumed to have the necessary syntax and
               characteristics.

           Examples:

               > ustamp(clock, "${Conf::DACS_HOME}/hostid")
               "h=2fbae312ddc1d2ae388cea1b57a47c66, s=1185565675:9"


       valuesof(alist)
           If its argument is a single pair, the pair's value is returned. If
           there is more than one pair in the argument, a list of values is
           returned. To get the key component of a pair or set of pairs, use
           keysof()[18].

           Examples:

               > valuesof({red, 17})
               17
               > valuesof({red, 17, blue, 100})
               [17, 100]


       var(op, namespace, variable-name [, args ...])
           This function performs various operations on a variable, some of
           which are awkward or impossible to do using the more concise
           variable reference syntax. For example, the namespace or variable
           name argument to var() can be specified by an expression.

           The following operations are available:

           var(delete, namespace, variable-name)
               Delete (undefine) the variable named variable-name within
               namespace. If the variable is deleted, 1 is returned, and if it
               does not exist, 0 is returned.

           var(exists, namespace, variable-name)
               Test if the variable named variable-name within namespace
               exists, returning 1 if so and 0 if not.

           var(get, namespace, variable-name [, altval])
               Return the value of the variable named variable-name within
               namespace. If the variable does not exist, altval is returned
               if given, otherwise the empty string is returned (which could
               potentially be confused with a legitimate value).

           var(set, namespace, variable-name, value)
               Set the value of the variable named variable-name within
               namespace to value. If namespace or variable-name do not exist
               they are created. If the variable already exists, its value is
               replaced. The function returns value.

           Examples:

               > ${Y::foo} = 17
               17
               > setvar(split, X, "/a/b/c/Y", "/")
               5
               > var(get, X, 4)
               "Y"
               > var(get, X, ${X::#} - 1)
               "Y"
               > var(get, var(get, X, "4"), "foo")
               "17"
               > var(set, Y, "f" . "o" . "o", 2007)
               2007
               > ${Y::foo}
               2007


       vfs(op, vfs-ref [, argument ...])
           This function is an interface to the DACS virtual filestore
           subsystem, described in dacs.vfs(5)[121]. Please refer to
           dacs.conf(5)[26] and dacsvfs(1)[122] for details and examples.

           The first argument specifies the operation to be performed. The
           second argument identifies a filestore (typically a file or
           database); it can be an absolute pathname, an item_type that has
           been configured through a VFS[26] directive, or a VFS URI[123].
           Zero or more arguments may follow, depending on op. For most
           operations, the third argument will be the key that identifies the
           object of interest. The underlying filestore is implicitly opened
           and closed.

           An operation that fails abnormally triggers a fatal error.

           The following operations (op) are available:

           vfs(control, vfs-ref, c_op [, argument ...]
               Perform a configuration operation, specified by c_op, on the
               filestore. Zero or more arguments may follow c_op, depending on
               the semantics of c_op. Not all c_op requests are valid for a
               given storage scheme or have an effect.  True is returned if
               successful, False otherwise. Recognized c_op specifiers are:

               flush
                   For dacs-kwv type schemes, if modified data has been
                   buffered, write it to the underlying storage layer.

               get_container
                   For most schemes, return a URI for the underlying object
                   that stores the instance's data (e.g., the URI for a
                   filename).

               set_cookies
                   For an http or https scheme, each argument is an HTTP
                   cookie to submit with each request. (NOT IMPLEMENTED).

               set_field_sep field_sep
                   For dacs-kwv type schemes, set the field separator string
                   to field_sep.

               set_lock mode
                   For a native filesystem object (the fs scheme), set or
                   unset a lock on the underlying storage object according to
                   mode. (NOT IMPLEMENTED.)


           vfs(defined, item-type)
               Test if the specified item-type has been defined by a VFS[26]
               directive.

                   vfs(defined, "passwds")


           vfs(delete, vfs-ref [, key])
               Delete the referenced object.

           vfs(enabled [, store-name])
               With an argument, test if the specified store-name can be used.
               With no argument, return a list[69] of enabled store names.

                   vfs(enabled, "db") ? print("yes") : print("no");


           vfs(exists, vfs-ref [, key])
               Test whether the referenced object exists, returning True or
               False.

                   vfs(exists, "/usr/local/dacs/conf/passwd")
                   vfs(exists, "file:///usr/local/dacs/conf/passwd")


           vfs(get, vfs-ref [, key])
               Retrieve the referenced object.

           vfs(getsize, vfs-ref [, key])
               Return the length, in bytes, of the referenced object.

           vfs(list, vfs-ref)
               List the keys of all objects in the store.

           vfs(put, vfs-ref, value)
           vfs(put, vfs-ref, key, value)
               Store an item under the given key, replacing any existing
               instance. The value is null-terminated.

           vfs(rename, vfs-ref, oldkey, newkey)
               Change the key associated with an existing item from oldkey to
               newkey.

           vfs(uri, item-type)
               If item-type has been defined by a VFS[26] directive, return
               its URI, otherwise the empty string.

                   > vfs(uri, "passwds")
                   "[passwds]dacs-kwv-fs:/usr/local/dacs/conf/passwd?field_sep=:"


           This statement sets a variable to the contents of the file
           /tmp/somefile:

               ${somefile} = vfs(get, "file:///tmp/somefile")

           As do this equivalent statements:

               ${somefile} = vfs(get, "/tmp/somefile")
               ${somefile} = get("/tmp/somefile")

           This expression lists the files in the /tmp directory:

               vfs(list,"dacs-fs:/tmp")

           These expressions 1) add a key/value pair to a Berkeley DB database
           (/tmp/mydb.db), creating the database file if necessary, 2)
           retrieve the value, 3) rename the key, and 4) list the keys in the
           database:

               vfs(put, "dacs-db:/tmp/mydb.db", "foo", "baz");
               vfs(get, "dacs-db:/tmp/mydb.db", "foo");
               vfs(rename, "dacs-db:/tmp/mydb.db", "foo", "bar");
               vfs(list, "dacs-db:/tmp/mydb.db");

           This rule fragment denies access if the user has already been
           granted access five times:

               <deny>
                 if (user("auth")) {
                   if (vfs(exists, counter_db, ${DACS::IDENTITY})) {
                     ${count} = vfs(get, counter_db, ${DACS::IDENTITY});
                   }
                   else {
                     ${count} = 0;
                   }
                   if (${count} gt 5) {
                     return(1);
                   }
                   vfs(put, counter_db, ${DACS::IDENTITY}, ++${count});
                   return(0);
                 }
               </deny>

           The item type counter_db would be configured in dacs.conf; e.g.,

               VFS "[counter_db]dacs-db:/usr/local/dacs/federations/counters.db"


SEE ALSO
       dacsexpr(1)[1]

BUGS
       Assorted clunky aspects of the language are likely to be replaced by
       simplified or more general approaches once requirements are clearer.
       The list and alist data types have not been fully developed and
       integrated. Assignment to a namespace would be a useful extension.

       A way to handle errors and exceptions (such as with try/catch/throw
       statements) would be nice. A switch statement and dynamically loaded
       functions are planned. A foreach statement might be useful, although
       the language has so far successfully avoided loop constructs as a way
       to limit its complexity.

       Various aspects of variables and namespaces are not implemented. A
       namespace cannot be copied by assignment; use setvar().

       Input and output processing is still rather limited.

       Having to use ":" instead of ".." when matching octet ranges with
       from()[114] is unfortunate but avoids pesky period proliferation.

       Some of the more esoteric functions and modes of operation exist
       primarily to expose DACS core code for testing purposes.

AUTHOR
       Distributed Systems Software (www.dss.ca[124])

COPYING
       Copyright2003-2013 Distributed Systems Software. See the LICENSE[125]
       file that accompanies the distribution for licensing information.

NOTES
        1. dacsexpr(1)
           http://dacs.dss.ca/man/dacsexpr.1.html

        2. Perl
           http://www.perl.org/

        3. PHP
           http://www.php.net

        4. Tcl
           http://www.tcl.tk/about

        5. isprint(3)
           http://www.freebsd.org/cgi/man.cgi?query=isprint&apropos=0&sektion=3&manpath=FreeBSD+9.1-RELEASE&format=html

        6. print()
           http://dacs.dss.ca/man/#print

        7. cast
           http://dacs.dss.ca/man/#cast

        8. modifier flag
           http://dacs.dss.ca/man/#variable_modifiers

        9. dacs_authenticate(8)
           http://dacs.dss.ca/man/dacs_authenticate.8.html

       10. dacs.conf(5)
           http://dacs.dss.ca/man/dacs.conf.5.html

       11. dacs_acs(8)
           http://dacs.dss.ca/man/dacs_acs.8.html

       12. environ(7)
           http://www.freebsd.org/cgi/man.cgi?query=environ&apropos=0&sektion=7&manpath=FreeBSD+9.1-RELEASE&format=html

       13. exec()
           http://dacs.dss.ca/man/#exec

       14. list()
           http://dacs.dss.ca/man/#list

       15. length()
           http://dacs.dss.ca/man/#length

       16. strchars()
           http://dacs.dss.ca/man/#strchars

       17. expression grammar
           http://dacs.dss.ca/man/#expression_grammar

       18. keysof()
           http://dacs.dss.ca/man/#keysof

       19. valuesof()
           http://dacs.dss.ca/man/#valuesof

       20. alist()
           http://dacs.dss.ca/man/#alist

       21. supported data types
           http://dacs.dss.ca/man/#data_types

       22. variable reference
           http://dacs.dss.ca/man/#variables

       23. dacs_notices(8)
           http://dacs.dss.ca/man/dacs_notices.8.html

       24. alist construction operator
           http://dacs.dss.ca/man/#alists

       25. listref()
           http://dacs.dss.ca/man/#listref

       26. VFS
           http://dacs.dss.ca/man/dacs.conf.5.html#VFS

       27. revocation list
           http://dacs.dss.ca/man/dacs.acls.5.html#revocation_list

       28. access control rule
           http://dacs.dss.ca/man/dacs.acls.5.html

       29. on_success()
           http://dacs.dss.ca/man/#on_success

       30. AUTH_SUCCESS
           http://dacs.dss.ca/man/dacs.conf.5.html#AUTH_SUCCESS

       31. ACS_SUCCESS
           http://dacs.dss.ca/man/dacs.conf.5.html#ACS_SUCCESS

       32. ADMIN_IDENTITY
           http://dacs.dss.ca/man/dacs.conf.5.html#ADMIN_IDENTITY

       33. approval stamp
           http://dacs.dss.ca/man/dacs_acs.8.html#dacs_approval

       34. dacs64 decoding
           http://dacs.dss.ca/man/dacs.exprs.5.html#encode

       35. dacs_list_jurisdictions(8)
           http://dacs.dss.ca/man/dacs_list_jurisdictions.8.html

       36. dacsauth(1)
           http://dacs.dss.ca/man/dacsauth.1.html

       37. dacscheck(1)
           http://dacs.dss.ca/man/dacscheck.1.html

       38. encode()
           http://dacs.dss.ca/man/#encode

       39. cryptographic hash
           http://en.wikipedia.org/wiki/Message_digest

       40. MD5 Message-Digest Algorithm
           http://en.wikipedia.org/wiki/MD5

       41. hash()
           http://dacs.dss.ca/man/#hash

       42. decode()
           http://dacs.dss.ca/man/#decode

       43. radix-85
           http://en.wikipedia.org/wiki/Ascii85

       44. RFC 2045
           http://www.rfc-editor.org/rfc/rfc2045.txt

       45. RFC 1738
           http://www.rfc-editor.org/rfc/rfc1738.txt

       46. RFC 2396
           http://www.rfc-editor.org/rfc/rfc2396.txt

       47. RFC 3986
           http://www.rfc-editor.org/rfc/rfc3986.txt

       48. execv(3)
           http://www.freebsd.org/cgi/man.cgi?query=execv&apropos=0&sektion=3&manpath=FreeBSD+9.1-RELEASE&format=html

       49. basename(1)
           http://www.freebsd.org/cgi/man.cgi?query=basename&apropos=0&sektion=1&manpath=FreeBSD+9.1-RELEASE&format=html

       50. dirname(1)
           http://www.freebsd.org/cgi/man.cgi?query=dirname&apropos=0&sektion=1&manpath=FreeBSD+9.1-RELEASE&format=html

       51. stat
           http://dacs.dss.ca/man/#stat

       52. stat(1)
           http://www.freebsd.org/cgi/man.cgi?query=stat&apropos=0&sektion=1&manpath=FreeBSD+9.1-RELEASE&format=html

       53. stat(2)
           http://www.freebsd.org/cgi/man.cgi?query=stat&apropos=0&sektion=2&manpath=FreeBSD+9.1-RELEASE&format=html

       54. printf(3)
           http://www.freebsd.org/cgi/man.cgi?query=printf&apropos=0&sektion=3&manpath=FreeBSD+9.1-RELEASE&format=html

       55. test(1)
           http://www.freebsd.org/cgi/man.cgi?query=test&apropos=0&sektion=1&manpath=FreeBSD+9.1-RELEASE&format=html

       56. mod_access
           http://httpd.apache.org/docs-2.2/mod/mod_access.html

       57. RFC 1035
           http://www.rfc-editor.org/rfc/rfc1035.txt

       58. CIDR notation
           http://en.wikipedia.org/wiki/CIDR_notation

       59. RFC 1338
           http://www.rfc-editor.org/rfc/rfc1338.txt

       60. range specification
           http://dacs.dss.ca/man/#range-spec

       61. regmatch()
           http://dacs.dss.ca/man/#regmatch

       62. user()
           http://dacs.dss.ca/man/#user

       63. digest()
           http://dacs.dss.ca/man/#digest

       64. message authentication code
           http://en.wikipedia.org/wiki/Message_Authentication_Code

       65. Keyed-Hash Message Authentication Code (HMAC)
           http://csrc.nist.gov/publications/fips/fips198-1/FIPS-198-1_final.pdf

       66. Secure Hash Standard functions
           http://dacs.dss.ca/man/dacs.conf.5.html#SHA_functions

       67. MD5 (RFC 2104)
           http://www.rfc-editor.org/rfc/rfc2104.txt

       68. RFC 2253
           http://www.rfc-editor.org/rfc/rfc2253.txt

       69. list construction operator
           http://dacs.dss.ca/man/#lists

       70. dacspasswd(1)
           http://dacs.dss.ca/man/dacspasswd.1.html

       71. PASSWORD_DIGEST
           http://dacs.dss.ca/man/dacs.conf.5.html#PASSWORD_DIGEST

       72. PASSWORD_SALT_PREFIX
           http://dacs.dss.ca/man/dacs.conf.5.html#PASSWORD_SALT_PREFIX

       73. local_passwd_authenticate
           http://dacs.dss.ca/man/dacs_authenticate.8.html#local_passwd_authenticate

       74. vfs()
           http://dacs.dss.ca/man/#vfs

       75. PASSWORD_CONSTRAINTS
           http://dacs.dss.ca/man/dacs.conf.5.html#PASSWORD_CONSTRAINTS

       76. dacs.conf(5)
           http://dacs.dss.ca/man/dacs.conf.5.html#interpolation

       77. RFC 2898
           http://www.rfc-editor.org/rfc/rfc2898.txt

       78. RFC 3962
           http://www.rfc-editor.org/rfc/rfc3962.txt

       79. LOG_FILTER
           http://dacs.dss.ca/man/dacs.conf.5.html#LOG_FILTER

       80. cryptographically strong pseudo-random values
           http://www.openssl.org/docs/crypto/RAND_bytes.html

       81. strtr()
           http://dacs.dss.ca/man/#strtr

       82. ACS_ERROR_HANDLER
           http://dacs.dss.ca/man/dacs.conf.5.html#ACS_ERROR_HANDLER

       83. ErrorDocument directive
           http://httpd.apache.org/docs-2.2/mod/core.html#errordocument

       84. Rlinks
           http://dacs.dss.ca/man/dacs_acs.8.html#rlinks

       85. permalinks
           http://en.wikipedia.org/wiki/Permalink

       86. regex(3)
           http://www.freebsd.org/cgi/man.cgi?query=regex&apropos=0&esektion=3&emanpath=FreeBSD+9.1-RELEASE&format=html

       87. re_format(7)
           http://www.freebsd.org/cgi/man.cgi?query=re_format&sektion=7&apropos=0&manpath=FreeBSD+9.1-RELEASE&format=html

       88. access control rules
           http://dacs.dss.ca/man/dacs.acls.5.html#elements

       89. read-only namespace
           http://dacs.dss.ca/man/#reserved_namespaces

       90. RFC 2617
           http://www.rfc-editor.org/rfc/rfc2617.txt

       91. copy
           http://dacs.dss.ca/man/#setvar-copy

       92. query
           http://dacs.dss.ca/man/#setvar-query

       93. cgiparse(8)
           http://dacs.dss.ca/man/cgiparse.8.html

       94. split
           http://dacs.dss.ca/man/#setvar-split

       95. sleep(3)
           http://www.freebsd.org/cgi/man.cgi?query=sleep&apropos=0&sektion=3&manpath=FreeBSD+9.1-RELEASE&format=html

       96. sprintf(3)
           http://www.freebsd.org/cgi/man.cgi?query=sprintf&apropos=0&sektion=3&manpath=FreeBSD+9.1-RELEASE&format=html

       97. strftime(3)
           http://www.freebsd.org/cgi/man.cgi?query=strftime&apropos=0&sektion=3&manpath=FreeBSD+9.1-RELEASE&format=html

       98. strptime(3)
           http://www.freebsd.org/cgi/man.cgi?query=strptime&apropos=0&sektion=3&manpath=FreeBSD+9.1-RELEASE&format=html

       99. tr(1)
           http://www.freebsd.org/cgi/man.cgi?query=tr&apropos=0&sektion=1&manpath=FreeBSD+9.1-RELEASE&format=html

       00. DACS name
           http://dacs.dss.ca/man/dacs.1.html#naming

       01. RFC 822
           http://www.rfc-editor.org/rfc/rfc822.txt

       02. RFC 952
           http://www.rfc-editor.org/rfc/rfc952.txt

       03. FEDERATION_NAME
           http://dacs.dss.ca/man/dacs.conf.5.html#FEDERATION_NAME

       04. RFC 1123
           http://www.rfc-editor.org/rfc/rfc1123.txt

       05. RFC 790
           http://www.rfc-editor.org/rfc/rfc790.txt

       06. JURISDICTION_NAME
           http://dacs.dss.ca/man/dacs.conf.5.html#JURISDICTION_NAME

       07. strptime()
           http://dacs.dss.ca/man/#strptime

       08. localtime(3)
           http://www.freebsd.org/cgi/man.cgi?query=localtime&apropos=0&sektion=3&manpath=FreeBSD+9.1-RELEASE&format=html

       09. dacstransform(1)
           http://dacs.dss.ca/man/dacstransform.1.html

       10. transform_config()
           http://dacs.dss.ca/man/#transform_config

       11. concise user syntax
           http://dacs.dss.ca/man/dacs.1.html#concise_user_syntax

       12. transform()
           http://dacs.dss.ca/man/#transform

       13. ACS_CREDENTIALS_LIMIT
           http://dacs.dss.ca/man/dacs.conf.5.html#ACS_CREDENTIALS_LIMIT

       14. from()
           http://dacs.dss.ca/man/#from

       15. dacs.groups(5)
           http://dacs.dss.ca/man/dacs.groups.5.html

       16. styles
           http://dacs.dss.ca/man/dacs_authenticate.8.html#STYLE

       17. dacs_auth_agent(8)
           http://dacs.dss.ca/man/dacs_auth_agent.8.html

       18. dacs_auth_transfer(8)
           http://dacs.dss.ca/man/dacs_auth_transfer.8.html

       19. dacscookie(1)
           http://dacs.dss.ca/man/dacscookie.1.html

       20. DACS username
           http://dacs.dss.ca/man/dacs.1.html#dacs_identity

       21. dacs.vfs(5)
           http://dacs.dss.ca/man/dacs.vfs.5.html

       22. dacsvfs(1)
           http://dacs.dss.ca/man/dacsvfs.1.html

       23. VFS URI
           http://dacs.dss.ca/man/man/dacs.conf.5.html#VFS

       24. www.dss.ca
           http://www.dss.ca

       25. LICENSE
           http://dacs.dss.ca/man/../misc/LICENSE



DACS 1.4.28b                      02/04/2014                     DACS.EXPRS(5)