DACS.EXPRS(5) | DACS Formats Manual | DACS.EXPRS(5) |
NAME¶
dacs.exprs - DACS expression languageDESCRIPTION¶
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.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.
Three comment styles are recognized:
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.
•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:
Here are examples of all three styles:
> ${foo:? \#xxx} " #xxx"
/* * This is a comment */ // This is another comment ${x} = 17; # And one last comment
<!-- 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, 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
, 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
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:
binary
•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 & and a
< character must be written as <. For example, the query string
a=1&b=2 might be used as
${Foo::QUERY_STRING} = "a=1&b=2"
foo"baz" foo."baz"
, 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.
bareword
> "\0\1\2" "000102"
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:
These two expressions are equivalent and yield "foobaz":
bool
file(test, "-e", foo) file("test", "-e", "foo")
foo."baz" foo.baz
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.
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.
A variable reference may have either of the following syntaxes:
For instance, the following refers to the value of a variable called
JURISDICTION_NAME within the namespace called Conf:
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:
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:
Note that the variable reference ${foo-17} has a valid but different
interpretation if the braces are omitted.
${[ namespace::]variable-name[:flags]} $[ namespace::]variable-name
${Conf::JURISDICTION_NAME}
-_.!~*'()
${Conf::#}
${myvar} $myvar ${foo::baz} $foo::baz
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
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.
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:?}"
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:
In a future release, this mechanism may be generalized to provide a run-time
means of selecting the default namespace.
${foo} = 17 ${Temp::foo} = 17 $foo = 17
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.
A list is composed of zero or more basic data types or sub-lists. A list is
created using the following syntax:
A list can also be created through the list()[14] function.
Here is a list consisting of four elements:
The length()[15] function returns the number of elements in a list.
A list can be assigned to a variable:
Note
These two statements are equivalent:
And so are these two:
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.
A list element can be referenced using a subscript between zero and one less
than the number of elements in the list:
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.
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.
The dotdot operator can also be used to construct an element of a list or alist:
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:
Tip
Individual characters and sequences of characters of a string-valued expression
can be selected using strchars()[16], which uses a similar syntax.
Note
LIST -> "[" "]" | "[" LIST-ELS "]" LIST-ELS -> EL | EL "," LIST-ELS EL -> BASIC-DATA-TYPE | LIST
[1, "one", 1.000, ["one sublist"]]
$mylist = [1, 2, 3, 4, 5, 6] $mylist_copy = $mylist
$mylist = ["one", "two"] ${mylist} = ["one", "two"]
$mylist[0] ${mylist}[0]
> $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]
> $mylist = [1, 2, 3, 4, 5, 6]; length($mylist) 6 > $mylist[0] 1
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
> $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]
> $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]
> $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
•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]
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:
An alist can also be created through the alist()[20] function.
Here is an alist consisting of four elements:
The length()[15] function returns the number of pairs of elements in an
alist.
An alist can be assigned to a variable:
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.
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.
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:
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.
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
{"red", 0, "blue", 2, "green", 5, "black", 7}
$myalist = {1, 2, 3, 4, 5, 6} $myalist_copy = $myalist
> $myalist={sunny, 3} {"sunny", 3} > $myalist . {rainy, 11} {"sunny", 3, "rainy", 11} > $myalist .= {"snowy", 13} {"sunny", 3, "snowy", 13}
> $myalist = {a, 2, b, 4, c, 6}; length($myalist) 3 > $myalist["a"] 2 > $myalist{"b"} {"b", 4} > $myalist{"c", "a"} {"c", 6, "a", 2}
> $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
Expression Grammar¶
The following grammar is used to construct an expression (EXP) or sequence (S) of expressions.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 ->
${a} += 17
if ( expression) { sequence } [elseif ( expression) { sequence }] ... [else { sequence }]
${a} = if (${b} > 8) {${b}++; 33;} else {${b} - 1}
"hello, " . (if (0) {b . y . e} else {"world"})
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.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 '&'.
|
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 '&'.
==, !=, 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 '<'; 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.
Note
A period will be recognized as a decimal point in a real number context rather
than as the dot operator, so the input:
will be scanned as a number whereas, for example, the input:
will evaluate to the string "45".
<<, >>
> "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]]
4.5
"4".5
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.
+, -, not, !, ~, ++ VAR, --VAR, (type)
> 2**10 1024
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.
An explicit type conversion can be forced by using a cast. The syntax for this
type coercion is:
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:
VAR++, VAR--, primary
> ${foo} = 17, ++${foo} 18
( type) expression
> (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"}
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.
is equivalent to the expression:
And the call:
yields:
alistref(list)
alist(cars, 2, bikes, 5)
{"cars", 2, "bikes", 5}
alist(2, xx, [0, 1], yy)
{"2", xx, "[0,1]", yy}
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].
is equivalent to the expression:
the value of which is:
bstring(string, length)
listref({"a", 1, "b", 2, "c", 3}, alistref(["b"]))
{"a", 1, "b", 2, "c", 3}{"b"}
{"b", 2}
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.
contains_any(format, test-set, target-set[, nocase])
> bstring("\0\1\2", 4) "000102" > bstring("\0\1\2", 2) "0001"
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.
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])
contains_any(",", ${Args::LAYERS:i}, "Nests,Secret_roads,Heritage") contains_any(",", "a,a,b,z", "a,a,a,b,b,b,a,z,z")
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.
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]:
The counter's value might then be tested in the revocation list[27] or by
an access control rule[28], for instance:
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:
dacs_admin()
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.
% dacsexpr -e 'counter(set, "dacs-kwv-fs:/usr/local/dacs/counters/logins", "EXAMPLE::EX:bob", 1)'
counter(exists, "dacs-kwv-fs:/usr/local/dacs/counters/logins", ${DACS::IDENTITY})
counter(decdel, "dacs-kwv-fs:/usr/local/dacs/counters/logins", ${DACS::IDENTITY})
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)
dacs_meta(op[, ...])
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.
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)
dacsauth(dacsauth-flags)
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.
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
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)
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.
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].
encode(encoding-type, arg)
> digest("foo", 0, "md5") "acbd18db4cc2f85cedef654fccc4a4d8" > digest("Hello, world", 0, "SHA256") "4ae7c3b6ac0beff671efa8cf57386151c06e58ca53a78d83f36107316cec125f"
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)
eval(expression)
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(cescape, arg)
> encode(ascii85, decode(hex, "123456789a")) "&i<X6RK"
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(dacs64, arg)
> encode(cescape, bstring("hi\0\1\2\3\012", 7)) "hi\0\001\002\003\n"
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(hex, arg)
> encode(dacs64, bstring("\0\0\0\1", 4)) "_____-"
This encoding converts each byte in arg into a
hexadecimal character pair.
encode(mime, arg)
> encode(hex, "Hello") "48656c6c6f"
This encoding applies the MIME base-64 encoding function
( RFC 2045[44], Section 6.8) to its argument and returns the result.
encode(url, arg)
> encode(mime, bstring("\0\0\0\1", 4)) "AAAAAQ=="
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"
This function evaluates its string argument and returns
the result.
The call:
exec(prog, ...)
> eval("length(\"abc\")") 3
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:
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)
> exec("/bin/sh", "-c", "date | grep -c ^Thu") "0"
> ${ExecEnv::PATH} = "/usr/bin"; "/usr/bin" > exec("/bin/sh", "-c", "printenv"); "PATH=/usr/bin"
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.
file(op [,arg-list])
> ${a} = 17 17 > "${a}" "17" > '${a}' "${a}" > expand('${a}') "17" > ${b} = 1999, ${c} = expand('${a}, \${b}') "17, ${b}" > expand(${c}) "17, 1999"
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.
file_group([path])
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.
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:
This predicate provides a simple way of limiting access to a file to its group
membership with respect to file system permissions:
For example, if the user requesting access has been assigned the following roles
by the current jurisdiction (e.g., through local_unix_roles):
and the resource being requested is the file:
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])
file(test, "-e", ${DACS::FILENAME}) and user("%" . ${Conf::JURISDICTION_NAME} . ":" \ . file(stat, "%G", ${DACS::FILENAME}))
<allow> file_group() </allow>
wheel,www,users
-rw-r--r-- 1 bobo www 75 Apr 11 12:41 htdocs/foo.html
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:
This predicate provides a simple way of limiting access to a file to its owner
with respect to file system permissions:
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)
file(test, "-e", ${DACS::FILENAME}) and user(${Conf::JURISDICTION_NAME} . ":" . file(stat, "%U", ${DACS::FILENAME}))
<allow> file_owner() </allow>
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:
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])
1.a full or partially matching domain name:
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.
from("metalogic.example.com")
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 "..": :
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.0.[0:100,255]")
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):
An alternative method is to perform a regular expression match against
${DACS::REMOTE_ADDR} using regmatch()[61].
from("all")
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].
hmac(msg, msg-len, key, key-len [,
digest-name])
> hash("Hello, world", 0) "3696529580" > hash("Hello, world", 0, hash64) "462009511995194717"
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.
http(url, [method [,arglist]])
> hmac("Sample #2", 0, decode(hex, "303132333435363738393a3b3c3d3e3f40414243"), 0) "0922d3405faa3d194f82a45830737d5cc6c75d24"
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:
index(string, character-class [, nocase])
> ${x} = http("http://example.com") > http("https://example.com:8443/cgi-bin/dacs_prenv.cgi", "GET", "FOO", 17, "BAZ", 1+1)
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:
info(namespaces)
> 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
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:
keysof(alist)
info(namespaces) info(namespace, "Conf")
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:
ldap(dn_length, dn-string)
> keysof({red, 17}) "red" > keysof({red, 17, blue, 100}) ["red", "blue"]
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:
length(string)
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))
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].
is equivalent to the expression:
listref(list, list-ref [, ...])
list(1, 2, [hello, world], 5)
[1, 2, [hello, world], 5]
This function provides an alternate syntax to the
language's list/array notation. For example, the function call:
is equivalent to the expression:
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:
The parentheses are necessary here because the subscript binds more tightly than
the concatenation operator. This expression can also be written as:
on_success(list-name [, expr])
listref([1, 2, [3, 4], 5], 2, 1)
[1, 2, [3, 4], 5][2][1]
($a . $b)[0]
listref($a . $b, 0)
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])
pathname(path, hostname, port)
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
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].
print(...)
> pbkdf2("password", "ATHENA.MIT.EDUraeburn", 1200, 32) "5c08eb61fdf71e4e4ec3cf6ba1f5512ba7e52ddbc5e5142f708a31e2e62b1e13" > pbkdf2("password", decode(hex,"1234567878563412"), 5, 16) "d1daa78615f287e6a1c8b120d7062a49"
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)
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:
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)
> random(string,12,"a-zA-Z0-9") "LgROshy6SMMH" > random(string,12,"a-z") "kehhvwydhhbk"
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 "&".
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:
With this rule in place, a request like:
would result in a redirect to this target:
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])
<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>
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:
regsub(string, regex, replacement [, nocase]
[,repeat])
•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"
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:
request_match(uri-string)
> 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"
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:
return(result)
> 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
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:
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:
The following call would only return True ( 1) any day between
5:00pm and 5:59pm:
Note
setvar(op, dst-namespace [, args ...])
${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
<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>
rule("/exam1.html?user=teacher", "dacs-fs:/usr/local/exams/acls");
•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.
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)
setvar(load, dst-namespace, item_type, key)
setvar(load, dst-namespace, vfs-ref, key)
sizeof(typename)
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(copy, dst-namespace, src-namespace)
setvar(authorization, Foo, "Basic Qm9ibzpteVBhc3NXb3Jk")
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:
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(kwv, "Foo", "=", ", ", "a=b, c=d, e=f")
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:
Here, there are 25 lines in /etc/passwd and the third line is printed.
setvar(loadi, dst-namespace, vfs-ref)
> setvar(load, PASSWD, "/etc/passwd") 25 > ${PASSWD::2} "root:*:0:0:Charlie &:/root:/bin/csh"
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.
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)
> setvar(loadi, PASSWD, "dacs-kwv-fs:/etc/passwd") 23 > ${PASSWD::root} "*:0:0:Charlie &:/root:/bin/csh" > ${PASSWD::bobo} "bobo:*:1001:1001:Bobo &:/home/bobo:/bin/tcsh"
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":
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(regsplit, dst-namespace, string,
delimiter-regex [, limit])
setvar(query, "Foo", "a=b&c=d&e=f")
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 */ }
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:
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:
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":
(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(uri, dst-namespace, uri)
setvar(split, "ROLES", ${DACS::ROLES}, ",")
> setvar(split, "X", "a\nb\nc\n", "\n") "3" > ${X::0} "a" > ${X::#} "3"
> setvar(split, "X", "/a/long/path", "/") 4
> 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"
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" "
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].
sleep(seconds)
> sizeof(real) 8
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:
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, ...)
source("/usr/local/dacs/scripts/script17") eval(get("/usr/local/dacs/scripts/script17"))
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.
strchars(str, range-spec [,...])
${a} = sprintf("Hello") . ", world." "Hello, world." length(sprintf("Hello") . ", world.") 13
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:
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").
strchop(str, del-spec)
range-start ".." range-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"
This function deletes from the end of str a
continuous run of any characters in del-spec.
strftime(format)
> strchop("foo4.859", ".56789") "foo4" > strchop("foo7.859", ".5679") "foo7.8" > strchop("hello ", " ") "hello" > strchop("dogs rule\n\n", "\n") "dogs rule"
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)
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.
strrstr(string, substring [, nocase])
> 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
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.
strstr(string, substring [, nocase])
> strrstr("afoofoofooz", "foo") "fooz" > strrstr("afOOfoofooz", "FooF", nocase) "foofooz" > strrstr("afOOfoofooz", "ofoo",nocase) "ofooz"
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.
strtolower(string)
> strstr("foobazbar", "baz") "bazbar" > strstr("foobazbar", "") "foobazbar" > strstr("foobazbar", "zzz") "" > strstr("", "zzz") "" > strstr("afoofoofooz", "foo") "foofoofooz" > strstr("fooZbar", "Ozb", nocase) "oZbar"
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":
strtoupper(string)
strtolower("Hello, World 2008") strtr("Hello, World 2008", "A-Z", "a-z")
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":
strtr(input-string, string1, [string2 [,cds]])
strtoupper("Hello, World 2008") strtr("Hello, World 2008", "a-z", "A-Z")
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
subset(format, purported-subset, superset [,
nocase])
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"
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:
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)
subset(",", ${Args::LAYERS:i}, "RELIEF:Foundation,GTOPO30:Foundation")
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.
syntax(type, name [, flag])
> substr("foozle", 3, 4) "ozle" > substr("foobar", -3, 2) "ba" > substr("foobar", -5, -1) "oobar" > substr("foobar", 10, -1) "" > substr("foobar", -10, 3) ""
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)
time(format [, timeval])
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:
syntax(emailaddr, name)
•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
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
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:
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])
•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.
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:
trim(string, delete-set [,limit])
•-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.
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.
typeof([typename,] expression)
> trim("abceffff", "f") "abce" > trim("abceffff", abf) "abce" > trim("a\n\n\n", "\n") "a" > trim("a", "a-z") ""
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.
undef()
> typeof(4.5) "real" > typeof(integer, 4.5) 0
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
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
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,
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:
Here are examples of the user() function. Note that any non-zero
expression value implies True.
Tip
The following two tests are not equivalent:
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 ...])
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" | "!"
True if the DACS identity username
matches.
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
user("METALOGIC:auggie") user(":bobo")
True if jurisdiction matches the name of
the jurisdiction that created the credentials.
federation
user("METALOGIC:") user("DEMO::METALOGIC:")
True if federation matches the name of the
federation that created the credentials.
address
user("DEMO::")
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.
group
user("10.0.0.123") user("10.0.0.0/24") user("example.com")
True if the identity is a member of group,
which is a DACS group.
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
user("%METALOGIC:admin")
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:
style style-list
setvar(load, APP_USERS, "/usr/local/dacs/app_users"); user("namespace APP_USERS")
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:
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:
The following style keywords are understood:
acs
passwd
importedby jurisdiction
user("style passwd,cert")
user("style passwd") and user("style CERT")
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]
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.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.
version protocol-version
user("importedby METALOGIC")
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.
authenticated, unauthenticated
user("version 1.4")
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.
mine
user("auth") user("unauth")
The keyword "mine" (case insensitive) is
True if the user was authenticated by the current jurisdiction.
any
user("mine")
The keyword "any" (case insensitive) is always
True.
none
user("any")
The keyword "none" (case insensitive) is always
False.
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).
user("none")
user("not METALOGIC:rmorriso")
user("not METALOGIC:rmorriso and auth")
1.
Return True if the client was authenticated by the jurisdiction METALOGIC
in this federation
user("METALOGIC:")
2.
Return True if the client was authenticated as the user
METALOGIC:rmorriso
user("METALOGIC:rmorriso")
3.
Return True if the client was authenticated by the given federation and
jurisdiction as rmorriso
user("DEMO::METALOGIC:rmorriso")
4.
Return True if the client is a member of the group METALOGIC:admin
user("%METALOGIC:admin")
5.
Return True if the client was authenticated as the username rmorriso by
any jurisdiction in this federation
user("*:rmorriso")
6.
Return True if the client was authenticated anywhere
user("auth")
7.
Return True if the client is not authenticated
user("UnAuthenticated")
8.
Return True if the client was authenticated through a request from a host
having the IP address 10.0.0.123
user("10.0.0.123")
9.
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)
user("not 10.0.0.123")
10.
Always return True
user("ANY")
11.
Return True if the client has more than one set of current credentials
(i.e., has authenticated as two or more identities)
user("any") gt 1
12.
Return True if the client was authenticated as rmorriso by this
jurisdiction
user(":rmorriso")
13.
Return True if the client was authenticated as rmorriso,
case-insensitively, by this jurisdiction
user(":rmorriso nocase")
14.
Return True if the client was authenticated as the user
metalogic:RMORRISO, but comparing the jurisdiction name, username, and implied
federation name case-insensitively
user("metalogic:RMORRISO nocase")
15.
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
user("METALOGIC:rmorriso default")
user("auth") user("DSS:auth")
This function generates a string called a stamp
that is globally unique and sequenced, with high probability. It has the
following syntax:
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.,
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)
valuesof(alist)
h= hostid, s=seqno
EVAL ${Conf::ustamp_seqno} = "${Conf::DACS_HOME}/seqno"
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"
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:
var(op, namespace, variable-name [, args
...])
> valuesof({red, 17}) 17 > valuesof({red, 17, blue, 100}) [17, 100]
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)
vfs(op, vfs-ref [, argument ...])
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
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 ...]
vfs(put, vfs-ref, key, value)
As do this equivalent statements:
This expression lists the files in the /tmp directory:
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:
This rule fragment denies access if the user has already been granted access
five times:
The item type counter_db would be configured in dacs.conf; e.g.,
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
vfs(defined, item-type)
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.)
Test if the specified item-type has been defined
by a VFS[26] directive.
vfs(delete, vfs-ref [, key])
vfs(defined, "passwds")
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(exists, vfs-ref [, key])
vfs(enabled, "db") ? print("yes") : print("no");
Test whether the referenced object exists, returning
True or False.
vfs(get, vfs-ref [, key])
vfs(exists, "/usr/local/dacs/conf/passwd") vfs(exists, "file:///usr/local/dacs/conf/passwd")
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)
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.
This statement sets a variable to the contents of the file /tmp/somefile:
> vfs(uri, "passwds") "[passwds]dacs-kwv-fs:/usr/local/dacs/conf/passwd?field_sep=:"
${somefile} = vfs(get, "file:///tmp/somefile")
${somefile} = vfs(get, "/tmp/somefile") ${somefile} = get("/tmp/somefile")
vfs(list,"dacs-fs:/tmp")
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");
<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>
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)
- 2.
- Perl
- 3.
- PHP
- 4.
- Tcl
- 5.
- isprint(3)
- 6.
- print()
- 7.
- cast
- 8.
- modifier flag
- 10.
- dacs.conf(5)
- 11.
- dacs_acs(8)
- 12.
- environ(7)
- 13.
- exec()
- 14.
- list()
- 15.
- length()
- 16.
- strchars()
- 17.
- expression grammar
- 18.
- keysof()
- 19.
- valuesof()
- 20.
- alist()
- 21.
- supported data types
- 22.
- variable reference
- 23.
- dacs_notices(8)
- 24.
- alist construction operator
- 25.
- listref()
- 26.
- VFS
- 27.
- revocation list
- 28.
- access control rule
- 29.
- on_success()
- 30.
- AUTH_SUCCESS
- 31.
- ACS_SUCCESS
- 32.
- ADMIN_IDENTITY
- 33.
- approval stamp
- 34.
- dacs64 decoding
- 36.
- dacsauth(1)
- 37.
- dacscheck(1)
- 38.
- encode()
- 39.
- cryptographic hash
- 40.
- MD5 Message-Digest Algorithm
- 41.
- hash()
- 42.
- decode()
- 43.
- radix-85
- 44.
- RFC 2045
- 45.
- RFC 1738
- 46.
- RFC 2396
- 47.
- RFC 3986
- 48.
- execv(3)
- 49.
- basename(1)
- 50.
- dirname(1)
- 51.
- stat
- 52.
- stat(1)
- 53.
- stat(2)
- 54.
- printf(3)
- 55.
- test(1)
- 56.
- mod_access
- 57.
- RFC 1035
- 58.
- CIDR notation
- 59.
- RFC 1338
- 60.
- range specification
- 61.
- regmatch()
- 62.
- user()
- 63.
- digest()
- 64.
- message authentication code
- 65.
- Keyed-Hash Message Authentication Code (HMAC)
- 66.
- Secure Hash Standard functions
- 67.
- MD5 (RFC 2104)
- 68.
- RFC 2253
- 69.
- list construction operator
- 70.
- dacspasswd(1)
- 71.
- PASSWORD_DIGEST
- 72.
- PASSWORD_SALT_PREFIX
- 73.
- local_passwd_authenticate
- 74.
- vfs()
- 75.
- PASSWORD_CONSTRAINTS
- 76.
- dacs.conf(5)
- 77.
- RFC 2898
- 78.
- RFC 3962
- 79.
- LOG_FILTER
- 80.
- cryptographically strong pseudo-random values
- 81.
- strtr()
- 82.
- ACS_ERROR_HANDLER
- 83.
- ErrorDocument directive
- 84.
- Rlinks
- 85.
- permalinks
- 86.
- regex(3)
- 87.
- re_format(7)
- 88.
- access control rules
- 89.
- read-only namespace
- 90.
- RFC 2617
- 91.
- copy
- 92.
- query
- 93.
- cgiparse(8)
- 94.
- split
- 95.
- sleep(3)
- 96.
- sprintf(3)
- 97.
- strftime(3)
- 98.
- strptime(3)
- 99.
- tr(1)
- 00.
- DACS name
- 01.
- RFC 822
- 02.
- RFC 952
- 03.
- FEDERATION_NAME
- 04.
- RFC 1123
- 05.
- RFC 790
- 06.
- JURISDICTION_NAME
- 07.
- strptime()
- 08.
- localtime(3)
- 09.
- dacstransform(1)
- 10.
- transform_config()
- 11.
- concise user syntax
- 12.
- transform()
- 13.
- ACS_CREDENTIALS_LIMIT
- 14.
- from()
- 15.
- dacs.groups(5)
- 16.
- styles
- 19.
- dacscookie(1)
- 20.
- DACS username
- 21.
- dacs.vfs(5)
- 22.
- dacsvfs(1)
- 23.
- VFS URI
- 24.
- www.dss.ca
- 25.
- LICENSE
07/17/2013 | DACS 1.4.28b |