.\" Copyright (c) 2003-2012 .\" Distributed Systems Software. All rights reserved. .\" See the file LICENSE for redistribution information. .\" $Id: copyright-nr 2564 2012-03-02 00:17:08Z brachman $ '\" t .\" Title: dacs.exprs .\" Author: [see the "AUTHOR" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 08/23/2020 .\" Manual: DACS Formats Manual .\" Source: DACS 1.4.40 .\" Language: English .\" .TH "DACS\&.EXPRS" "5" "08/23/2020" "DACS 1.4.40" "DACS Formats Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" dacs.exprs \- \fBDACS\fR expression language .SH "DESCRIPTION" .PP These files are part of the \fBDACS\fR suite\&. .PP \fBDPL\fR (the \fBDACS\fR programming language) is used in access control rules, revocation lists, configuration files, for self\-testing \fBDACS\fR, in general purpose scripts, and interactively\&. The ability to evaluate scripts gives \fBDACS\fR maximum run\-time configurability and flexibility\&. A \fBDPL\fR expression may appear within predicate, allow, and deny elements of an access control rule, for example\&. \fBDPL\fR is also accessible using the \m[blue]\fBdacsexpr(1)\fR\m[]\&\s-2\u[1]\d\s+2 command, which can be used for writing scripts even for non\-\fBDACS\fR applications\&. .PP \fBDPL\fR, which is gradually evolving in mostly backward\-compatible ways, is similar in many ways to \m[blue]\fBPerl\fR\m[]\&\s-2\u[2]\d\s+2, \m[blue]\fBPHP\fR\m[]\&\s-2\u[3]\d\s+2, \m[blue]\fBTcl\fR\m[]\&\s-2\u[4]\d\s+2 and its expressions look and behave much like C/C++ expressions\&. The calling signatures for functions are reminiscent of those of \fBTcl\fR, 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\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .PP The philosophy guiding the design of the \fBDACS\fR expression language is that it should remain small and limited to basic operations on elementary data types that can be expressed simply and evaluated efficiently\&. This is why the language does not include much in the way of control flow statements \- our feeling is that complicated expressions are more likely to introduce mistakes, which can easily result in access control rules not working as intended\&. A collection of utility and higher\-level functions are provided for the typical kinds of tasks at hand\&. Only a subset of the functionality implemented within \fBDACS\fR is accessible through the language\&. .PP While fleshing out the language is not a priority, expression syntax and the set of functions are being extended as necessary\&. An extensibility mechanism has been designed that would let user\-defined functions be loaded at run\-time\&. .PP While there are no immediate plans to do so, replacing the \fBDACS\fR expression language with a general\-purpose extension language may eventually make sense\&. \fBTcl\fR and \fBPerl\fR would be leading contenders\&. .sp .5v .RE .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBTip\fR .ps -1 .br .PP The \m[blue]\fBdacsexpr(1)\fR\m[]\&\s-2\u[1]\d\s+2 utility can be useful for learning, testing, and debugging \fBDPL\fR\&. .sp .5v .RE .SS "Expression Syntax" .PP 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\&. .PP 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 \fBFalse\fR result\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .PP Because files containing expressions are local to the \fBDACS\fR site on which they appear (i\&.e\&., \fBDACS\fR does not copy them), they need not be portable across sites\&. This means that any \fBDACS\fR jurisdiction is free to customize or extend these expressions at will since they do not have to be understood or executed by any other jurisdiction\&. .sp .5v .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBComments\fR .RS 4 .PP Three comment styles are recognized: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The /* \&.\&.\&. */ C style comment syntax, which does not nest; .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The // syntax of C++, where the remainder of the line following the token is ignored; and .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} 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: .sp .if n \{\ .RS 4 .\} .nf > ${foo:? \e#xxx} " #xxx" .fi .if n \{\ .RE .\} .sp .RE .PP Here are examples of all three styles: .sp .if n \{\ .RS 4 .\} .nf /* * This is a comment */ // This is another comment ${x} = 17; # And one last comment .fi .if n \{\ .RE .\} .PP 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 ()\&. Such comments can span multiple lines\&. .sp .if n \{\ .RS 4 .\} .nf STYLE "expr" CONTROL "sufficient" \-\-> .fi .if n \{\ .RE .\} .sp .RE .SS "Basic Data Types" .PP The following basic data types are supported: .PP integer .br int .RS 4 , Integers are represented internally as a C/C++ \fBlong int\fR\&. 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)\&. .RE .PP real .br double .RS 4 , Reals are represented internally as a C/C++ \fBdouble\fR\&. 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 \*(Aqe\*(Aq or \*(AqE\*(Aq followed by at least one digit\&. .RE .PP string .RS 4 A string is a sequence of characters enclosed between matching single or double quotes (e\&.g\&., \*(AqHello world\*(Aq)\&. Interpolation of variables occurs within double quotes but not single quotes\&. C\-style character escape codes and octal and hex numeric escape codes are understood (e\&.g\&., "\et", "\e010", "\exfa") and either quote character (e\&.g\&., \*(AqIt\e\*(Aqs here\*(Aq) and the backslash character (e\&.g\&., "\e\e") can be quoted\&. An unrecognized quoted character is mapped to that character (e\&.g\&., "\ex" is "x")\&. Character strings are limited in length by available memory and are represented internally as a null\-terminated vector\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} 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 \m[blue]\fBisprint(3)\fR\m[]\&\s-2\u[5]\d\s+2) automatically becomes a bstring (see below)\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Because \fBDACS\fR 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 .sp .if n \{\ .RS 4 .\} .nf ${Foo::QUERY_STRING} = "a=1&b=2" .fi .if n \{\ .RE .\} .sp .RE .sp .5v .RE Variable references may occur within a (double\-quoted) string; the value of the variable reference is interpolated at that point\&. If \fI${Foo::bar}\fR is "hello", then the value of "${Foo::bar}, world" is "hello, world"\&. .sp .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br The first expression is invalid and must be written as the second: .sp .if n \{\ .RS 4 .\} .nf foo"baz" foo\&."baz" .fi .if n \{\ .RE .\} .sp .5v .RE .RE .PP binary .br bstring .RS 4 , 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\&. .sp .if n \{\ .RS 4 .\} .nf > "\e0\e1\e2" "000102" .fi .if n \{\ .RE .\} .sp .RE .PP bareword .RS 4 This type is a "literal word" much like Perl\*(Aqs \fIbarewords\fR\&. 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: .sp .if n \{\ .RS 4 .\} .nf file(test, "\-e", foo) file("test", "\-e", "foo") .fi .if n \{\ .RE .\} .sp These two expressions are equivalent and yield "foobaz": .sp .if n \{\ .RS 4 .\} .nf foo\&."baz" foo\&.baz .fi .if n \{\ .RE .\} .sp .RE .PP bool .RS 4 The boolean values \fBTrue\fR and \fBFalse\fR 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 \fB1\fR is the canonical "true" value and \fB0\fR 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 \fBTrue\fR and \fB0\fR is considered \fBFalse\fR\&. For the string data type, both the empty string (i\&.e\&., "") and the string "0" are considered \fBFalse\fR and anything else is considered \fBTrue\fR\&. A binary string is equivalent to \fBFalse\fR if and only if its length is zero\&. An empty list of either variety ("[]" or "{}") is \fBFalse\fR, while any non\-empty list or alist is \fBTrue\fR\&. .RE .PP 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\&. .PP 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\&. .PP 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, \m[blue]\fBprint()\fR\m[]\&\s-2\u[6]\d\s+2 for example\&. A value can be \m[blue]\fBcast\fR\m[]\&\s-2\u[7]\d\s+2 to void\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .PP Support for binary data is only partially implemented\&. .sp .5v .RE .SS "Variables and Namespaces" .PP 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 \fIArgs\fR namespace and variables automatically created by \fBDACS\fR are put in the \fIDACS\fR namespace\&. Namespaces address the problem of a parameter name that happens to have the same name as a variable created by \fBDACS\fR, for example\&. They also allow intermediate results to be stored in their own namespace, also avoiding the problem of clashing variable names\&. .PP 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 \fBDACS\fR 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\&. .PP The interpreter tries to maintain the natural type of a variable when possible, to avoid conversions to and from the string type\&. .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBVariable Syntax\fR .RS 4 .PP A variable reference may have either of the following syntaxes: .sp .if n \{\ .RS 4 .\} .nf ${[\fInamespace\fR::]\fIvariable\-name\fR[:\fIflags\fR]} $[\fInamespace\fR::]\fIvariable\-name\fR .fi .if n \{\ .RE .\} .PP For instance, the following refers to the value of a variable called \fIJURISDICTION_NAME\fR within the namespace called \fIConf\fR: .sp .if n \{\ .RS 4 .\} .nf ${Conf::JURISDICTION_NAME} .fi .if n \{\ .RE .\} .sp A variable called \fIJURISDICTION_NAME\fR within a different namespace could exist and would be completely distinct\&. .PP 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\&. .PP If the namespace is omitted from a variable reference, a default namespace is implied (see below)\&. .PP A variable name consists of any number of alphanumeric characters (upper and lower case), and characters from this set: .sp .if n \{\ .RS 4 .\} .nf \-_\&.!~*\*(Aq() .fi .if n \{\ .RE .\} .sp Additionally, a "%" character that is followed by two hexadecimal characters (upper and lower case) is acceptable\&. .PP Variables having names that would ordinarily be invalid may be created during execution\&. Although they may be visible in some contexts, they cannot be directly referenced or modified\&. .PP 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 \fIConf\fR namespace: .sp .if n \{\ .RS 4 .\} .nf ${Conf::#} .fi .if n \{\ .RE .\} .PP 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 \m[blue]\fBmodifier flag\fR\m[]\&\s-2\u[8]\d\s+2 is an error\&. Referencing an undefined variable yields the empty string\&. .PP Variable names are case sensitive by default; namespaces are always case sensitive\&. .PP User\-defined variables and namespaces are not persistent\&. They disappear when their execution context terminates\&. .PP The variables within a namespace have no predictable natural ordering; the namespace can be thought of as an unordered set of variables\&. This of course does not preclude the application of a naming convention to effectively order the contents of the namespace\&. For example, we might do: .sp .if n \{\ .RS 4 .\} .nf ${Months::first} = "January" ${Months::second} = "February" ${Months::third} = "March" .fi .if n \{\ .RE .\} .sp Or perhaps: .sp .if n \{\ .RS 4 .\} .nf ${Months::0} = "January" ${Months::1} = "February" ${Months::2} = "March" .fi .if n \{\ .RE .\} .sp .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBTip\fR .ps -1 .br .PP A variable reference may not contain any whitespace except when it appears after a ? or + \m[blue]\fBmodifier flag\fR\m[]\&\s-2\u[8]\d\s+2\&. .sp .5v .RE .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBTip\fR .ps -1 .br .PP 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: .sp .if n \{\ .RS 4 .\} .nf ${myvar} $myvar ${foo::baz} $foo::baz .fi .if n \{\ .RE .\} .sp Note that the variable reference ${foo\-17} has a valid but different interpretation if the braces are omitted\&. .sp .5v .RE .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBVariable Modifier Flags\fR .RS 4 .PP A variable reference may include one or more modifier flags that control how the reference is to be interpreted\&. .PP The following modifier flags are recognized: .PP e .RS 4 \fIExists\fR: 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 \fBFalse\fR)\&. .RE .PP i .RS 4 \fIInsensitive\fR: 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\&., \fI${FOO::i}\fR)\&. The namespace lookup is always case sensitive\&. .RE .PP n .RS 4 \fINon\-empty\fR: The "n" modifier flag tests whether the variable exists (has been defined) \fIand\fR 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 \fBFalse\fR)\&. .RE .PP z .RS 4 \fIZero\fR: 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 \fBFalse\fR)\&. .RE .PP ? .RS 4 \fIDefault\fR: 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\&. .RE .PP + .RS 4 \fISubstitute\fR: 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\&. .RE 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\&. .PP Consider these examples: .sp .if n \{\ .RS 4 .\} .nf ${Args::SCALE:?17} ${Foo::bar:i?${Bar::baz\e}baz} "${DACS::QUERY:+?}${DACS::QUERY:?}" .fi .if n \{\ .RE .\} .sp In the first example, if \fI${Args::SCALE}\fR is undefined or empty, the value of the variable reference is "17" instead of the value of \fI${Args::SCALE}\fR\&. In the second example, if \fI${Foo::bar}\fR (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 \fI${DACS::QUERY}\fR is defined and not empty, the value of the expression will be a question mark followed by the value of \fI${DACS::QUERY}\fR\&. If \fI${DACS::QUERY}\fR is undefined or empty, the value will be the empty string\&. .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBReserved Namespaces\fR .RS 4 .PP The following namespaces are predefined by \fBDACS\fR and reserved for particular uses\&. Some are read\-only, which means that only \fBDACS\fR can create a variable or change the value of a variable in the namespace, except in certain contexts\&. .PP \fIArgs\fR .RS 4 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\&. .RE .PP \fIArgv\fR .RS 4 Instantiated by \fBdacsexpr\fR from the command line flags passed to the script\&. The value of \fI${Argv::0}\fR is the name of the file being processed, with \- signifying the standard input\&. The next argument, if any, will be \fI${Argv::1}\fR, and so on\&. This namespace is read\-only\&. .RE .PP \fIAuth\fR .RS 4 Used by \m[blue]\fBdacs_authenticate(8)\fR\m[]\&\s-2\u[9]\d\s+2 during authentication processing\&. .RE .PP \fIConf\fR .RS 4 Instantiated with configuration directive variables, this namespace is made read\-only after configuration processing\&. See \m[blue]\fBdacs\&.conf(5)\fR\m[]\&\s-2\u[10]\d\s+2\&. .RE .PP \fICookies\fR .RS 4 This namespace is instantiated with HTTP cookies that were submitted with a request\&. For security reasons, those associated with \fBDACS\fR 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 \fI${Cookies::foo}\fR\&. .RE .PP \fIDACS\fR .RS 4 Instantiated with \fBDACS\fR\-specific variables\&. It is read\-only\&. See \m[blue]\fBdacs_acs(8)\fR\m[]\&\s-2\u[11]\d\s+2\&. .RE .PP \fIEnv\fR .RS 4 For web services, instantiated with the standard \fBApache\fR environment variables; for other programs, instantiated from the execution environment (\m[blue]\fBenviron(7)\fR\m[]\&\s-2\u[12]\d\s+2)\&. It is read\-only\&. .RE .PP \fIExecEnv\fR .RS 4 Used by \m[blue]\fBexec()\fR\m[]\&\s-2\u[13]\d\s+2\&. .RE .PP \fIExpr\fR .RS 4 Contains variables that control the behaviour of expression evaluation\&. This is a convenience, a kludge, or both\&. .RE .PP \fILDAP\fR .RS 4 Used by \fBlocal_ldap_authenticate\fR\&. .RE .PP \fITemp\fR .RS 4 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: .sp .if n \{\ .RS 4 .\} .nf ${foo} = 17 ${Temp::foo} = 17 $foo = 17 .fi .if n \{\ .RE .\} .sp In a future release, this mechanism may be generalized to provide a run\-time means of selecting the default namespace\&. .RE .RE .SS "Lists, Alists, and Arrays" .PP \fBDPL\fR 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\&. .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBLists\fR .RS 4 .PP A list is composed of zero or more basic data types or sub\-lists\&. A list is created using the following syntax: .sp .if n \{\ .RS 4 .\} .nf \fILIST\fR \-> "[" "]" | "[" \fILIST\-ELS\fR "]" \fILIST\-ELS\fR \-> \fIEL\fR | \fIEL\fR "," \fILIST\-ELS\fR \fIEL\fR \-> \fIBASIC\-DATA\-TYPE\fR | \fILIST\fR .fi .if n \{\ .RE .\} .sp A list can also be created through the \m[blue]\fBlist()\fR\m[]\&\s-2\u[14]\d\s+2 function\&. .PP Here is a list consisting of four elements: .sp .if n \{\ .RS 4 .\} .nf [1, "one", 1\&.000, ["one sublist"]] .fi .if n \{\ .RE .\} .sp The \m[blue]\fBlength()\fR\m[]\&\s-2\u[15]\d\s+2 function returns the number of elements in a list\&. .PP A list can be assigned to a variable: .sp .if n \{\ .RS 4 .\} .nf $mylist = [1, 2, 3, 4, 5, 6] $mylist_copy = $mylist .fi .if n \{\ .RE .\} .sp .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .PP These two statements are equivalent: .sp .if n \{\ .RS 4 .\} .nf $mylist = ["one", "two"] ${mylist} = ["one", "two"] .fi .if n \{\ .RE .\} .sp And so are these two: .sp .if n \{\ .RS 4 .\} .nf $mylist[0] ${mylist}[0] .fi .if n \{\ .RE .\} .sp Modifier flags therefore do not apply to list elements, only the list variable\&. .sp .5v .RE .PP 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\&. .sp .if n \{\ .RS 4 .\} .nf > $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] .fi .if n \{\ .RE .\} .PP A list element can be referenced using a subscript between zero and one less than the number of elements in the list: .sp .if n \{\ .RS 4 .\} .nf > $mylist = [1, 2, 3, 4, 5, 6]; length($mylist) 6 > $mylist[0] 1 .fi .if n \{\ .RE .\} .sp 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\&.) .PP 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\&. .sp .if n \{\ .RS 4 .\} .nf \fILIST\-REFERENCE\fR \-> "[" \fILIST\-REFERENCE\-ELS\fR "]" \fILIST\-REFERENCE\-ELS\fR \-> \fIEMPTY\fR | \fILIST\-REFERENCE\-EL\fR | \fILIST\-REFERENCE\-EL\fR "," \fILIST\-REFERENCE\-ELS\fR \fILIST\-REFERENCE\-EL\fR \-> \fIEXP\fR | \fILIST\-REFERENCE\-SLICE\fR \fILIST\-REFERENCE\-SLICE\fR \-> \fIEXP\fR "\&.\&." \fIEXP\fR \fILIST\-REFERENCE\-SEQ\fR \-> \fILIST\-REFERENCE\fR | \fILIST\-REFERENCE\fR \fILIST\-REFERENCE\-SEQ\fR .fi .if n \{\ .RE .\} .sp An \fIEXP\fR 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\*(Aqs 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\&. .sp .if n \{\ .RS 4 .\} .nf > $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] .fi .if n \{\ .RE .\} .PP The dotdot operator can also be used to construct an element of a list or alist: .sp .if n \{\ .RS 4 .\} .nf > $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] .fi .if n \{\ .RE .\} .PP 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\&. .PP List references can be composed as a right\-associative operation\&. For example: .sp .if n \{\ .RS 4 .\} .nf > $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 .fi .if n \{\ .RE .\} .sp .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBTip\fR .ps -1 .br .PP Individual characters and sequences of characters of a string\-valued expression can be selected using \m[blue]\fBstrchars()\fR\m[]\&\s-2\u[16]\d\s+2, which uses a similar syntax\&. .sp .5v .RE .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .PP .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The list constructor and list reference syntax has not yet been integrated with the \m[blue]\fBexpression grammar\fR\m[]\&\s-2\u[17]\d\s+2\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} 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: .sp .if n \{\ .RS 4 .\} .nf > $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] .fi .if n \{\ .RE .\} .sp .RE .sp .5v .RE .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBAlists\fR .RS 4 .PP \fBDPL\*(Aqs\fR associative list, or "alist", is similar to Perl\*(Aqs 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 \m[blue]\fBkeysof()\fR\m[]\&\s-2\u[18]\d\s+2\&. Similarly, \m[blue]\fBvaluesof()\fR\m[]\&\s-2\u[19]\d\s+2 yields the value element or a list of value elements\&. .PP 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\&. .PP An alist has the following syntax: .sp .if n \{\ .RS 4 .\} .nf \fIALIST\fR \-> "{" "}" | "{" \fIALIST\-PAIRS\fR "}" \fIALIST\-PAIRS\fR \-> \fIALIST\-PAIR\fR | \fIALIST\-PAIRS\fR "," \fIALIST\-PAIR\fR \fIALIST\-PAIR\fR \-> \fIKEY\-EL\fR "," \fIVALUE\-EL\fR \fIKEY\-EL\fR \-> \fISTRING\fR \fIVALUE\-EL\fR \-> \fIBASIC\-DATA\-TYPE\fR | \fILIST\fR | \fIALIST\fR .fi .if n \{\ .RE .\} .sp An alist can also be created through the \m[blue]\fBalist()\fR\m[]\&\s-2\u[20]\d\s+2 function\&. .PP Here is an alist consisting of four elements: .sp .if n \{\ .RS 4 .\} .nf {"red", 0, "blue", 2, "green", 5, "black", 7} .fi .if n \{\ .RE .\} .sp The \m[blue]\fBlength()\fR\m[]\&\s-2\u[15]\d\s+2 function returns the number of pairs of elements in an alist\&. .PP An alist can be assigned to a variable: .sp .if n \{\ .RS 4 .\} .nf $myalist = {1, 2, 3, 4, 5, 6} $myalist_copy = $myalist .fi .if n \{\ .RE .\} .PP 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\&. .sp .if n \{\ .RS 4 .\} .nf > $myalist={sunny, 3} {"sunny", 3} > $myalist \&. {rainy, 11} {"sunny", 3, "rainy", 11} > $myalist \&.= {"snowy", 13} {"sunny", 3, "snowy", 13} .fi .if n \{\ .RE .\} .PP 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\&. .sp .if n \{\ .RS 4 .\} .nf > $myalist = {a, 2, b, 4, c, 6}; length($myalist) 3 > $myalist["a"] 2 > $myalist{"b"} {"b", 4} > $myalist{"c", "a"} {"c", 6, "a", 2} .fi .if n \{\ .RE .\} .sp 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\&.) .PP Like regular lists, alist references can be composed as a right\-associative operation: .sp .if n \{\ .RS 4 .\} .nf > $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 .fi .if n \{\ .RE .\} .PP It is possible to convert an alist to a regular list, or vice versa; see the \m[blue]\fBcast\fR\m[]\&\s-2\u[7]\d\s+2 operator\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .PP There is currently no way to delete an alist pair\&. .sp .5v .RE .RE .SS "Expression Grammar" .PP The following grammar is used to construct an expression (EXP) or sequence (S) of expressions\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .PP The syntax is very similar to that of the C programming language\&. It differs with respect to data types, variables, compile\-time operators, and on some minor aspects of grammar\&. .sp .5v .RE .PP A sequence of statements (or simply a sequence) is two or more expressions, with a ";" character separating them\&. The ";" is unnecessary following the last statement in a sequence of statements (and is therefore unnecessary if there is only one expression)\&. The statements are evaluated in the order in which they appear\&. The value of a sequence is that of the last expression, unless an \fBexit\fR or \fBreturn\fR function is invoked, in which case the value of the sequence is the value returned by the function call\&. An error condition will also terminate evaluation of the sequence and yield a result of \fBFalse\fR\&. A sequence within curly braces is called a block\&. .PP \fBFigure\ \&1.\ \&Expression Grammar\fR .sp .if n \{\ .RS 4 .\} .nf \fIS\fR \-> \fIE\fR | \fIE\fR ";" | \fIE\fR ";" \fIS\fR \fIE\fR \-> \fIE2\fR | \fIE2\fR "," \fIE\fR \fIE2\fR \-> \fIE3\fR | \fIVAR ASSIGN_OP\fR \fIE2\fR | \fIIF_ELSEIF_ELSE\fR \fIE3\fR \-> \fIE4\fR | \fIE4\fR "?" \fIE\fR ":" \fIE\fR \fIE4\fR \-> \fIE5\fR | \fIE5\fR \fIOR\fR \fIE5\fR \fIE5\fR \-> \fIE6\fR | \fIE6\fR \fIAND\fR \fIE5\fR \fIE6\fR \-> \fIE7\fR | \fIE7\fR "|" \fIE7\fR \fIE7\fR \-> \fIE8\fR | \fIE8\fR "^" \fIE8\fR \fIE8\fR \-> \fIE9\fR | \fIE9\fR "&" \fIE9\fR \fIE9\fR \-> \fIE10\fR | \fIE10\fR \fIEQ_OP\fR \fIE10\fR \fIE10\fR \-> \fIE11\fR | \fIE11\fR \fIREL_OP\fR \fIE11\fR \fIE11\fR \-> \fIE12\fR | \fIE12\fR "\&." \fIE12\fR \fIE12\fR \-> \fIE13\fR | \fIE13\fR "<<" \fIE13\fR | \fIE13\fR ">>" \fIE13\fR \fIE13\fR \-> \fIE14\fR | \fIE14\fR "+" \fIE14\fR | \fIE14\fR "\-" \fIE14\fR \fIE14\fR \-> \fIE15\fR | \fIE15\fR "*" \fIE15\fR | \fIE15\fR "/" \fIE15\fR | \fIE15\fR "%" \fIE15\fR \fIE15\fR \-> \fIE16\fR | \fIE16\fR "^" \fIE14\fR | \fIE16\fR "**" \fIE14\fR \fIE16\fR \-> \fIE17\fR | \fINOT\fR \fIE16\fR | "~" \fIE16\fR | "++" \fIVAR\fR | "\-\-" \fIVAR\fR | "+" \fIE\fR | "\-" \fIE\fR | "(" \fItype\fR ")" \fIE17\fR \-> "(" \fIE\fR ")" | \fIVAR\fR "++" | \fIVAR\fR "\-\-" | \fIFUNCTION_CALL\fR | \fIPRIMARY\fR \fIASSIGN_OP\fR \-> "=" | "+=" | "\-=" | "*=" | "/=" | "%=" | ">>=" | "<<=" | "&=" | "^=" | "|=" | "\&.=" \fIPRIMARY\fR \-> \fIa number\fR | \fIa string\fR | \fIVAR\fR \fIOR\fR \-> "||" | "or" \fIAND\fR \-> "&&" | "and" \fINOT\fR \-> "!" | "not" \fIEQ_OP\fR \-> "==" | "!=" | "eq" | "ne" \fIREL_OP\fR \-> "<" | "<=" | ">" | ">=" | "lt" | "le" | "gt" | "ge" \fIVAR\fR \-> \fIa variable reference\fR \fIFUNCTION_CALL\fR \-> \fIFUNCTION_NAME\fR "(" \fIARG_LIST\fR ")" \fIARG_LIST\fR \-> \fIEMPTY\fR | \fIE2\fR | \fIARG_LIST\fR "," \fIE2\fR \fIEMPTY\fR \-> .fi .if n \{\ .RE .\} .PP Keywords and function names are case sensitive\&. .PP The production \fIVAR\fR \fIASSIGN_OP\fR \fIE\fR in the grammar refers to assignment of the evaluation of \fIE\fR to a variable using the given assignment operator (\fIASSIGN_OP\fR)\&. For example, .sp .if n \{\ .RS 4 .\} .nf ${a} += 17 .fi .if n \{\ .RE .\} .sp Provided \fI${a}\fR has been initialized to an integer value, this expression increments it by 17\&. .PP The production \fIIF_ELSEIF_ELSE\fR represents a familiar if statement with zero or more elseif components and an optional else component: .sp .if n \{\ .RS 4 .\} .nf if (\fIexpression\fR) { \fIsequence\fR } [elseif (\fIexpression\fR) { \fIsequence\fR }] \&.\&.\&. [else { \fIsequence\fR }] .fi .if n \{\ .RE .\} .sp Each \fIblock\fR is an optional sequence of statements\&. Braces are mandatory\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBTip\fR .ps -1 .br .PP An if_elseif_else statement has a value: it is either that of the last statement executed in the selected block, or the empty string if no statement is executed\&. In this example, \fI${a}\fR is set to either \fB33\fR or ${b} \- 1, depending on whether \fI${b}\fR is greater than eight: .sp .if n \{\ .RS 4 .\} .nf ${a} = if (${b} > 8) {${b}++; 33;} else {${b} \- 1} .fi .if n \{\ .RE .\} .sp Here are additional examples: .sp .if n \{\ .RS 4 .\} .nf > "hello, " \&. (if (0) {b \&. y \&. e} else {"world"}) "hello, world" > encode(hex, if (1 ge 1) { "hi" } else {"bye"}) "6869" .fi .if n \{\ .RE .\} .sp .5v .RE .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .PP As in C, function calls, nested assignment operators, and increment and decrement operators cause side effects where the value of a variable is changed during expression evaluation\&. Because exactly when such side effects take place is left unspecified, programmers should avoid writing code with these kinds of dependencies on evaluation ordering\&. .sp .5v .RE .SS "Operators" .PP 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\*(Aqs), with operators in the same section having equal precedence\&. The result of applying an operator is one of the \m[blue]\fBsupported data types\fR\m[]\&\s-2\u[21]\d\s+2, or an error\&. Parentheses can be applied to subexpressions in the usual way\&. .PP 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\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .PP In the examples that follow, the \*(Aq>\*(Aq character at the beginning of an input line is a prompt from \m[blue]\fBdacsexpr(1)\fR\m[]\&\s-2\u[1]\d\s+2\&. .sp .5v .RE .PP , .RS 4 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\&. .RE .PP =, +=, \-=, *=, /=, %=, >>=, <<=, &=, ^=, |=, \&.= .RS 4 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\*(Aqs similar to \fBPerl\fR\*(Aqs syntax)\&. .sp .if n \{\ .RS 4 .\} .nf > ${foo::bar} = "hello" "hello" > ${foo::bar} \&.= ", world" "hello, world" > ${a} = [1, 2] [1,2] > ${a} \&.= [3, 4] [1,2,3,4] .fi .if n \{\ .RE .\} .sp .RE .PP ?: .RS 4 This is equivalent to the C/C++ conditional expression, which has right to left associativity\&. If the first expression is \fBTrue\fR, the result is the value of the second expression (the third is not evaluated)\&. If the first expression is \fBFalse\fR, the result is the value of the third expression (the second is not evaluated)\&. .RE .PP or, || .RS 4 This is the C/C++ logical OR operator, which yields \fB1\fR (\fBTrue\fR) if either operand is \fBTrue\fR, otherwise it yields \fB0\fR (\fBFalse\fR)\&. 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\&. .RE .PP and, && .RS 4 This is the C/C++ logical AND operator, which yields \fB1\fR (\fBTrue\fR) if both operands are \fBTrue\fR, otherwise it yields \fB0\fR (\fBFalse\fR)\&. 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\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br When expressions are parsed as XML attribute values, an \*(Aq&\*(Aq character must be encoded as the five characters \*(Aq&\*(Aq\&. .sp .5v .RE .RE .PP | .RS 4 This is the C/C++ bitwise inclusive OR operator\&. Both operands must be integers\&. .RE .PP ^ .RS 4 This is the C/C++ bitwise exclusive OR operator\&. Both operands must be integers\&. .RE .PP & .RS 4 This is the C/C++ bitwise AND operator\&. Both operands must be integers\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br When expressions are parsed as XML attribute values, an \*(Aq&\*(Aq character must be encoded as the five characters \*(Aq&\*(Aq\&. .sp .5v .RE .RE .PP ==, !=, eq, ne, eq:i, ne:i .RS 4 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\&. .sp 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(\fIstring\fR) bytes\&. The case flag is ignored if at least one argument is a bstring\&. .RE .PP <, <=, >, >=, lt, le, lt:i, le:i, gt, ge, gt:i, ge:i .RS 4 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\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br When expressions are parsed as XML attribute values, the \*(Aq<\*(Aq character must be encoded as the four characters \*(Aq<\*(Aq; the same applies to the "greater than" symbol\&. .sp .5v .RE The symbolic and alphabetic versions of the relational operators are semantically identical\&. So >= and ge mean exactly the same thing\&. The latter form may sometimes be more convenient\&. .sp If either argument is of type bstring 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(\fIstring\fR) bytes\&. The case flag is ignored if at least one argument is a bstring\&. .RE .PP \&. .RS 4 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\&. .sp .if n \{\ .RS 4 .\} .nf > "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]] .fi .if n \{\ .RE .\} .sp .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br A period will be recognized as a decimal point in a real number context rather than as the dot operator, so the input: .sp .if n \{\ .RS 4 .\} .nf 4\&.5 .fi .if n \{\ .RE .\} .sp will be scanned as a number whereas, for example, the input: .sp .if n \{\ .RS 4 .\} .nf "4"\&.5 .fi .if n \{\ .RE .\} .sp will evaluate to the string "45"\&. .sp .5v .RE .RE .PP <<, >> .RS 4 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\&. .RE .PP +, \- .RS 4 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\&. .RE .PP *, /, % .RS 4 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\&. .RE .PP ** .RS 4 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\&. .sp .if n \{\ .RS 4 .\} .nf > 2**10 1024 .fi .if n \{\ .RE .\} .sp .RE .PP +, \-, not, !, ~, ++\fIVAR\fR, \-\-\fIVAR\fR, (\fItype\fR) .RS 4 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\&. .sp 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\&. .sp The ~ operator is the one\*(Aqs complement (bitwise not) unary operator\&. .sp The ++\fIVAR\fR and \-\-\fIVAR\fR operators are the prefix increment and decrement operators, respectively\&. These operators are followed by a variable reference\&. The variable must have an integer value\&. .sp .if n \{\ .RS 4 .\} .nf > ${foo} = 17, ++${foo} 18 .fi .if n \{\ .RE .\} .sp An explicit type conversion can be forced by using a cast\&. The syntax for this type coercion is: .sp .if n \{\ .RS 4 .\} .nf (\fItype\fR) \fIexpression\fR .fi .if n \{\ .RE .\} .sp The \fItype\fR 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\&. .sp 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: .sp .if n \{\ .RS 4 .\} .nf > (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) "\e0\e1\e2" "" > bstring("\e0\e1\e2",3) \&. bstring("\e3\e4", 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"} .fi .if n \{\ .RE .\} .sp .RE .PP \fIVAR\fR++, \fIVAR\fR\-\-, primary .RS 4 The \fIVAR\fR++ and \fIVAR\fR\-\- operators are the postfix increment and decrement operators, respectively\&. These operators are preceded by a variable reference\&. The variable must have an integer value\&. .sp A primary is a basic \m[blue]\fBdata type\fR\m[]\&\s-2\u[21]\d\s+2 (i\&.e\&., an integer or real number, string, bareword, or binary string), or a \m[blue]\fBvariable reference\fR\m[]\&\s-2\u[22]\d\s+2\&. .RE .SS "Functions" .PP 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)\&. .PP The result of a function call is one of the \m[blue]\fBsupported data types\fR\m[]\&\s-2\u[21]\d\s+2, or an error\&. An invalid function call, including those that fail during execution, yields a \fBFalse\fR result\&. .PP \fBFunction Index:\fR .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBack\fR: notice acknowledgement processing .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBalist\fR: create an alist .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBalistref\fR: create an alist reference .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBargon2\fR: memory\-hard password hash function .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBbstring\fR: convert a string to binary .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBcontains_any\fR: count elements common to two lists .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBcounter\fR: persistent integer counters .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBcsv\fR: comma\-separated value parsing .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBdacs_admin\fR: test if user is an administrator .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBdacs_approval\fR: create or test a signed authorization .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBdacs_meta\fR: get or update metadata .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBdacsauth\fR: perform authentication tests .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBdacscheck\fR: perform authorization tests .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBdebug\fR: control debugging output .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBdecode\fR: convert from a text representation .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBdigest\fR: cryptographic hash functions .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBencode\fR: convert to a text representation .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBeval\fR: evaluate a string .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBexec\fR: execute a program .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBexit\fR: terminate current evaluation .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBexpand\fR: variable interpolation .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBfile\fR: perform an operation on a file .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBfile_group\fR: test if user is associated with file\*(Aqs group .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBfile_owner\fR: test if user is associated with file\*(Aqs owner .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBfrom\fR: test where the current request comes from .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBget\fR: read the contents of a file or VFS object .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBhash\fR: fast hashes .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBhkdf\fR: HMAC\-based extract\-and\-expand key derivation .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBhmac\fR: secure keyed\-hashes .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBhttp\fR: invoke an HTTP request .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBindex\fR: search a string or list .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBinfo\fR: information about namespaces and variables .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBkeysof\fR: extract keys from an alist .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBldap\fR: extract a component from an LDAP name .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBlength\fR: string length .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBlist\fR: create a list .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBlistref\fR: dereference a list .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBon_success\fR: evaluate an expression if authentication or authorization succeeds .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBpassword\fR: compute or check a password hash .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBpathname\fR: filename\-based string interpolation .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBpbkdf2\fR: password\-based key derivation .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBprint\fR: display a string .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBprintf\fR: display a formatted string .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBrandom\fR: generate random values .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBreadline\fR: read one line from stdin .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBredirect\fR: redirect user after access is denied .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBregmatch\fR: string matching .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBregsub\fR: string substitution .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBrequest_match\fR: compare the current request to a URI .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBrequest_match_url_patterns\fR: compare the current request to a list of url_patterns .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBreturn\fR: terminate current evaluation .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBrule\fR: recursive authorization checking .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBscrypt\fR: memory\-hard password\-based derivation .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBsetvar\fR: manipulating collections of variables and parsing strings .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBsizeof\fR: basic data type sizes .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBsleep\fR: suspend execution temporarily .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBsource\fR: read and evaluate external expressions .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBsprintf\fR: format a string .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBstrchars\fR: select characters from a string .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBstrchop\fR: delete characters from the end of a string .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBstrclone\fR: concatenate repeatedly .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBstrftime\fR: format the current date and time .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBstrptime\fR: parse a date and time .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBstrrstr\fR: locate the last instance of a substring .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBstrstr\fR: locate the first instance of a substring .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBstrtolower\fR: map uppercase to lowercase .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBstrtoupper\fR: map lowercase to uppercase .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBstrtr\fR: character transliteration .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBsubset\fR: test if one set is a subset of another .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBsubstr\fR: extract a substring .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBsyntax\fR: perform a syntax check on a string .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBtime\fR: local time and date .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBtransform\fR: filter text through rule\-based transformations .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBtransform_config\fR: set options for transform .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBtrim\fR: delete trailing characters .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBtypeof\fR: get or test data type .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBundef\fR: an undefined value .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBuser\fR: test current user\*(Aqs identity .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBustamp\fR: generate a unique stamp .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBvaluesof\fR: extract values from an alist .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBvar\fR: operations on individual variables .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBvfs\fR: perform a VFS operation .RE .PP \fBack\fR(\fInotice\-uri\fR[, \fI\&.\&.\&.\fR][, EXACT_MATCH | ALL_MATCH]) .RS 4 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 \fInotice\-uri\fR 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 \m[blue]\fBdacs_notices(8)\fR\m[]\&\s-2\u[23]\d\s+2\&. .RE .PP \fBalist\fR([\fIkey\fR, \fIvalue\fR [, \&.\&.\&.]) .RS 4 This function is equivalent to the \m[blue]\fBalist construction operator\fR\m[]\&\s-2\u[24]\d\s+2\&. 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\&. .sp .if n \{\ .RS 4 .\} .nf alist(cars, 2, bikes, 5) .fi .if n \{\ .RE .\} .sp is equivalent to the expression: .sp .if n \{\ .RS 4 .\} .nf {"cars", 2, "bikes", 5} .fi .if n \{\ .RE .\} .sp And the call: .sp .if n \{\ .RS 4 .\} .nf alist(2, xx, [0, 1], yy) .fi .if n \{\ .RE .\} .sp yields: .sp .if n \{\ .RS 4 .\} .nf {"2", xx, "[0,1]", yy} .fi .if n \{\ .RE .\} .sp .RE .PP \fBalistref\fR(\fIlist\fR) .RS 4 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 \m[blue]\fBlistref()\fR\m[]\&\s-2\u[25]\d\s+2\&. .sp .if n \{\ .RS 4 .\} .nf listref({"a", 1, "b", 2, "c", 3}, alistref(["b"])) .fi .if n \{\ .RE .\} .sp is equivalent to the expression: .sp .if n \{\ .RS 4 .\} .nf {"a", 1, "b", 2, "c", 3}{"b"} .fi .if n \{\ .RE .\} .sp the value of which is: .sp .if n \{\ .RS 4 .\} .nf {"b", 2} .fi .if n \{\ .RE .\} .sp .RE .PP \fBargon2\fR(\fIpassword\fR, \fIsalt\fR, \fIsecret\fR, \fIad\fR, \fIoutlen\fR, \fIt_cost\fR, \fIm_cost\fR, \fIlanes\fR, \fIthreads\fR[, \fIalg\fR]) .RS 4 Compute the \m[blue]\fBArgon2\fR\m[]\&\s-2\u[26]\d\s+2 memory\-hard password hash function (a key derivation function), which uses Blake2 as its underlying hash function, on \fIpassword\fR, \fIsalt\fR, \fIsecret\fR, and \fIad\fR (all binary strings, or converted as required), to produce a digest of \fIoutlen\fR bytes, modified by parameters \fIt_cost\fR (the number of iterations), \fIm_cost\fR (the memory requirement, in KB), \fIlanes\fR (the amount of requested parallelism), and \fIthreads\fR (the actual parallelism)\&. By default, the argon2i variant is used\&. As an optional final argument, either of the strings "argon2i" or "argon2d" may appear to select the variant\&. The \fIsecret\fR and \fIad\fR ("associated data") arguments can be zero length strings\&. .sp Argon2 was selected as the winner of the \m[blue]\fBPassword Hashing Competition\fR\m[]\&\s-2\u[27]\d\s+2 in 2015\&. For details, refer to \m[blue]\fBdraft\-irtf\-cfrg\-argon2\-03\fR\m[]\&\s-2\u[28]\d\s+2 and \m[blue]\fBphc\-winner\-argon2\fR\m[]\&\s-2\u[29]\d\s+2\&. .sp .if n \{\ .RS 4 .\} .nf > argon2( bstring("\e1\e1\e1\e1\e1\e1\e1\e1\e1\e1\e1\e1\e1\e1\e1\e1\e1\e1\e1\e1\e1\e1\e1\e1\e1\e1\e1\e1\e1\e1\e1\e1", 0), bstring("\e2\e2\e2\e2\e2\e2\e2\e2\e2\e2\e2\e2\e2\e2\e2\e2", 0), bstring("\e3\e3\e3\e3\e3\e3\e3\e3",0), bstring("\e4\e4\e4\e4\e4\e4\e4\e4\e4\e4\e4\e4",0), 32, 3, 32, 4, 4) "c814d9d1dc7f37aa13f0d77f2494bda1c8de6b016dd388d29952a4c4672b6ce8" .fi .if n \{\ .RE .\} .sp .RE .PP \fBbstring\fR(\fIstring\fR, \fIlength\fR) .br \fBbstring\fR(\fIstring\fR) .RS 4 This function converts the first \fIlength\fR characters of \fIstring\fR (which may also be a bstring and which is converted to a string if necessary) into the binary type\&. The \fIlength\fR argument may be less than the actual length of \fIstring\fR\&. If \fIlength\fR is zero or omitted, the actual length is computed\&. If \fIlength\fR is greater than the actual length, the actual length is used\&. The implicit null character on the end of \fIstring\fR is not considered part of it\&. .sp .if n \{\ .RS 4 .\} .nf > bstring("\e0\e1\e2", 4) "000102" > bstring("\e0\e1\e2", 2) "0001" .fi .if n \{\ .RE .\} .sp .RE .PP \fBcontains_any\fR(\fIformat\fR, \fItest\-set\fR, \fItarget\-set\fR[, nocase]) .RS 4 This function returns a count of the number of elements of \fItest\-set\fR that appear in \fItarget\-set\fR at least once\&. Duplicate elements may appear in \fItest\-set\fR and are considered to be distinct\&. The \fIformat\fR 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\&. .sp .if n \{\ .RS 4 .\} .nf contains_any(",", ${Args::LAYERS:i}, "Nests,Secret_roads,Heritage") contains_any(",", "a,a,b,z", "a,a,a,b,b,b,a,z,z") .fi .if n \{\ .RE .\} .sp The first expression returns \fB3\fR if every element in the third parameter appears at least once (case insensitive) in the second parameter, otherwise the value of the expression is \fB0\fR\&. The second expression returns \fB4\fR\&. .RE .PP \fBcounter\fR(\fIop\fR, \fIvfs\-ref\fR, \fIcounter_name\fR [,\fIvalue\fR]) .RS 4 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 \m[blue]\fBintegers\fR\m[]\&\s-2\u[21]\d\s+2\&. .sp 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 \m[blue]\fBVFS\fR\m[]\&\s-2\u[30]\d\s+2)\&. 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\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br 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\&. .sp .5v .RE .sp .RS 4 .ie n \{\ \h'-04' 1.\h'+01'\c .\} .el \{\ .sp -1 .IP " 1." 4.2 .\} counter(set, \fIvfs\-ref\fR, \fIcounter_name\fR, \fInew\-value\fR) .sp This is used to create a new counter or reset an existing counter\&. The counter\*(Aqs value will be \fInew\-value\fR, which must be an integer, and is the return value\&. .RE .sp .RS 4 .ie n \{\ \h'-04' 2.\h'+01'\c .\} .el \{\ .sp -1 .IP " 2." 4.2 .\} counter(create, \fIvfs\-ref\fR, \fIcounter_name\fR, \fIinitial\-value\fR) .sp This is used to create a new counter if it does not already exist\&. The new counter\*(Aqs value will be \fIinitial\-value\fR, which must be an integer\&. If the counter exists, its value will not be changed and is returned\&. .RE .sp .RS 4 .ie n \{\ \h'-04' 3.\h'+01'\c .\} .el \{\ .sp -1 .IP " 3." 4.2 .\} counter(del[ete], \fIvfs\-ref\fR, \fIcounter_name\fR) .sp This operation deletes an existing counter\&. The operation can be del or delete\&. .RE .sp .RS 4 .ie n \{\ \h'-04' 4.\h'+01'\c .\} .el \{\ .sp -1 .IP " 4." 4.2 .\} counter(exists, \fIvfs\-ref\fR, \fIcounter_name\fR) .sp This operation returns 1 if a counter exists, 0 otherwise\&. .RE .sp .RS 4 .ie n \{\ \h'-04' 5.\h'+01'\c .\} .el \{\ .sp -1 .IP " 5." 4.2 .\} counter(get, \fIvfs\-ref\fR, \fIcounter_name\fR) .sp This operation returns the current counter value\&. .RE .sp .RS 4 .ie n \{\ \h'-04' 6.\h'+01'\c .\} .el \{\ .sp -1 .IP " 6." 4.2 .\} counter(inc|dec, \fIvfs\-ref\fR, \fIcounter_name\fR[, \fIamount\fR]) .sp This operation increments or decrements an existing counter by \fIamount\fR, which must be an integer\&. If \fIamount\fR is not given, 1 is used\&. The updated counter value is returned\&. .RE .sp .RS 4 .ie n \{\ \h'-04' 7.\h'+01'\c .\} .el \{\ .sp -1 .IP " 7." 4.2 .\} counter(decdel, \fIvfs\-ref\fR, \fIcounter_name\fR[, \fIamount\fR]) .sp This operation decrements an existing counter by \fIamount\fR, which must be an integer\&. If \fIamount\fR 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\&. .RE .sp .RS 4 .ie n \{\ \h'-04' 8.\h'+01'\c .\} .el \{\ .sp -1 .IP " 8." 4.2 .\} counter(list, \fIvfs\-ref\fR) .sp This operation returns a list of counters as a string, newline separated, each with its current value\&. .RE .sp Operations that set or change the counter value return the new value\&. .sp For filestores that support locking, read\-only operations obtain a shared lock while the other operations obtain an exclusive lock\&. .sp It is an error to reference a counter that does not exist unless the operation is set or exists\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br To some extent, this function is a poor substitute for a more general Perl\-like \fBtie()\fR function\&. Such a function is being considered\&. .sp Modifications to counters are not atomic\&. Amongst other things, this means that a crash may cause counter updates to be lost\&. .sp .5v .RE A counter would typically be created by running \m[blue]\fBdacsexpr(1)\fR\m[]\&\s-2\u[1]\d\s+2: .sp .if n \{\ .RS 4 .\} .nf % dacsexpr \-e \*(Aqcounter(set, "dacs\-kwv\-fs:/usr/local/dacs/counters/logins", "EXAMPLE::EX:bob", 1)\*(Aq .fi .if n \{\ .RE .\} .sp The counter\*(Aqs value might then be tested in the \m[blue]\fBrevocation list\fR\m[]\&\s-2\u[31]\d\s+2 or by an \m[blue]\fBaccess control rule\fR\m[]\&\s-2\u[32]\d\s+2, for instance: .sp .if n \{\ .RS 4 .\} .nf counter(exists, "dacs\-kwv\-fs:/usr/local/dacs/counters/logins", ${DACS::IDENTITY}) .fi .if n \{\ .RE .\} .sp The counter might be conditionally updated using the \m[blue]\fBon_success()\fR\m[]\&\s-2\u[33]\d\s+2 function, or the \m[blue]\fBAUTH_SUCCESS\fR\m[]\&\s-2\u[34]\d\s+2 or \m[blue]\fBACS_SUCCESS\fR\m[]\&\s-2\u[35]\d\s+2 directives, using an expression like: .sp .if n \{\ .RS 4 .\} .nf counter(decdel, "dacs\-kwv\-fs:/usr/local/dacs/counters/logins", ${DACS::IDENTITY}) .fi .if n \{\ .RE .\} .sp .RE .PP \fBcsv\fR(\fIinput\fR, \fIifs\fR [,\fIstartq\fR, \fIendq\fR]) .RS 4 EXPERIMENTAL\&. Return a list of fields in \fIinput\fR, where each field is separated from the next by any character in \fIifs\fR or terminated by a newline or the end of string\&. A backslash can be used to quote any character\&. A field may also include embedded \fIifs\fR characters by quoting the entire field\&. Any character in the string \fIstartq\fR that appears at the beginning of a field indicates the start of a quoted field; the character at the same index into \fIendq\fR indicates the end of the quoted field (they can be the same character)\&. A quote character embedded within a field has no special meaning if it has not been used as the starting quote character in that field; it is an error if has been used as the starting quote character, it must be escaped\&. Following (\m[blue]\fBRFC 4180\fR\m[]\&\s-2\u[36]\d\s+2, if double quotes are used as both the opening and closing quote characters, an embedded double quote can also be quoted by doubling it\&. An empty field or missing field is parsed as an empty string\&. Spaces preceding a field are ignored\&. When used as a separator character, unlike other separators, multiple consecutive spaces are always equivalent to a single space\&. .RE .PP \fBdacs_admin\fR() .RS 4 This predicate returns \fBTrue\fR if the user making a service request has any credentials that match any specified by the \m[blue]\fBADMIN_IDENTITY\fR\m[]\&\s-2\u[37]\d\s+2 configuration directive\&. .RE .PP \fBdacs_approval\fR(\fIop\fR[, \&.\&.\&.]) .RS 4 This function is used to create an \m[blue]\fBapproval stamp\fR\m[]\&\s-2\u[38]\d\s+2 or inspect or validate one\&. .sp The following operations are available: .PP \fBdacs_approval\fR(approval, \fIdacs64\-approval\-message\fR, \fInamespace\fR) .RS 4 This operation parses the \fIdacs64\-approval\-message\fR (the value of \fBDACS_APPROVAL\fR), setting variables in \fInamespace\fR, after first \m[blue]\fBdacs64 decoding\fR\m[]\&\s-2\u[39]\d\s+2 the argument\&. If \fInamespace\fR exists, its contents are deleted\&. Variables set are: \fIj\fR (jurisdiction name), \fIh\fR (hash/digest name), \fIs\fR (stamp), \fIu\fR (URI), \fIm\fR (HTTP method), and \fIi\fR (user identity)\&. See \m[blue]\fBdacs_acs(8)\fR\m[]\&\s-2\u[38]\d\s+2\&. The signature is \fInot\fR checked\&. The function returns \fBTrue\fR (1) if the approval message is syntactically correct, otherwise \fBFalse\fR (0)\&. .RE .PP \fBdacs_approval\fR(check, \fIdacs64\-approval\-message\fR) .RS 4 The \fIdacs64\-approval\-message\fR is decoded and parsed, and the signature is validated\&. The function returns \fBTrue\fR (1) only if the signature is correct, otherwise \fBFalse\fR (0)\&. .sp 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\&. .RE .PP \fBdacs_approval\fR(create, \fIuri\fR, \fImethod\fR, \fIident\fR, \fIdigest\-name\fR) .RS 4 Create and return a \fIdacs64\-approval\-message\fR (as described above and in \m[blue]\fBdacs_acs(8)\fR\m[]\&\s-2\u[38]\d\s+2), formed from the given arguments and signed by the current jurisdiction\&. .RE .sp .RE .PP \fBdacs_meta\fR(\fIop\fR[, \&.\&.\&.]) .RS 4 This function returns information associated with the current federation, current jurisdiction, or other jurisdictions in the current federation\&. See \m[blue]\fBdacs_list_jurisdictions(8)\fR\m[]\&\s-2\u[40]\d\s+2 for additional information\&. .sp The following operations are available: .PP \fBdacs_meta\fR(federation, \fInamespace\fR) .RS 4 Return metadata for the current federation, setting variables in \fInamespace\fR\&. If \fInamespace\fR exists, its contents are deleted\&. Variables set are: \fIfederation\fR, \fIdomain\fR, \fIfed_id\fR (if available), and \fIfed_public_key\fR (if available, in PEM format)\&. .RE .PP \fBdacs_meta\fR(jname, \fIjurisdiction\-name\fR, \fInamespace\fR) .RS 4 Return metadata for the jurisdiction named \fIjurisdiction\-name\fR in the current federation\&. If \fInamespace\fR exists, its contents are deleted\&. Variables set are: \fIjname\fR, \fIname\fR, \fIalt_name\fR, \fIdacs_url\fR, \fIauthenticates\fR, \fIprompts\fR, \fIauxiliary\fR (if available), and \fIpublic_key\fR (if available, in PEM format)\&. .RE .PP \fBdacs_meta\fR(jurisdiction, \fInamespace\fR) .RS 4 This is equivalent to the jname operation with \fIjurisdiction_name\fR set to the name of the current jurisdiction\&. .RE .PP \fBdacs_meta\fR(list_jurisdictions) .RS 4 Return a newline\-separated list of all jurisdiction names in the current federation\&. A local copy of the metadata is used\&. .RE .PP \fBdacs_meta\fR(update_jurisdiction, \fIjname\fR [,\fIurl\fR]) .RS 4 \fINot implemented\fR\&. Intended to update the local metadata for the jurisdiction name \fIjname\fR\&. If \fIurl\fR is absent, then the current jurisdiction must already have the correct dacs_url attribute in its entry for \fIjname\fR\&. If \fIurl\fR is given, it is assumed to be the URL for \fBdacs_list_jurisdictions\fR and it is used instead of one formed from dacs_url for the jurisdiction\&. .RE .PP \fBdacs_meta\fR(update_jurisdictions, \fIjname\fR) .RS 4 \fINot implemented\fR\&. Intended to update the local metadata for all of the jurisdictions\&. If \fIjname\fR looks like a URL (i\&.e\&., it begins with either "http" or "https", then it is assumed to be the URL for \fBdacs_list_jurisdictions\fR and it is used to obtain a fresh copy of the metadata; otherwise, \fIjname\fR 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\&. .RE .sp .RE .PP \fBdacsauth\fR(\fIdacsauth\-flags\fR) .br \fBdacsauth\fR(\fIarg1\fR, \fIarg2\fR[, \&.\&.\&.]) .RS 4 This function provides an interface to \m[blue]\fBdacsauth(1)\fR\m[]\&\s-2\u[41]\d\s+2\&. 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\&. .sp An alist is returned that has the following three elements: .PP result .RS 4 An integer: 1 if authentication succeeded, 0 if it failed or was not requested, and \-1 if an error occured\&. .RE .PP identity .RS 4 A string: if authentication was requested and succeeded, this is the corresponding identity, otherwise it is the empty string\&. .RE .PP roles .RS 4 A string: if roles were requested (and authentication succeeded, if requested), this is the role descriptor string, otherwise it is the empty string\&. .RE .sp .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBImportant\fR .ps -1 .br 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)\&. .sp .5v .RE .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBSecurity\fR .ps -1 .br Like \fBdacsauth\fR and \fBdacs_authenticate\fR, 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\&. .sp .5v .RE 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=\*(Aq[federation_keys]dacs\-fs:/usr/local/dacs/federations/federation_keys\*(Aq \-u bobo") {"result",0,"identity","","roles","bobo,wheel,www,users"} .fi .if n \{\ .RE .\} .sp .RE .PP \fBdacscheck\fR(\fIdacscheck\-flags\fR) .br \fBdacscheck\fR(\fIarg1\fR, \fIarg2\fR[, \&.\&.\&.]) .RS 4 This function provides an interface to \m[blue]\fBdacscheck(1)\fR\m[]\&\s-2\u[42]\d\s+2, 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\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBImportant\fR .ps -1 .br This function should be considered experimental\&. Use it with caution\&. .sp .5v .RE .RE .PP \fBdebug\fR(\fItype\fR, \fIvalue\fR) .RS 4 This function enables, disables, or adjusts the amount of debugging output produced by the interpreter\&. Output type \fItype\fR is set to \fIvalue\fR, which may be "on", "off", or a non\-negative integer level (the meaning of which depends on \fItype\fR\&. .sp The following \fItype\fR names are recognized: TBD .RE .PP \fBdecode\fR(\fIencoding\-type\fR, \fIstring\fR) .RS 4 This function performs the inverse of \m[blue]\fBencode()\fR\m[]\&\s-2\u[43]\d\s+2 for the same \fIencoding\-type\fR\&. The result is a bstring\&. The function will fail if its argument is not properly encoded\&. .sp For the hex encoding type, alphabetic characters may be upper case or lower case\&. .RE .PP \fBdigest\fR(\fImsg\fR, \fImsg\-len\fR [, \fIdigest\-name\fR]) .br \fBdigest\fR(\fImsg\fR, \fImsg\-len\fR, "SHA\-512/t", \fIt\fR) .br \fBdigest\fR(\fImsg\fR, \fImsg\-len\fR, "Blake2" [, \fIhlen\fR [, \fIkey\fR, \fIkey\-len\fR]]) .RS 4 This function computes a \m[blue]\fBcryptographic hash\fR\m[]\&\s-2\u[44]\d\s+2 of \fImsg\fR (a string or bstring)\&. The \fImsg\-len\fR is the length of \fImsg\fR in bytes; if it is \fB0\fR, its length is implicitly the entire length of \fImsg\fR\&. .sp The following digest algorithms (\fIdigest\-name\fR) are available: .PP "md5" .RS 4 The 128\-bit \m[blue]\fBMD5 Message\-Digest Algorithm\fR\m[]\&\s-2\u[45]\d\s+2 .RE .PP "SHA" .RS 4 The deprecated 160\-bit SHA\-0 algorithm (\m[blue]\fBRFC 6194\fR\m[]\&\s-2\u[46]\d\s+2)\&. .RE .PP "SHA1" .RS 4 The 160\-bit SHA\-1 Secure Hash Algorithm (deprecated)\&. .RE .PP "SHA224" .br "SHA256" .br "SHA384" .br "SHA512" .br "SHA512/224" .br "SHA512/256" .br "SHA512/t" .RS 4 The SHA\-2 functions are as per \m[blue]\fBFIPS 180\-4\fR\m[]\&\s-2\u[47]\d\s+2, except that for "SHA512/t", the value of \fIt\fR, which is the size of the digest output \fIin bits\fR, is provided as an additional parameter that must be a multiple of \fB8\fR\&. The \fIt\fR parameter must also be greater than \fB0\fR, less than \fB512\fR, and not equal to \fB384\fR\&. .RE .PP "SHA3\-224" .br "SHA3\-256" .br "SHA3\-384" .br "SHA3\-512" .RS 4 The SHA\-3 family of functions are implemented as per the \m[blue]\fBFIPS PUB 202, August/2015\fR\m[]\&\s-2\u[48]\d\s+2 standard, except that the extendable\-output functions SHAKE128 and SHAKE256 are not implemented\&. If the additional parameter, \fIt\fR, is present, it is the number of (initial) bits of \fImsg\fR to use and \fImsg\-len\fR is ignored\&. .RE .PP "Blake2" .RS 4 The Blake2 cryptographic hash and message authentication code (see \m[blue]\fBRFC 7693\fR\m[]\&\s-2\u[49]\d\s+2) using the Blake2b flavour\&. By default, the maximum digest length of 64 bytes is produced\&. The optional fourth argument, \fIhlen\fR, specifies the digest length in bytes and must be between 1 and 64, inclusive\&. Optionally following the digest length, key and key length arguments may appear\&. If \fIkey\-len\fR is \fB0\fR, the length is implicitly the entire length of \fIkey\fR, which may not be \fB0\fR or greater than \fB64\fR\&. This API does not currently support salt or personal bytes parameters, or the Blake2s flavour\&. .RE .sp SHA1 is used by default\&. .sp The available digest functions are described by the "\fBdacs \-\-digests\fR" command (see \m[blue]\fBdacs(1)\fR\m[]\&\s-2\u[50]\d\s+2) and listed by \m[blue]\fBdacsversion(1)\fR\m[]\&\s-2\u[51]\d\s+2 and \m[blue]\fBdacs_version(8)\fR\m[]\&\s-2\u[52]\d\s+2\&. The available key derivation functions, such as \m[blue]\fBpbkdf2()\fR\m[]\&\s-2\u[53]\d\s+2 and \m[blue]\fBscrypt()\fR\m[]\&\s-2\u[54]\d\s+2, are also shown\&. .sp The \fIdigest\-name\fR is matched against the names of available hash functions case\-insensitively\&. Non\-consecutive hyphens, underscores, and slashes may be used as equivalent separators in \fIdigest\-name\fR\&. A separator may be omitted if doing so would not join two digits\&. An initial or trailing separator is disallowed\&. For example, "Sha224" matches "SHA\-224", "md\-5" matches "md5", "sha/512" matches "SHA\-512", "sha\-512t" matches "SHA512/t", and "SHA_512_224" matches "SHA512/224", but "sha3224" is invalid for "sha3\-224", as are "sha3\-\-224" and "sha3\-224_"\&. .sp The function value is a bstring and is always printed as a hex string\&. .sp If cryptographic strength is not required, see \m[blue]\fBhash()\fR\m[]\&\s-2\u[55]\d\s+2\&. .sp .if n \{\ .RS 4 .\} .nf > digest("foo", 0, "md5") "acbd18db4cc2f85cedef654fccc4a4d8" > digest("Hello, world", 0, "SHA256") "4ae7c3b6ac0beff671efa8cf57386151c06e58ca53a78d83f36107316cec125f" > digest("abc", 0, "sha512/t", 72) "644d768d5298864595" > digest("\ex0c", 0, "SHA3\-384",7) "b5a8cb0bf073b6b68d95cd33f5b09289670120bb931fc838b830d2592268b9e145a09088172b96eafb0093ef9a85df08" > substr(encode(hex, digest("one two three", 0, blake2, 64, "my secret", 0)), 1, 64) "fc182724dc024b95f62e606859ac806e4edca09a927f6bc8bccd07dade3e4f26" .fi .if n \{\ .RE .\} .sp .RE .PP \fBencode\fR(\fIencoding\-type\fR, \fIarg\fR) .RS 4 This function converts \fIarg\fR, a string or bstring, into a printable text representation that depends on \fIencoding\-type\fR\&. Applying \m[blue]\fBdecode()\fR\m[]\&\s-2\u[56]\d\s+2 with the same \fIencoding\-type\fR to the output of this function will produce a value equivalent to the original \fIarg\fR\&. The result is a string\&. .sp Note that encoding is only a representational or formatting change\&. If secrecy, authentication, or verification of integrity are required, use a cryptographic method\&. .sp The following encoding types are recognized: .PP \fBencode\fR(ascii85, \fIarg\fR) .RS 4 This encoding, also known as \m[blue]\fBradix\-85\fR\m[]\&\s-2\u[57]\d\s+2, 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\&. .sp .if n \{\ .RS 4 .\} .nf > encode(ascii85, decode(hex, "123456789a")) "&i encode(base32, "Auggie") "IF2WOZ3JMU======" > decode(base32,"IF2WOZ3JMU======") "Auggie" .fi .if n \{\ .RE .\} .sp .RE .PP \fBencode\fR(cescape, \fIarg\fR) .RS 4 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\&. .sp .if n \{\ .RS 4 .\} .nf > encode(cescape, bstring("hi\e0\e1\e2\e3\e012", 7)) "hi\e0\e001\e002\e003\en" .fi .if n \{\ .RE .\} .sp .RE .PP \fBencode\fR(dacs64, \fIarg\fR) .RS 4 This encoding type produces a base\-64 encoding of \fIarg\fR using upper\- and lower\-case alphabetics, digits, \*(Aq\-\*(Aq, and \*(Aq_\*(Aq\&. It is similar to the mime encoding except that \*(Aq\-\*(Aq and \*(Aq_\*(Aq are used in the encoding character set instead of \*(Aq+\*(Aq and \*(Aq/\*(Aq\&. This encoding is better suited for use in paths and URIs, for example, and is used extensively within \fBDACS\fR\&. It is sometimes referred to as "the dacs64 encoding" or just "dacs64" in the \fBDACS\fR documentation\&. .sp .if n \{\ .RS 4 .\} .nf > encode(dacs64, bstring("\e0\e0\e0\e1", 4)) "_____\-" .fi .if n \{\ .RE .\} .sp .RE .PP \fBencode\fR(hex, \fIarg\fR) .RS 4 This encoding converts each byte in \fIarg\fR into a hexadecimal character pair\&. .sp .if n \{\ .RS 4 .\} .nf > encode(hex, "Hello") "48656c6c6f" .fi .if n \{\ .RE .\} .sp .RE .PP \fBencode\fR(mime, \fIarg\fR) .RS 4 This encoding applies the MIME base\-64 encoding function (\m[blue]\fBRFC 2045\fR\m[]\&\s-2\u[59]\d\s+2, Section 6\&.8) to its argument and returns the result\&. .sp .if n \{\ .RS 4 .\} .nf > encode(mime, bstring("\e0\e0\e0\e1", 4)) "AAAAAQ==" .fi .if n \{\ .RE .\} .sp .RE .PP \fBencode\fR(percent, \fIarg\fR) .RS 4 All characters are percent\-encoded like they would be for the hex encoding type\&. .sp .if n \{\ .RS 4 .\} .nf > encode(percent, "Hello, world\&.%") "%48%65%6C%6C%6F%2C%20%77%6F%72%6C%64%2E%25" .fi .if n \{\ .RE .\} .sp .RE .PP \fBencode\fR(url, \fIarg\fR) .RS 4 This returns the URL\-encoding of the argument (\m[blue]\fBRFC 1738\fR\m[]\&\s-2\u[60]\d\s+2, \m[blue]\fBRFC 2396\fR\m[]\&\s-2\u[61]\d\s+2 (Section 2\&.4), and \m[blue]\fBRFC 3986\fR\m[]\&\s-2\u[62]\d\s+2)\&. .sp .if n \{\ .RS 4 .\} .nf > encode(url, bstring("a\e0b", 3)) "a%00b" .fi .if n \{\ .RE .\} .sp .RE .sp .RE .PP \fBeval\fR(\fIexpression\fR) .RS 4 This function evaluates its string argument and returns the result\&. .sp The call: .sp .if n \{\ .RS 4 .\} .nf > eval("length(\e"abc\e")") 3 .fi .if n \{\ .RE .\} .RE .PP \fBexec\fR(\fIprog\fR, \fI\&.\&.\&.\fR) .RS 4 The \fBexec\fR function executes \fIprog\fR, waits (indefinitely) for it to terminate, and returns the program\*(Aqs standard output\&. A trailing newline in the output is deleted\&. Optionally, command line arguments to \fIprog\fR may be given; they are automatically converted to strings\&. By default, no environment variables are passed to the program; if the namespace \fIExecEnv\fR exists, however, its contents are used as the executed program\*(Aqs environment variables\&. The exit status of \fIprog\fR is made available as the value of \fI${DACS::status}\fR\&. The program is executed using the \m[blue]\fBexecv(3)\fR\m[]\&\s-2\u[63]\d\s+2 function, not a command shell\&. .sp On POSIX systems, this call returns the string "1\en" on Thursdays, "0\en" on any other day: .sp .if n \{\ .RS 4 .\} .nf > exec("/bin/sh", "\-c", "date | grep \-c ^Thu") "0" .fi .if n \{\ .RE .\} .sp .sp .if n \{\ .RS 4 .\} .nf > ${ExecEnv::PATH} = "/usr/bin"; "/usr/bin" > exec("/bin/sh", "\-c", "printenv"); "PATH=/usr/bin" .fi .if n \{\ .RE .\} .sp .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBSecurity\fR .ps -1 .br The program is executed as the same user and group IDs as the \fBDACS\fR program that calls \fBexec()\fR\&. Take appropriate precautions to prevent unauthorized users from modifying or replacing \fBDACS\fR configuration files, access control rules, and so on\&. .sp .5v .RE .RE .PP \fBexit\fR(\fIresult\fR) .RS 4 Equivalent to \fBreturn\fR, this function causes evaluation of the expression, block, or program being evaluated to terminate and returns \fIresult\fR as the value of the expression or the program\*(Aqs exit status\&. .RE .PP \fBexpand\fR(\fIstring\fR) .RS 4 The argument, a string, is returned with variable references expanded\&. An undefined variable expands to the empty string\&. .sp .if n \{\ .RS 4 .\} .nf > ${a} = 17 17 > "${a}" "17" > \*(Aq${a}\*(Aq "${a}" > expand(\*(Aq${a}\*(Aq) "17" > ${b} = 1999, ${c} = expand(\*(Aq${a}, \e${b}\*(Aq) "17, ${b}" > expand(${c}) "17, 1999" .fi .if n \{\ .RE .\} .sp .RE .PP \fBfile\fR(\fIop\fR [,\fIarg\-list\fR]) .RS 4 This function performs various operations on files and filenames according to \fIop\fR, which is one of the following operation names, followed by command\-specific arguments\&. All arguments must either be strings or literal words\&. .sp .RS 4 .ie n \{\ \h'-04' 1.\h'+01'\c .\} .el \{\ .sp -1 .IP " 1." 4.2 .\} file(basename, \fIstring\fR [,\fIsuffix\fR]) .sp This is used to extract the last component of a pathname and is equivalent to the \m[blue]\fBbasename(1)\fR\m[]\&\s-2\u[64]\d\s+2 command\&. It deletes any prefix that ends with the last slash character in \fIstring\fR, after first stripping trailing slashes, and a \fIsuffix\fR, if present\&. The \fIsuffix\fR is \fInot\fR stripped, however, if it is identical to the remaining characters in \fIstring\fR\&. A non\-existent suffix is ignored\&. The value is the resulting string\&. .sp .if n \{\ .RS 4 .\} .nf > 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" .fi .if n \{\ .RE .\} .sp .RE .sp .RS 4 .ie n \{\ \h'-04' 2.\h'+01'\c .\} .el \{\ .sp -1 .IP " 2." 4.2 .\} file(chmod, \fIabs\-mode\fR, \fIfile\fR) .sp Change the mode of \fIfile\fR to \fIabs\-mode\fR, which is an absolute (octal) file mode (note, however, that \fBDACS\fR always set the process \fBumask\fR to 07)\&. .sp .if n \{\ .RS 4 .\} .nf file(chmod, "0755", "/usr/local/dacs/tmp/foofile") .fi .if n \{\ .RE .\} .RE .sp .RS 4 .ie n \{\ \h'-04' 3.\h'+01'\c .\} .el \{\ .sp -1 .IP " 3." 4.2 .\} file(dirname, \fIstring\fR) .sp Equivalent to the \m[blue]\fBdirname(1)\fR\m[]\&\s-2\u[65]\d\s+2 command, its value is the string that remains after deleting the filename portion of \fIstring\fR (a pathname), beginning with the last slash character to the end of \fIstring\fR, after first stripping trailing slashes\&. .sp .if n \{\ .RS 4 .\} .nf > file(dirname,"/usr/local/dacs/bin/dacsexpr") "/usr/local/dacs/bin" > file(dirname,"/usr/local/dacs///") "/usr/local" .fi .if n \{\ .RE .\} .sp .RE .sp .RS 4 .ie n \{\ \h'-04' 4.\h'+01'\c .\} .el \{\ .sp -1 .IP " 4." 4.2 .\} file(extension, \fIpathname\fR) .sp The returned value is all of the characters in \fIpathname\fR after and including the last dot in the last element\&. If there is no dot in the last element of \fIpathname\fR, the value is the empty string\&. .sp .if n \{\ .RS 4 .\} .nf > file(extension,"acl\-myapp\&.0") "\&.0" .fi .if n \{\ .RE .\} .sp .RE .sp .RS 4 .ie n \{\ \h'-04' 5.\h'+01'\c .\} .el \{\ .sp -1 .IP " 5." 4.2 .\} file(lstat, \fIfmt\fR, \fIfile\fR) .sp This is like the \m[blue]\fBstat\fR\m[]\&\s-2\u[66]\d\s+2 operation, except in the case where the named file is a symbolic link, in which case \fBlstat\fR returns information about the link, while \fBstat\fR returns information about the file the link references\&. .RE .sp .RS 4 .ie n \{\ \h'-04' 6.\h'+01'\c .\} .el \{\ .sp -1 .IP " 6." 4.2 .\} file(mkdir, \fIdirectory\fR [,abs\-mode]) .sp Create \fIdirectory\fR\&. If an absolute (octal) mode is given, the new directory will have that mode (note, however, that \fBDACS\fR always set the process \fBumask\fR to 07)\&. .RE .sp .RS 4 .ie n \{\ \h'-04' 7.\h'+01'\c .\} .el \{\ .sp -1 .IP " 7." 4.2 .\} file(readlink, \fIfile\fR) .sp If \fIfile\fR is a symbolic link, print its contents\&. .RE .sp .RS 4 .ie n \{\ \h'-04' 8.\h'+01'\c .\} .el \{\ .sp -1 .IP " 8." 4.2 .\} file(remove, \fIfile\fR) .sp Remove (delete) \fIfile\fR\&. .RE .sp .RS 4 .ie n \{\ \h'-04' 9.\h'+01'\c .\} .el \{\ .sp -1 .IP " 9." 4.2 .\} file(rename, \fIsource\-file\fR, \fItarget\-file\fR) .sp Rename (mv) \fIsource\-file\fR to \fItarget\-file\fR\&. .RE .sp .RS 4 .ie n \{\ \h'-04'10.\h'+01'\c .\} .el \{\ .sp -1 .IP "10." 4.2 .\} file(rmdir, \fIdirectory\fR) .sp Remove (delete) \fIdirectory\fR, which must be empty\&. .RE .sp .RS 4 .ie n \{\ \h'-04'11.\h'+01'\c .\} .el \{\ .sp -1 .IP "11." 4.2 .\} file(stat, \fIfmt\fR, \fIfile\fR) .sp Similar to the \m[blue]\fBstat(1)\fR\m[]\&\s-2\u[67]\d\s+2 command available on some systems, this makes the functionality of the \m[blue]\fBstat(2)\fR\m[]\&\s-2\u[68]\d\s+2 system call available\&. The \fIfmt\fR argument is a \m[blue]\fBprintf(3)\fR\m[]\&\s-2\u[69]\d\s+2\-type descriptor that indicates what file status information is wanted and how it is to be printed\&. Non\-formatting characters, including \en, \et, and \e\e, are copied to the output verbatim\&. .sp The following format specifiers are understood: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} %d .sp The value of \fIst_dev\fR\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} %i .sp The value of \fIst_ino\fR\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} %m .sp The value of \fIst_mode\fR in octal\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} %M .sp The value of \fIst_mode\fR as text\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} %l .sp The value of \fIst_nlink\fR\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} %u .sp The value of \fIst_uid\fR in decimal\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} %U .sp The value of \fIst_uid\fR as text\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} %g .sp The value of \fIst_gid\fR in decimal\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} %G .sp The value of \fIst_gid\fR as text\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} %r .sp The value of \fIst_rdev\fR\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} %s .sp The value of \fIst_size\fR\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} %b .sp The value of \fIst_blksize\fR\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} %n .sp The value of the \fIfile\fR argument\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} %N .sp If the argument is a symbolic link, print the contents of the link, otherwise print the \fIfile\fR argument\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} %ta .sp The value of \fIst_atime\fR in decimal\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} %tA .sp The value of \fIst_atime\fR as text\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} %tm .sp The value of \fIst_mtime\fR in decimal\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} %tM .sp The value of \fIst_mtime\fR as text\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} %tc .sp The value of \fIst_ctime\fR in decimal\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} %tC .sp The value of \fIst_ctime\fR as text\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} %f .sp The name of the host (fileserver) where the file is stored\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} %% .sp A literal \*(Aq%\*(Aq character\&. .RE .sp This excerpt from an access control rule limits access to authenticated users for every file greater than 999 bytes in length that it \fBDACS\fR\-wraps: .sp .if n \{\ .RS 4 .\} .nf user("auth") user("any") and file(stat, "%s", ${DACS::FILENAME}) lt 1000 .fi .if n \{\ .RE .\} .sp .RE .sp .RS 4 .ie n \{\ \h'-04'12.\h'+01'\c .\} .el \{\ .sp -1 .IP "12." 4.2 .\} file(test, \fIop\fR [, \fIargs\fR]) .sp Most of the file\-testing predicates of the \m[blue]\fBtest(1)\fR\m[]\&\s-2\u[70]\d\s+2 command are available\&. .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fB\-b\fR\ \& \fIfile\fR .sp \fBTrue\fR if \fIfile\fR exists and is a block special file\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fB\-c\fR\ \& \fIfile\fR .sp \fBTrue\fR if \fIfile\fR exists and is a character special file\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fB\-d\fR\ \& \fIfile\fR .sp \fBTrue\fR if \fIfile\fR exists and is a directory\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fB\-e\fR\ \& \fIfile\fR .sp \fBTrue\fR if \fIfile\fR exists, regardless of its type\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fB\-f\fR\ \& \fIfile\fR .sp \fBTrue\fR if \fIfile\fR exists and is a regular file\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fB\-g\fR\ \& \fIfile\fR .sp \fBTrue\fR if \fIfile\fR exists and its set group ID flag is set\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fB\-k\fR\ \& \fIfile\fR .sp \fBTrue\fR if \fIfile\fR exists and its sticky bit is set\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fB\-p\fR\ \& \fIfile\fR .sp \fBTrue\fR if \fIfile\fR exists and is a named pipe (FIFO)\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fB\-r\fR\ \& \fIfile\fR .sp \fBTrue\fR if \fIfile\fR exists and is readable (access(file, R_OK) == 0)\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fB\-s\fR\ \& \fIfile\fR .sp \fBTrue\fR if \fIfile\fR exists and has a size greater than zero bytes\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fB\-u\fR\ \& \fIfile\fR .sp \fBTrue\fR if \fIfile\fR exists and its set user ID flag is set\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fB\-w\fR\ \& \fIfile\fR .sp \fBTrue\fR if \fIfile\fR exists and is writable (access(file, W_OK) == 0)\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fB\-x\fR\ \& \fIfile\fR .sp \fBTrue\fR if \fIfile\fR exists and is executable (access(file, X_OK) == 0)\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fB\-L\fR\ \& \fIfile\fR .sp \fBTrue\fR if \fIfile\fR exists and is a symbolic link\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fB\-O\fR\ \& \fIfile\fR .sp \fBTrue\fR if \fIfile\fR exists and its owner matches the effective user id of this process\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fB\-G\fR\ \& \fIfile\fR .sp \fBTrue\fR if \fIfile\fR exists and its group matches the effective group id of this process\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fB\-S\fR\ \& \fIfile\fR .sp \fBTrue\fR if \fIfile\fR exists and is a socket\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fB\-nt\fR\ \& \fIfile1\fR \fIfile2\fR .sp \fBTrue\fR if \fIfile1\fR and \fIfile2\fR exist and the former is newer than the latter\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fB\-ot\fR\ \& \fIfile1\fR \fIfile2\fR .sp \fBTrue\fR if \fIfile1\fR and \fIfile2\fR exist and the former is older than the latter\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fB\-ef\fR\ \& \fIfile1\fR \fIfile2\fR .sp \fBTrue\fR if \fIfile1\fR and \fIfile2\fR exist and refer to the same file\&. .RE .RE .sp .RS 4 .ie n \{\ \h'-04'13.\h'+01'\c .\} .el \{\ .sp -1 .IP "13." 4.2 .\} file(touch, \fIfile\fR [, \fIabs\-mode\fR]) .sp If \fIfile\fR does not exist, it is created; if an absolute (octal) mode is given, the new file will have that mode (note, however, that \fBDACS\fR always set the process \fBumask\fR to 07)\&. If the file exists, its modification time will be set to the current date and time\&. .RE .sp .RE .PP \fBfile_group\fR([\fIpath\fR]) .RS 4 Test if \fIpath\fR (defaults to \fI${DACS::FILENAME}\fR, which is equivalent to Apache\*(Aqs \fBSCRIPT_FILENAME\fR or \fIREQUEST_FILENAME\fR variables) has a group ownership with which the user making the request is associated\&. This is effectively the same as: .sp .if n \{\ .RS 4 .\} .nf file(test, "\-e", ${DACS::FILENAME}) and user("%" \&. ${Conf::JURISDICTION_NAME} \&. ":" \e \&. file(stat, "%G", ${DACS::FILENAME})) .fi .if n \{\ .RE .\} .sp This predicate provides a simple way of limiting access to a file to its group membership with respect to file system permissions: .sp .if n \{\ .RS 4 .\} .nf file_group() .fi .if n \{\ .RE .\} .sp For example, if the user requesting access has been assigned the following roles by the current jurisdiction (e\&.g\&., through \fBlocal_unix_roles\fR): .sp .if n \{\ .RS 4 .\} .nf wheel,www,users .fi .if n \{\ .RE .\} .sp and the resource being requested is the file: .sp .if n \{\ .RS 4 .\} .nf \-rw\-r\-\-r\-\- 1 bobo www 75 Apr 11 12:41 htdocs/foo\&.html .fi .if n \{\ .RE .\} .sp then this predicate would return \fBTrue\fR because the file has group ownership www and the user is associated with that role\&. .sp 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\&. .RE .PP \fBfile_owner\fR([\fIpath\fR]) .RS 4 Test if \fIpath\fR (defaults to \fI${DACS::FILENAME}\fR, which is equivalent to Apache\*(Aqs \fBSCRIPT_FILENAME\fR or \fIREQUEST_FILENAME\fR variables) is owned by the user making the request\&. This is effectively the same as: .sp .if n \{\ .RS 4 .\} .nf file(test, "\-e", ${DACS::FILENAME}) and user(${Conf::JURISDICTION_NAME} \&. ":" \&. file(stat, "%U", ${DACS::FILENAME})) .fi .if n \{\ .RE .\} .sp This predicate provides a simple way of limiting access to a file to its owner with respect to file system permissions: .sp .if n \{\ .RS 4 .\} .nf file_owner() .fi .if n \{\ .RE .\} .sp 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\&. .RE .PP \fBfrom\fR(\fIstring\fR) .RS 4 This predicate is used to test where a request comes from, based on the values of \fBREMOTE_ADDR\fR and \fBREMOTE_HOST\fR\&. These environment variables are passed to \fBDACS\fR from \fBApache\fR\&. The supported argument types are similar to those recognized by the \fBApache\fR \m[blue]\fBmod_authz_host\fR\m[]\&\s-2\u[71]\d\s+2 module\*(Aqs allow and deny directives\&. If either \fBREMOTE_HOST\fR or \fBREMOTE_ADDR\fR are needed to evaluate the argument but are not available, the result will be \fBFalse\fR\&. .sp The string argument may be: .sp .RS 4 .ie n \{\ \h'-04' 1.\h'+01'\c .\} .el \{\ .sp -1 .IP " 1." 4.2 .\} a full or partially matching domain name: .sp .if n \{\ .RS 4 .\} .nf from("metalogic\&.example\&.com") .fi .if n \{\ .RE .\} .sp Here, the function yields \fBTrue\fR if the given domain name matches \fBREMOTE_HOST\fR or is a subdomain of \fBREMOTE_HOST\fR\&. Case\-insensitive matching is performed (\m[blue]\fBRFC 1035\fR\m[]\&\s-2\u[72]\d\s+2)\&. Only complete components are matched, so the above example will match foo\&.metalogic\&.example\&.com but not foonmetalogic\&.example\&.com\&. If \fBREMOTE_ADDR\fR is available but not \fBREMOTE_HOST\fR, a reverse DNS lookup will be performed on the domain name and all IP addresses that result will be tested against \fBREMOTE_ADDR\fR; if this lookup results in an error (i\&.e\&., it fails), then the function raises an error condition\&. .RE .sp .RS 4 .ie n \{\ \h'-04' 2.\h'+01'\c .\} .el \{\ .sp -1 .IP " 2." 4.2 .\} a full IPv4 address in standard dot notation: .sp .if n \{\ .RS 4 .\} .nf from("10\&.0\&.0\&.123") .fi .if n \{\ .RE .\} .RE .sp .RS 4 .ie n \{\ \h'-04' 3.\h'+01'\c .\} .el \{\ .sp -1 .IP " 3." 4.2 .\} a partial IPv4 address (the first one, two, or three bytes) in standard dot notation: .sp .if n \{\ .RS 4 .\} .nf from("10\&.0") .fi .if n \{\ .RE .\} .RE .sp .RS 4 .ie n \{\ \h'-04' 4.\h'+01'\c .\} .el \{\ .sp -1 .IP " 4." 4.2 .\} a network/netmask pair: .sp .if n \{\ .RS 4 .\} .nf from("10\&.0\&.0\&.0/255\&.255\&.0\&.0") .fi .if n \{\ .RE .\} .RE .sp .RS 4 .ie n \{\ \h'-04' 5.\h'+01'\c .\} .el \{\ .sp -1 .IP " 5." 4.2 .\} a network/nnn pair using \m[blue]\fBCIDR notation\fR\m[]\&\s-2\u[73]\d\s+2 (\m[blue]\fBRFC 1338\fR\m[]\&\s-2\u[74]\d\s+2): .sp .if n \{\ .RS 4 .\} .nf from("10\&.0\&.0\&.0/8") .fi .if n \{\ .RE .\} .RE .sp .RS 4 .ie n \{\ \h'-04' 6.\h'+01'\c .\} .el \{\ .sp -1 .IP " 6." 4.2 .\} a full or partial IPv4 address in standard dot notation where any address element can be a decimal number (0 through 255) or a \m[blue]\fBrange specification\fR\m[]\&\s-2\u[75]\d\s+2, similar to that used with \m[blue]\fBstrchars()\fR\m[]\&\s-2\u[16]\d\s+2; note that the range separator in this context is ":" instead of "\&.\&.": : .sp .if n \{\ .RS 4 .\} .nf from("10\&.0\&.[0:100,255]") .fi .if n \{\ .RE .\} .sp In the example above, the two high\-order octets of \fI${DACS::REMOTE_ADDR}\fR 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: .sp .if n \{\ .RS 4 .\} .nf from("10") from("10\&.") from("[10]") from("[10]\&.") from("10\&.0\&.0\&.0/8") from("10\&.0\&.0\&.0/255\&.0\&.0\&.0") .fi .if n \{\ .RE .\} .sp .RE .sp .RS 4 .ie n \{\ \h'-04' 7.\h'+01'\c .\} .el \{\ .sp -1 .IP " 7." 4.2 .\} "all" (always yields \fBTrue\fR and is included for compatibility with \fBApache\fR): .sp .if n \{\ .RS 4 .\} .nf from("all") .fi .if n \{\ .RE .\} .RE .sp An alternative method is to perform a regular expression match against \fI${DACS::REMOTE_ADDR}\fR using \m[blue]\fBregmatch()\fR\m[]\&\s-2\u[76]\d\s+2\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBTip\fR .ps -1 .br To test where a client authenticated from, which is not necessarily the same as the place from which a request is sent, use the \m[blue]\fBuser()\fR\m[]\&\s-2\u[77]\d\s+2 function\&. .sp .5v .RE .RE .PP \fBget\fR(\fIvfs\-ref\fR [,\fIkey\fR]) .RS 4 The file or item specified by \fIvfs\-ref\fR, which may be followed by a \fIkey\fR if it is an indexed filestore, is read and returned\&. The \fIvfs\-ref\fR may be an absolute pathname, an item type, or a \m[blue]\fBvfs_uri\fR\m[]\&\s-2\u[30]\d\s+2, except if called from a standalone application without a \fIkey\fR argument, in which case \fIvfs\-ref\fR may also be a relative pathname\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br 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)\&. .sp .5v .RE .RE .PP \fBhash\fR(\fImsg\fR, \fImsg\-len\fR [,\fIhash\-name\fR]) .RS 4 This function computes a fast hash of \fImsg\fR, a string or bstring\&. The \fImsg\-len\fR is the length of \fImsg\fR in bytes; if it is 0, its length is computed\&. The \fIhash\-name\fR 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 \m[blue]\fBdigest()\fR\m[]\&\s-2\u[78]\d\s+2\&. .sp .if n \{\ .RS 4 .\} .nf > hash("Hello, world", 0) "3696529580" > hash("Hello, world", 0, hash64) "462009511995194717" .fi .if n \{\ .RE .\} .sp .RE .PP \fBhkdf\fR(\fIinput\fR, \fIsalt\fR, \fIinfo\fR, \fIlength\fR, \fIdigest\-name\fR) .RS 4 This function computes an HMAC\-based key derivation function (HKDF) that takes initial keying material and derives from it a cryptographically strong secret key\&. For details, refer to \m[blue]\fBRFC 5869\fR\m[]\&\s-2\u[79]\d\s+2 and \m[blue]\fB\fICryptographic Extraction and Key Derivation: The HKDF Scheme\fR\fR\m[]\&\s-2\u[80]\d\s+2 (Hugo Krawczyk, Proceedings of CRYPTO 2010)\&. .sp The \fIinput\fR, \fIsalt\fR, and \fIinfo\fR arguments are of type string or bstring (converted as required)\&. Only \fIinput\fR must not be zero length\&. A bstring of \fIlength\fR bytes is returned\&. Any \m[blue]\fBHMAC compatible\fR\m[]\&\s-2\u[81]\d\s+2 cryptographic hash function can be given as \fIdigest\-name\fR\&. .sp .if n \{\ .RS 4 .\} .nf > hkdf(decode(hex, "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"), \e decode(hex, "000102030405060708090a0b0c"), \e decode(hex, "f0f1f2f3f4f5f6f7f8f9"), 42, "sha\-256") "3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865" > hkdf("\ex0b\ex0b\ex0b\ex0b\ex0b\ex0b\ex0b\ex0b\ex0b\ex0b\ex0b\ex0b\ex0b\ex0b\ex0b\ex0b\ex0b\ex0b\ex0b\ex0b\ex0b\ex0b", \e "","",42,"sha\-1") "0ac1af7002b3d761d1e55298da9d0506b9ae52057220a306e07b6b87e8df21d0ea00033de03984d34918" .fi .if n \{\ .RE .\} .sp .RE .PP \fBhmac\fR(\fImsg\fR, \fImsg\-len\fR, \fIkey\fR, \fIkey\-len\fR [, \fIdigest\-name\fR]) .RS 4 This function computes a cryptographic \m[blue]\fBmessage authentication code\fR\m[]\&\s-2\u[82]\d\s+2 \- specifically, the \m[blue]\fBKeyed\-Hash Message Authentication Code (HMAC)\fR\m[]\&\s-2\u[83]\d\s+2 \- of \fImsg\fR (a string or bstring), using \fIkey\fR (a string or bstring)\&. The \fImsg\-len\fR is the length of \fImsg\fR in bytes; if it is 0, its length is computed\&. Similarly, \fIkey\-len\fR is the length of \fIkey\fR in bytes and if it is 0, its length is computed\&. The available digests are those listed by the "\fBdacs \-\-digests\fR" command (see \m[blue]\fBdacs(1)\fR\m[]\&\s-2\u[50]\d\s+2) having the HMAC attribute\&. This includes the \m[blue]\fBSecure Hash Standard functions\fR\m[]\&\s-2\u[84]\d\s+2, such as \fBSHA\-512\fR\&. The \fIdigest\-name\fR is case insensitive; if absent, SHA\-1 is used\&. The function value is a bstring\&. .sp Note that the function is not commutative\&. The key is the third argument, not the first\&. If you are not getting the expected value from this function, try exchanging the \fImsg\fR and \fIkey\fR arguments\&. .sp 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\&. .sp .if n \{\ .RS 4 .\} .nf > hmac("Sample #2", 0, decode(hex, "303132333435363738393a3b3c3d3e3f40414243"), 0) "0922d3405faa3d194f82a45830737d5cc6c75d24" > hmac(decode(hex, "4869205468657265"), 0, \e decode(hex, "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"), 0, "sha3\-224") "3b16546bbc7be2706a031dcafd56373d9884367641d8c59af3c860f7" .fi .if n \{\ .RE .\} .sp .RE .PP \fBhttp\fR(\fIurl\fR, [\fImethod\fR [,\fIarglist\fR]]) .RS 4 This function sends an HTTP request to \fIurl\fR, 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 \fIurl\fR 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\&. .sp 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/TLS, passing it two parameters, FOO=17 and FOO=2: .sp .if n \{\ .RS 4 .\} .nf > ${x} = http("http://example\&.com") > http("https://example\&.com:8443/cgi\-bin/dacs_prenv\&.cgi", "GET", "FOO", 17, "BAZ", 1+1) .fi .if n \{\ .RE .\} .sp .RE .PP \fBindex\fR(\fIstring\fR, \fIcharacter\-class\fR [, nocase]) .br \fBindex\fR(\fIlist\fR, \fIsearch_operand\fR [, nocase]) .RS 4 If the first argument is a string, this function returns the first position in \fIstring\fR (counting from 1) where the first character in \fIcharacter\-class\fR was found, or 0\&. Case\-sensitive character comparison is used unless the optional \fInocase\fR literal argument is present\&. .sp If the first argument is a list, the position of element \fIsearch_operand\fR (counting from 1) in \fIlist\fR 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 \fInocase\fR literal argument is present\&. .sp Examples: .sp .if n \{\ .RS 4 .\} .nf > 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 .fi .if n \{\ .RE .\} .sp .RE .PP \fBinfo\fR(namespaces) .br \fBinfo\fR(namespace, \fInamespace\-name\fR) .RS 4 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\&. .sp Examples: .sp .if n \{\ .RS 4 .\} .nf info(namespaces) info(namespace, "Conf") .fi .if n \{\ .RE .\} .sp .RE .PP \fBkeysof\fR(\fIalist\fR) .RS 4 If its argument is a single pair, the pair\*(Aqs 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 \m[blue]\fBvaluesof()\fR\m[]\&\s-2\u[19]\d\s+2\&. .sp Examples: .sp .if n \{\ .RS 4 .\} .nf > keysof({red, 17}) "red" > keysof({red, 17, blue, 100}) ["red", "blue"] .fi .if n \{\ .RE .\} .sp .RE .PP \fBldap\fR(dn_length, \fIdn\-string\fR) .br \fBldap\fR(dn_index, \fIdn\-string\fR, \fInth\fR) .br \fBldap\fR(rdn_length, \fIrdn\-string\fR) .br \fBldap\fR(rdn_index, \fIrdn\-string\fR, \fInth\fR) .br \fBldap\fR(rdn_attrtype, \fIrdn\-string\fR [, \fInth\fR]) .br \fBldap\fR(rdn_attrvalue, \fIrdn\-string\fR [, \fInth\fR]) .RS 4 The \fBldap\fR 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 \m[blue]\fBRFC 2253\fR\m[]\&\s-2\u[85]\d\s+2\&. .sp 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 \fInth\fR RDN component of the DN, where \fInth\fR is an integer greater than zero\&. If \fInth\fR is greater than the number of components, the last component is returned\&. .sp 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 \fInth\fR AttributeTypeAndValue component of the RDN, where \fInth\fR is an integer greater than zero\&. If \fInth\fR is greater than the number of components, the last component is returned\&. .sp The rdn_attrtype mode returns the AttributeType of the \fInth\fR AttributeTypeAndValue component of the RDN, where \fInth\fR is an integer greater than zero\&. If \fInth\fR is missing, it is taken to be 1\&. If \fInth\fR is greater than the number of components, the last component is selected\&. The rdn_attrvalue mode is similar except that it returns the AttributeValue\&. .sp The first and second expressions below return 2, the third expression returns Administrator: .sp .if n \{\ .RS 4 .\} .nf ldap(dn_length, "dc=example,dc=com") ldap(rdn_length, "foo=bar+bar=baz") ldap(rdn_attrvalue, ldap(dn_index, \e "CN=Administrator,CN=Users,DC=example,DC=com", 1)) .fi .if n \{\ .RE .\} .sp .RE .PP \fBlength\fR(\fIstring\fR) .br \fBlength\fR(\fIbstring\fR) .br \fBlength\fR(\fIlist\fR) .br \fBlength\fR(\fIalist\fR) .RS 4 This function returns the length, in characters, of \fIstring\fR, the number of bytes in binary string \fIbstring\fR, the number of elements in \fIlist\fR, or the number of pairs in \fIalist\fR\&. .RE .PP \fBlist\fR([\fIvalue\fR [, \&.\&.\&.]) .RS 4 This function is equivalent to the \m[blue]\fBlist construction operator\fR\m[]\&\s-2\u[86]\d\s+2\&. .sp .if n \{\ .RS 4 .\} .nf list(1, 2, [hello, world], 5) .fi .if n \{\ .RE .\} .sp is equivalent to the expression: .sp .if n \{\ .RS 4 .\} .nf [1, 2, [hello, world], 5] .fi .if n \{\ .RE .\} .sp .RE .PP \fBlistref\fR(\fIlist\fR, \fIlist\-ref\fR [, \&.\&.\&.]) .RS 4 This function provides an alternate syntax to the language\*(Aqs list/array notation\&. For example, the function call: .sp .if n \{\ .RS 4 .\} .nf listref([1, 2, [3, 4], 5], 2, 1) .fi .if n \{\ .RE .\} .sp is equivalent to the expression: .sp .if n \{\ .RS 4 .\} .nf [1, 2, [3, 4], 5][2][1] .fi .if n \{\ .RE .\} .sp 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: .sp .if n \{\ .RS 4 .\} .nf ($a \&. $b)[0] .fi .if n \{\ .RE .\} .sp The parentheses are necessary here because the subscript binds more tightly than the concatenation operator\&. This expression can also be written as: .sp .if n \{\ .RS 4 .\} .nf listref($a \&. $b, 0) .fi .if n \{\ .RE .\} .sp .RE .PP \fBon_success\fR(\fIlist\-name\fR [, \fIexpr\fR]) .RS 4 The \fIlist\-name\fR 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 \fIexpr\fR argument (a string) will be evaluated by \fBdacs_acs\fR immediately after any \m[blue]\fBACS_SUCCESS\fR\m[]\&\s-2\u[35]\d\s+2 directive, and just prior to program termination\&. These expressions are not evaluated if authorization is denied, an authorization processing error occurs, or a \fIDACS_ACS\fR argument prevents execution of the request\&. For the latter case, if authentication is successful, the \fIexpr\fR argument (a string) will be evaluated by \m[blue]\fBdacs_authenticate(8)\fR\m[]\&\s-2\u[9]\d\s+2 immediately after any \m[blue]\fBAUTH_SUCCESS\fR\m[]\&\s-2\u[34]\d\s+2 directive, and just prior to program termination\&. These expressions are not evaluated if authentication fails or an authentication processing error occurs\&. .sp Once added to either list, an entry cannot be removed\&. The expressions are evaluated in the order in which \fBon_success()\fR was called\&. The values returned by the expressions are discarded and errors are ignored\&. .sp If no \fIexpr\fR 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\&. .RE .PP \fBpassword\fR(\fIop\fR [, \fIop\-args\fR]) .RS 4 This function performs a variety of read\-only operations on \fBDACS\fR accounts and their passwords\&. See \m[blue]\fBdacspasswd(1)\fR\m[]\&\s-2\u[87]\d\s+2 and directives \m[blue]\fBPASSWORD_DIGEST\fR\m[]\&\s-2\u[88]\d\s+2 and \m[blue]\fBPASSWORD_SALT_PREFIX\fR\m[]\&\s-2\u[89]\d\s+2 for additional information\&. .sp The following operations are available (the operation is specified by the first argument to the function): .PP \fBpassword\fR(check, \fIgiven\-password\fR, \fIpassword\-digest\fR [,\fIalg\-name\fR]) .RS 4 With the check operation, the digest of \fIgiven\-password\fR is computed (as computed by the hash operation) and compared to \fIpassword\-digest\fR, which was previously generated by the hash operation of this function, retrieved by the getdigest operation, or obtained using \fBdacspasswd\fR\&. This algorithm is identical to the one used by \m[blue]\fBlocal_passwd_authenticate\fR\m[]\&\s-2\u[90]\d\s+2 to validate passwords\&. If \fIalg\-name\fR is given, it names the digest algorithm to use instead of the one specified within \fIpassword\-digest\fR\&. If \fIgiven\-password\fR is correct (i\&.e\&., the same passwords were used to generate the two digest values), \fBTrue\fR (1) is returned, otherwise \fBFalse\fR (0) is returned\&. .RE .PP \fBpassword\fR(getdata, \fIusername\fR [,\fIvfs\-ref\fR]) .RS 4 The getdata operation returns the private data associated with the account for \fIusername\fR\&. 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 \fIvfs\-ref\fR 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\&. .RE .PP \fBpassword\fR(getdigest, \fIusername\fR [,\fIvfs\-ref\fR]) .RS 4 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\&. .RE .PP \fBpassword\fR(hash, \fIplain\-password\fR [,\fIalg\-name\fR]) .RS 4 With the hash operation, a (new) digest of the string \fIplain\-password\fR is returned as a printable string\&. The password hashing algorithm is identical to the one used by \m[blue]\fBdacspasswd(1)\fR\m[]\&\s-2\u[87]\d\s+2\&. If \fIalg\-name\fR is given (see \m[blue]\fBdigest()\fR\m[]\&\s-2\u[78]\d\s+2), it names the digest algorithm to use instead of the configured default\&. .RE .PP \fBpassword\fR(list [, \fIvfs\-ref\fR]) .RS 4 The list operation returns a list of account names, one per line\&. An empty string is returned if there are no accounts\&. If a \fIvfs\-ref\fR is given, it identifies the virtual filestore to use, otherwise the item type passwds is used\&. To test if a password file exists, use \m[blue]\fBvfs()\fR\m[]\&\s-2\u[91]\d\s+2\&. .RE .PP \fBpassword\fR(syntax, \fIpassword\fR [,\fIconstraints\fR]) .RS 4 The syntax operation tests if \fIpassword\fR satisfies the \fIconstraints\fR argument, if provided, otherwise the value of the \m[blue]\fBPASSWORD_CONSTRAINTS\fR\m[]\&\s-2\u[92]\d\s+2 directive\&. The \fIconstraints\fR are specified in the same syntax as the PASSWORD_CONSTRAINTS directive\&. The function returns \fBTrue\fR (1) if the constraints are satisfied, otherwise \fBFalse\fR (0)\&. .RE .PP \fBpassword\fR(test, \fItest\-op\fR, \fIusername\fR [,\fIvfs\-ref\fR]) .RS 4 The test operation applies \fItest\-op\fR to the account entry for \fIusername\fR in the virtual filestore \fIvfs\-ref\fR (or item type passwds)\&. It is an error if the password file does not exist or is unreadable\&. It returns \fBTrue\fR if the test is successful, otherwise the result is \fBFalse\fR\&. The recognized values of \fItest\-op\fR 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)\&. .RE .sp Examples: .sp .if n \{\ .RS 4 .\} .nf > password(hash, "bobo") "2|XYZZYxBhU/7VgJAt2lc\&.G|HL4RQ2vo0uNoXlXnv\&.GcY3Vlf9\&." > password(check, "bobo", "2|XYZZYxBhU/7VgJAt2lc\&.G|HL4RQ2vo0uNoXlXnv\&.GcY3Vlf9\&.") 1 .fi .if n \{\ .RE .\} .sp .RE .PP \fBpathname\fR(\fIpath\fR, \fIhostname\fR, \fIport\fR) .RS 4 Perform string interpolation on \fIpath\fR based on the other arguments\&. For details, please see \m[blue]\fBdacs\&.conf(5)\fR\m[]\&\s-2\u[93]\d\s+2 (where \fIhostname\fR is \fBSERVER_NAME\fR)\&. .RE .PP \fBpbkdf2\fR(\fIpassword\fR, \fIsalt\fR, \fIcount\fR, \fIdklen\fR [, \fIdigest\-name\fR]) .RS 4 Apply a pseudo\-random function (by default, HMAC\-SHA\-1) to \fIpassword\fR and \fIsalt\fR (both binary strings, or converted as required), modified by \fIcount\fR iterations, returning a binary string of length \fIdklen\fR bytes (greater than zero)\&. Optionally, \fIdigest\-name\fR can be provided (see \m[blue]\fBdigest()\fR\m[]\&\s-2\u[78]\d\s+2)\&. For details, please see \m[blue]\fBRFC 2898\fR\m[]\&\s-2\u[94]\d\s+2 and \m[blue]\fBRFC 3962\fR\m[]\&\s-2\u[95]\d\s+2\&. .sp .if n \{\ .RS 4 .\} .nf > pbkdf2("password", "ATHENA\&.MIT\&.EDUraeburn", 1200, 32) "5c08eb61fdf71e4e4ec3cf6ba1f5512ba7e52ddbc5e5142f708a31e2e62b1e13" > pbkdf2("password", decode(hex,"1234567878563412"), 5, 16) "d1daa78615f287e6a1c8b120d7062a49" > pbkdf2("password", "salt", 4096, 20, "SHA256") "c5e478d59288c841aa530db6845c4c8d962893a0" > pbkdf2("1", "2", 1024, 32, "SHA512") "a180451f4618df9515ab0be2c56ac3420287cb8fc015f78494c9394a62ef6e66" .fi .if n \{\ .RE .\} .sp .RE .PP \fBprint\fR(\fI\&.\&.\&.\fR) .RS 4 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 \m[blue]\fBdacsexpr(1)\fR\m[]\&\s-2\u[1]\d\s+2, the string is printed to the standard output; otherwise, it is printed to the \fBDACS\fR log file (or stderr), which can be useful for debugging purposes\&. These log messages are associated with the user class (see the \m[blue]\fBLOG_FILTER\fR\m[]\&\s-2\u[96]\d\s+2 directive)\&. .RE .PP \fBprintf\fR(\fIfmt\fR, \fI\&.\&.\&.\fR) .RS 4 This is a slightly scaled\-down version of the \m[blue]\fBprintf(3)\fR\m[]\&\s-2\u[69]\d\s+2 library function\&. If called from \m[blue]\fBdacsexpr(1)\fR\m[]\&\s-2\u[1]\d\s+2, the string is printed to the standard output; otherwise, it is printed to the \fBDACS\fR log file (or stderr), which can be useful for debugging purposes\&. These log messages are associated with the user class (see the \m[blue]\fBLOG_FILTER\fR\m[]\&\s-2\u[96]\d\s+2 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\&. .RE .PP \fBrandom\fR(bytes, \fInbytes\fR) .br \fBrandom\fR(uint, \fIlo\fR, \fIhi\fR) .br \fBrandom\fR(string, \fInbytes\fR [, \fIspec\fR]) .br \fBrandom\fR(stringc, \fInbytes\fR, \fIspec\fR) .RS 4 The various forms of this function, distinguished by the first argument, return \m[blue]\fBcryptographically strong pseudo\-random values\fR\m[]\&\s-2\u[97]\d\s+2 in various formats\&. The starting point (seed value) for the pseudo\-random sequence cannot be set, meaning that the sequence cannot be (intentionally) reproduced\&. .sp The bytes operation requests \fInbytes\fR bytes of random material\&. The result is a bstring of that length\&. .sp The uint operation requests an unsigned random integer between \fIlo\fR and \fIhi\fR (both unsigned integers), inclusive\&. It is an error if \fIlo\fR is not greater than \fIhi\fR\&. The result is an (unsigned) integer\&. .sp The string operation requests \fInbytes\fR of random material, returned as a hex\-encoded string\&. If a \fIspec\fR argument is present, it uses the character specification syntax of \m[blue]\fBstrtr()\fR\m[]\&\s-2\u[98]\d\s+2 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 \fIspec\fR argument\&. Example: .sp .if n \{\ .RS 4 .\} .nf > random(string,12,"a\-zA\-Z0\-9") "LgROshy6SMMH" > random(string,12,"a\-z") "kehhvwydhhbk" .fi .if n \{\ .RE .\} .sp 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 \fIspec\fR argument is complemented to indicate those characters that may \fInot\fR be used in the encoding of the result\&. .RE .PP \fBreadline\fR() .RS 4 Read one line from /dev/stdin, strip any trailing newline character, and return the string\&. \fIThis function is experimental\fR\&. .RE .PP \fBredirect\fR(\fIerror\-code\fR, \fItarget\fR) .br \fBredirect\fR(\fItarget\fR) .RS 4 Permitted only within the context of an access control rule\*(Aqs deny clause, this function causes expression evaluation and rule processing to stop immediately, access to be denied, and the client to be redirected to \fItarget\fR, a URL that may contain a query component\&. If the \fIerror\-code\fR is present, it must be an ACS error name or number (see the \m[blue]\fBACS_ERROR_HANDLER\fR\m[]\&\s-2\u[99]\d\s+2 directive), otherwise "BY_REDIRECT" is used\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br 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 "&"\&. .sp .5v .RE The \fItarget\fR string is expected to have one of the syntaxes of the document component of \fBApache\*(Aqs\fR \m[blue]\fBErrorDocument directive\fR\m[]\&\s-2\u[100]\d\s+2\&. In essence, this function causes an ACS_ERROR_HANDLER directive to be created and triggered\&. The function returns the \fItarget\fR string, although because of the function\*(Aqs run time behaviour the value cannot be used\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBTip\fR .ps -1 .br 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 \fItarget\fR)\&. The short link is made public\&. It must be \fBDACS\fR\-wrapped; the \fItarget\fR does not need to be\&. Any attempt to access the short link is denied by its rule, but the rule uses the \fBredirect()\fR function, probably with BY_SIMPLE_REDIRECT as the \fIerror\-code\fR (see \m[blue]\fBdacs\&.conf(5)\fR\m[]\&\s-2\u[99]\d\s+2), to redirect the user agent to the \fItarget\fR\&. .sp The following rule demonstrates how this can be done: .sp .if n \{\ .RS 4 .\} .nf setvar(split, "X", ${Env::REQUEST_URI}, "/"); ${x} = var(get, X, ${X::#} \- 1); redirect(BY_SIMPLE_REDIRECT, "https://example\&.com/docs/${x}\&.html"); .fi .if n \{\ .RE .\} .sp With this rule in place, a request like: .sp .if n \{\ .RS 4 .\} .nf https://example\&.com/id/17795821 .fi .if n \{\ .RE .\} .sp would result in a redirect to this target: .sp .if n \{\ .RS 4 .\} .nf https://example\&.com/docs/17795821\&.html .fi .if n \{\ .RE .\} .sp 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 \m[blue]\fBRlinks\fR\m[]\&\s-2\u[101]\d\s+2\&. .sp Because the rule associated with the short link can be changed at any time, this feature can be used to implement smart \m[blue]\fBpermalinks\fR\m[]\&\s-2\u[102]\d\s+2\&. .sp This mechanism can also be used to implement a \m[blue]\fBlinkback\fR\m[]\&\s-2\u[103]\d\s+2 method in which an action is triggered (such as a notification) when a link is invoked\&. .sp .5v .RE .RE .PP \fBregmatch\fR(\fIstring\fR, \fIregex\fR [, \fInamespace\fR] [, nocase]) .RS 4 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 \fIstring\fR argument is then matched against the regular expression, which may contain subexpressions enclosed between \*(Aq(\*(Aq and \*(Aq)\*(Aq (or \*(Aq\e(\*(Aq and \*(Aq\e)\*(Aq)\&. If the match fails, the result is 0\&. If the match succeeds there are several possibilities: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} if there are no subexpressions in \fIregex\fR, the result is an integer that is the number of characters matched\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} if there is at least one subexpression in \fIregex\fR but no \fInamespace\fR (a string argument) is given, the result is the substring of \fIstring\fR that was matched by the entire regular expression\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} if there is at least one subexpression in \fIregex\fR 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 "\fI1\fR" in the namespace, the value of the second subexpression is assigned to a variable named "\fI2\fR" in the namespace, and so on up to the ninth subexpression\&. The variable named "\fI0\fR" 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, \fInamespace\fR is accessible only within the predicate, allow, or deny element in which it appears\&. .RE .sp If the optional \fInocase\fR 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 (\m[blue]\fBregex(3)\fR\m[]\&\s-2\u[104]\d\s+2, \m[blue]\fBre_format(7)\fR\m[]\&\s-2\u[105]\d\s+2)\&. .sp Examples: .sp .if n \{\ .RS 4 .\} .nf > ${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\e\e\&.168\e\e\&.(\&.*)\e\e\&.\&.*", "X") 11 > ${X::1} "7" .fi .if n \{\ .RE .\} .sp .RE .PP \fBregsub\fR(\fIstring\fR, \fIregex\fR, \fIreplacement\fR [, nocase] [,repeat]) .RS 4 This function matches \fIregex\fR against \fIstring\fR, like \m[blue]\fBregmatch()\fR\m[]\&\s-2\u[76]\d\s+2 does, and returns the string that results when the substitution specified by \fIreplacement\fR is applied to the matched text\&. This is similar to the \fBed\fR/\fBvi\fR/\fBsed\fR command "s/regex/replacement/" applied to \fIstring\fR\&. If no match is found, the empty string is returned\&. .sp The optional \fIrepeat\fR literal argument causes the replacement to be applied to all matches; i\&.e\&., like the \fBed\fR/\fBvi\fR/\fBsed\fR command "s/regex/replacement/g"\&. .sp Examples: .sp .if n \{\ .RS 4 .\} .nf > regsub("hello world", "world", "auggie") "hello auggie" > regsub("hello world", "auggie", "world") "" > regsub("hello", "\&.*", "& &") "hello hello" > regsub("one two three", "(\&.*) (\&.*) (\&.*)", "\e${3} \e${2} \e${1}") "three two one" > regsub("one two three", "(\&.*) (\&.*) (\&.*)", \*(Aq${3} ${2} ${1}\*(Aq) "three two one" > strtr(regsub("https://BOB\&.Example\&.com", "\e([^:]*\e)://\e([^\&.]*\e)\e\e\&.\e(\&.*\e)", \*(Aq${1}\-${2}@${3}\*(Aq), "A\-Z", "a\-z") "https\-bob@example\&.com" > regsub("one, bone, cone, hone", "one", "two", repeat) "two, btwo, ctwo, htwo" .fi .if n \{\ .RE .\} .sp .RE .PP \fBrequest_match\fR(\fIuri\-string\fR) .RS 4 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 \fIurl_pattern\fR attribute used in \m[blue]\fBaccess control rules\fR\m[]\&\s-2\u[106]\d\s+2 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 \fB0\fR if \fIuri\-string\fR does not match the current request, otherwise it returns the number of path components of \fIuri\-string\fR that match the current request\&. If the scheme and authority components are given in \fIuri\-string\fR, they count as one naming component\&. .sp Assuming that the current request is http://example\&.com:18123/a/b/c, we get: .sp .if n \{\ .RS 4 .\} .nf > 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 .fi .if n \{\ .RE .\} .sp .RE .PP \fBrequest_match_url_patterns\fR(\fInamespace\fR) .RS 4 The argument is a namespace\&. .RE .PP \fBreturn\fR(\fIresult\fR) .RS 4 Equivalent to \fBexit\fR, this function causes evaluation of the expression to terminate and returns \fIresult\fR as the value of the expression\&. .RE .PP \fBrule\fR(\fIobject\fR, \fIruleset_vfs\fR) .RS 4 The \fBrule\fR predicate is an interface to the \fBDACS\fR rule processing engine\&. It is used to test if the rule set \fIruleset_vfs\fR authorizes \fIobject\fR, much as \m[blue]\fBdacscheck(1)\fR\m[]\&\s-2\u[42]\d\s+2 does\&. The \fIobject\fR 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 \fIpath\fR is mapped internally to a URI as file://\fIpath\fR; e\&.g\&., /myapp is interpreted as file:///myapp (see \m[blue]\fBRFC 1738\fR\m[]\&\s-2\u[60]\d\s+2)\&. .sp 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\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br Only the \fIpath\fR component of the URI is considered when \fBDACS\fR matches an object\*(Aqs name against the url_pattern of an access control rule\&. At present, the object name is not automatically canonicalized or resolved (see \m[blue]\fBRFC 3986\fR\m[]\&\s-2\u[62]\d\s+2), as is usually done by a web server, so relative path components such as "\&." and "\&.\&." should be avoided\&. .sp .5v .RE The \fIruleset_vfs\fR is a URI in the syntax of the \m[blue]\fBVFS\fR\m[]\&\s-2\u[30]\d\s+2 configuration directive\&. .sp The various components of the URI that names the object are available as \fBDACS\fR 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 \fIArgs\fR namespace, just as for \fBDACS\fR\-wrapped web services\&. .sp 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 \fIDACS\fR 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: .sp .if n \{\ .RS 4 .\} .nf ${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 .fi .if n \{\ .RE .\} .sp The value of \fI${Args::entry}\fR will be item1\&. The request method is always GET\&. The variable \fI${DACS::REMOTE_USER}\fR will be set if credentials are available in the execution environment\&. .sp For example, assuming that the file /usr/local/exams/acls/acl\-exams\&.17 contains: .sp .if n \{\ .RS 4 .\} .nf ${Args::user} eq "teacher" time(hour) eq 17 .fi .if n \{\ .RE .\} .sp The following call would only return \fBTrue\fR (\fB1\fR) any day between 5:00pm and 5:59pm: .sp .if n \{\ .RS 4 .\} .nf rule("/exam1\&.html?user=teacher", "dacs\-fs:/usr/local/exams/acls"); .fi .if n \{\ .RE .\} .sp .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Since any rule can call the \fBrule\fR function, take care to avoid infinite recursion\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Although this function is similar in concept to the \m[blue]\fBdacscheck(1)\fR\m[]\&\s-2\u[42]\d\s+2 command, there are some significant differences, particularly with respect to the context available during rule evaluation\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The \fIEnv\fR namespace is not reinitialized or altered during evaluation of rules processed by \fBrule\fR\&. That is, the \fIEnv\fR namespace is the same as the outer\-most one\&. .RE .sp .5v .RE .RE .PP \fBscrypt\fR(\fIpassword\fR, \fIsalt\fR, \fIN\fR, \fIr\fR, \fIp\fR, \fIdklen\fR) .RS 4 Compute the \m[blue]\fBscrypt\fR\m[]\&\s-2\u[107]\d\s+2 memory\-hard password\-based key derivation function, which applies a pseudo\-random function (HMAC\-SHA\-256) to \fIpassword\fR and \fIsalt\fR (both binary strings, or converted as required), modified by CPU/memory cost \fIN\fR, block size \fIr\fR, and parallelization parameter \fIp\fR, returning a binary string of length \fIdklen\fR\&. The last four arguments are integers greater than zero\&. For details, refer to \m[blue]\fBThe scrypt key derivation function\fR\m[]\&\s-2\u[108]\d\s+2 and \m[blue]\fBdraft\-josefsson\-scrypt\-kdf\-03\fR\m[]\&\s-2\u[109]\d\s+2\&. .sp .if n \{\ .RS 4 .\} .nf > scrypt("password", "NaCl", 1024, 8, 16, 32) "fdbabe1c9d3472007856e7190d01e9fe7c6ad7cbc8237830e77376634b373162" .fi .if n \{\ .RE .\} .sp .RE .PP \fBsetvar\fR(\fIop\fR, \fIdst\-namespace\fR [, \fIargs\fR \&.\&.\&.]) .RS 4 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 \fIdst\-namespace\fR\&. .sp The \fIdst\-namespace\fR cannot be a \m[blue]\fBread\-only namespace\fR\m[]\&\s-2\u[110]\d\s+2\&. Unless otherwise specified, if \fIdst\-namespace\fR exists, variables are added to it, with any existing variable assigned its new value\&. .sp The following operations are recognized: .PP \fBsetvar\fR(authorization, \fIdst\-namespace\fR, \fIauth\-str\fR) .RS 4 The \fIauth\-str\fR 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 \fIdst\-namespace\fR\&. If \fIdst\-namespace\fR exists, its contents are deleted first\&. Corresponding to the field names used in \m[blue]\fBRFC 2617\fR\m[]\&\s-2\u[111]\d\s+2 Section 3\&.2\&.2, the following variables are created: \fIAUTH_SCHEME\fR, \fIUSERNAME\fR, \fIPASSWORD\fR, \fIREALM\fR, \fINONCE\fR, \fIDIGEST_URI\fR, \fIRESPONSE\fR, \fIALGORITHM\fR, \fICNONCE\fR, \fIOPAQUE\fR, \fIMESSAGE_QOP\fR, \fINONCE_COUNT\fR, and \fIAUTH_PARAM\fR\&. Any variable that corresponds to a non\-existent field is assigned the empty string\&. .sp The following call sets \fI${Foo::AUTH_SCHEME}\fR to Basic, \fI${Foo::USERNAME}\fR to Bobo, and \fI${Foo::PASSWORD}\fR to myPassWord\&. .sp .if n \{\ .RS 4 .\} .nf setvar(authorization, Foo, "Basic Qm9ibzpteVBhc3NXb3Jk") .fi .if n \{\ .RE .\} .sp .RE .PP \fBsetvar\fR(copy, \fIdst\-namespace\fR, \fIsrc\-namespace\fR) .RS 4 With the copy operation, all variables in an existing namespace \fIsrc\-namespace\fR are copied to \fIdst\-namespace\fR\&. If the latter exists, its contents are deleted, otherwise the namespace is created\&. .RE .PP \fBsetvar\fR(delete, \fIdst\-namespace\fR) .RS 4 The delete operation is used to delete \fIdst\-namespace\fR and its contents\&. .RE .PP \fBsetvar\fR(kwv, \fIdst\-namespace\fR, \fIassign\-char\fR, \fIsep\-chars\fR, \fIstring\fR) .RS 4 For the kwv operation, \fIstring\fR is parsed, creating (or replacing) variables in \fIdst\-namespace\fR\&. The \fIstring\fR 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 \fIassign\-char\fR\&. A keyword/value pair is separated from the next by any character that appears in \fIsep\-chars\fR\&. Here is an example: .sp .if n \{\ .RS 4 .\} .nf setvar(kwv, "Foo", "=", ", ", "a=b, c=d, e=f") .fi .if n \{\ .RE .\} .sp The value of this call is 3 and it sets \fI${Foo::a}\fR to "b", \fI${Foo::c}\fR to "d", and \fI${Foo::e}\fR to "f"\&. .RE .PP \fBsetvar\fR(load, \fIdst\-namespace\fR, \fIfilename\fR) .br \fBsetvar\fR(load, \fIdst\-namespace\fR, \fIitem_type\fR, \fIkey\fR) .br \fBsetvar\fR(load, \fIdst\-namespace\fR, \fIvfs\-ref\fR, \fIkey\fR) .RS 4 Deprecated\&. Use the \m[blue]\fBvfs()\fR\m[]\&\s-2\u[91]\d\s+2 function with the load operator instead\&. .sp The load operator reads the contents of an object that consists of newline\-separated text\&. The first line is assigned the name "0" in \fIdst\-namespace\fR, the second "1", and so on\&. The object can be specified using a filename, as an \fIitem_type\fR, or using a \fIvfs\-ref\fR (see \m[blue]\fBvfs()\fR\m[]\&\s-2\u[91]\d\s+2), .RE .PP \fBsetvar\fR(loadi, \fIdst\-namespace\fR, \fIvfs\-ref\fR) .RS 4 Each item in the indexed text object specified by \fIvfs\-ref\fR (an absolute pathname, an item type, or a \m[blue]\fBVFS URI\fR\m[]\&\s-2\u[30]\d\s+2) is copied to \fIdst\-namespace\fR, with the same index\&. The index must be a valid \fIvariable\-name\fR\&. .sp .if n \{\ .RS 4 .\} .nf > 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" .fi .if n \{\ .RE .\} .sp Here, 23 items are copied into the \fIPASSWD\fR 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\&. .RE .PP \fBsetvar\fR(merge, \fIdst\-namespace\fR, \fIsrc\-namespace\fR) .RS 4 The merge operation is similar to \m[blue]\fBcopy\fR\m[]\&\s-2\u[112]\d\s+2 except that if \fIdst\-namespace\fR exists its contents are not deleted\&. .RE .PP \fBsetvar\fR(post, \fIdst\-namespace\fR [, \fIcontent\-type\fR, \fIstring\fR]) .RS 4 Like \m[blue]\fBquery\fR\m[]\&\s-2\u[113]\d\s+2, this operation parses its input into arguments in \fIdst\-namespace\fR\&. The function reads its standard input, unless a \fIstring\fR 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 \fICONTENT_TYPE\fR and \fICONTENT_LENGTH\fR environment variables must be set (as they are when Apache runs a script that is passed an entity\-body)\&. .sp The form that takes \fIstring\fR is not yet implemented\&. .RE .PP \fBsetvar\fR(query, \fIdst\-namespace\fR, \fIquery\-string\fR) .RS 4 For the query operation, \fIquery\-string\fR is parsed, creating variables in \fIdst\-namespace\fR\&. This uses the same parsing algorithm employed by \m[blue]\fBcgiparse(8)\fR\m[]\&\s-2\u[114]\d\s+2\&. 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 \fI${Foo::a}\fR to "b", \fI${Foo::c}\fR to "d", and \fI${Foo::e}\fR to "f": .sp .if n \{\ .RS 4 .\} .nf setvar(query, "Foo", "a=b&c=d&e=f") .fi .if n \{\ .RE .\} .sp One application of this function it to distinguish query arguments (which are part of the requested resource\*(Aqs URI and made available through the environment variable \fBQUERY_STRING\fR) from arguments supplied in the body of a POST method (or other such method)\&. For example: .sp .if n \{\ .RS 4 .\} .nf 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 */ } .fi .if n \{\ .RE .\} .sp .RE .PP \fBsetvar\fR(regsplit, \fIdst\-namespace\fR, \fIstring\fR, \fIdelimiter\-regex\fR [,\fIlimit\fR]) .RS 4 The regsplit operation is similar to \m[blue]\fBsplit\fR\m[]\&\s-2\u[115]\d\s+2 except that substrings are separated by the regular expression \fIdelimiter\-regex\fR\&. IEEE Std 1003\&.2 ("POSIX\&.2") "extended" regular expressions are used (\m[blue]\fBregex(3)\fR\m[]\&\s-2\u[104]\d\s+2)\&. .RE .PP \fBsetvar\fR(rename, \fIdst\-namespace\fR, \fIsrc\-namespace\fR) .RS 4 The rename operation deletes \fIdst\-namespace\fR, if it exists, and changes the name of \fIsrc\-namespace\fR to \fIdst\-namespace\fR\&. The two namespace arguments must be different\&. .RE .PP \fBsetvar\fR(split, \fIdst\-namespace\fR, \fIstring\fR, \fIdelimiter\fR [,\fIlimit\fR [,\fIdflag\fR]]) .RS 4 The split operation extracts substrings from \fIstring\fR\&. Substrings are separated by the string \fIdelimiter\fR\&. For example, this call separates a composite role string into individual basic roles: .sp .if n \{\ .RS 4 .\} .nf setvar(split, "ROLES", ${DACS::ROLES}, ",") .fi .if n \{\ .RE .\} .sp If the variable reference \fI${DACS::ROLES}\fR has the value "root,wheel,www,users", then the example would return 4 and set \fI${ROLES::0}\fR to "root", \fI${ROLES::1}\fR to "wheel", and so on\&. .sp If a \fIlimit\fR is given, it is an integer that specifies the maximum number of substrings to extract\&. Once the maximum has been reached, the remainder of \fIstring\fR that has not been split will be assigned to the last element\&. A \fIlimit\fR 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 \fI${X::0}\fR and "b,c,d" to \fI${X::1}\fR\&. .sp Here is another example: .sp .if n \{\ .RS 4 .\} .nf > setvar(split, "X", "a\enb\enc\en", "\en") "3" > ${X::0} "a" > ${X::#} "3" .fi .if n \{\ .RE .\} .sp This function can be used to break a pathname into its individual components\&. For instance, the following call results in \fI${X::0}\fR set to the empty string, \fI${X::1}\fR set to "a", \fI${X::2}\fR set to "long", and \fI${X::3}\fR set to "path": .sp .if n \{\ .RS 4 .\} .nf > setvar(split, "X", "/a/long/path", "/") 4 .fi .if n \{\ .RE .\} .sp (You may need to first remove redundant slashes in \fIstring\fR using \m[blue]\fBstrtr()\fR\m[]\&\s-2\u[98]\d\s+2\&.) .sp A \fIdflag\fR argument may follow the \fIlimit\fR argument to indicate whether \fIdelimiter\fR should not be included in substrings (\fIdflag\fR == 0, which is the default behavior), whether it should be included at the start of substrings with the possible exception of the first one (\fIdflag\fR > 0), or whether it should be included at the end of substrings with the possible exception of the last one (\fIdflag\fR < 0)\&. .sp .if n \{\ .RS 4 .\} .nf > 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" .fi .if n \{\ .RE .\} .sp .RE .PP \fBsetvar\fR(uri, \fIdst\-namespace\fR, \fIuri\fR) .RS 4 The given \fIuri\fR, a URI conforming to \m[blue]\fBRFC 2396\fR\m[]\&\s-2\u[61]\d\s+2 or \m[blue]\fBRFC 3986\fR\m[]\&\s-2\u[62]\d\s+2, is parsed into its components\&. Variables in \fIdst\-namespace\fR are set accordingly: \fISCHEME\fR (mapped to lower case), \fIHOST\fR (mapped to lower case), \fIAUTHORITY\fR, \fIPORT\fR, \fISERVER\fR, \fIUSERINFO\fR, \fIPATH\fR, \fIQUERY\fR, and \fIFRAGMENT\fR\&. If a component is absent from \fIuri\fR, the corresponding variable will not be defined\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBSecurity\fR .ps -1 .br It is possible for \fIUSERINFO\fR (called \fIuser\-pass\fR in \m[blue]\fBRFC 2617\fR\m[]\&\s-2\u[111]\d\s+2) to include either a username (\fIuserid\fR), plaintext password, or both\&. Either subfield may consist of any octet except CTLs but including whitespace, except that the username may not contain a colon\&. Refer to Section 4 of \m[blue]\fBRFC 2617\fR\m[]\&\s-2\u[111]\d\s+2 for security considerations related to this feature\&. .sp .5v .RE In addition, the URI\*(Aqs path component is split into its slash\-delimited pieces\&. The variable \fIPATH_LENGTH\fR is set to the number of such pieces (it will be zero if there are none), and variables \fIPATH_0\fR, \fIPATH_1\fR, 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\&. .sp .if n \{\ .RS 4 .\} .nf > 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" " > ${X::SERVER} "foo\&.example\&.com:8443" .fi .if n \{\ .RE .\} .sp .RE .sp .RE .PP \fBsizeof\fR(\fItypename\fR) .RS 4 This function returns the amount of memory in bytes, as an integer, used by \fItypename\fR, the name of a \m[blue]\fBbasic data type\fR\m[]\&\s-2\u[21]\d\s+2\&. 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 \m[blue]\fBlength()\fR\m[]\&\s-2\u[15]\d\s+2\&. .sp .if n \{\ .RS 4 .\} .nf > sizeof(real) 8 .fi .if n \{\ .RE .\} .sp .RE .PP \fBsleep\fR(\fIseconds\fR) .RS 4 The process is suspended for approximately \fIseconds\fR 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 \m[blue]\fBsleep(3)\fR\m[]\&\s-2\u[116]\d\s+2\&. It can be useful for inserting delays in conjunction with error handlers, for instance\&. .RE .PP \fBsource\fR(\fIvfs\-ref\fR [,\fIkey\fR]) .RS 4 The expressions in the file or item specified by \fIvfs\-ref\fR, which may be followed by a \fIkey\fR if it is an indexed filestore, are read and evaluated as a block\&. The \fIvfs\-ref\fR can be an absolute pathname, an item type, or a \m[blue]\fBVFS URI\fR\m[]\&\s-2\u[30]\d\s+2\&. The value returned is that of the evaluated block\&. The following two expressions are essentially equivalent: .sp .if n \{\ .RS 4 .\} .nf source("/usr/local/dacs/scripts/script17") eval(get("/usr/local/dacs/scripts/script17")) .fi .if n \{\ .RE .\} .sp This function is handy when a lengthy expression is needed but one does not want to clutter a configuration file or a rule\&. .RE .PP \fBsprintf\fR(\fIfmt\fR, \fI\&.\&.\&.\fR) .RS 4 This is a slightly scaled\-down version of the \m[blue]\fBsprintf(3)\fR\m[]\&\s-2\u[117]\d\s+2 library function\&. If necessary and possible, arguments are converted to the type requested by a formatting specification\&. The formatted string is returned\&. .sp .if n \{\ .RS 4 .\} .nf ${a} = sprintf("Hello") \&. ", world\&." "Hello, world\&." length(sprintf("Hello") \&. ", world\&.") 13 .fi .if n \{\ .RE .\} .sp .RE .PP \fBstrchars\fR(\fIstr\fR, \fIrange\-spec\fR [,\&.\&.\&.]) .RS 4 This function returns a new string by selecting characters from \fIstr\fR according to a sequence of one or more range specifications (each one a \fIrange\-spec\fR)\&. A \fIrange\-spec\fR is a string argument that determines the indexes of characters to select within \fIstr\fR\&. Indexes start at zero\&. The result of each successive range specification is appended to the previous result\&. .sp A \fIrange\-spec\fR is an unordered set of one or more comma\-separated elements, each of which is either an \fIindex\fR or a \fIrange\fR\&. An \fIindex\fR may either be a non\-negative integer or "#", which means "all indexes"\&. A \fIrange\fR represents a sequence of indexes and has the syntax: .sp .if n \{\ .RS 4 .\} .nf \fIrange\-start\fR "\&.\&." \fIrange\-end\fR .fi .if n \{\ .RE .\} .sp A \fIrange\-start\fR may be a non\-negative integer, the character "#" (which means "from the beginning"), or may be elided (also meaning "from the beginning")\&. A \fIrange\-end\fR may be a non\-negative integer (not less than \fIrange\-start\fR, if it is also a non\-negative integer), the character "#" (which means "to the end"), or may be omitted (also meaning "to the end")\&. .sp .if n \{\ .RS 4 .\} .nf > $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" .fi .if n \{\ .RE .\} .sp .RE .PP \fBstrchop\fR(\fIstr\fR, \fIdel\-spec\fR) .RS 4 This function deletes from the end of \fIstr\fR a continuous run of any characters in \fIdel\-spec\fR\&. .sp .if n \{\ .RS 4 .\} .nf > strchop("foo4\&.859", "\&.56789") "foo4" > strchop("foo7\&.859", "\&.5679") "foo7\&.8" > strchop("hello ", " ") "hello" > strchop("dogs rule\en\en", "\en") "dogs rule" .fi .if n \{\ .RE .\} .sp .RE .PP \fBstrclone\fR(\fIstr\fR, \fIcount\fR) .RS 4 This function returns the concatenation of \fIcount\fR copies of \fIstr\fR\&. The result has the same type as \fIstr\fR, which may be a string or bstring\&. The \fIcount\fR must not be less than 1\&. A limit is imposed on the length of the result\&. This function is sometimes useful when forming an argument to a hash or encryption function, which often consists of a repeated substring\&. .sp .if n \{\ .RS 4 .\} .nf > strclone("abc", 1) "abc" > strclone("abc", 3) "abcabcabc" > strclone("\ex0b",22) "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b" > strclone(decode(hex, "01"), 7) "01010101010101" .fi .if n \{\ .RE .\} .sp .RE .PP \fBstrftime\fR(\fIformat\fR) .RS 4 This function is an interface to the \m[blue]\fBstrftime(3)\fR\m[]\&\s-2\u[118]\d\s+2 function\&. It is applied to the current date and time\&. .RE .PP \fBstrptime\fR(\fIdate\-str\fR, \fIdate\-format\fR, \fInamespace\fR) .br \fBstrptime\fR(\fInamespace\fR) .RS 4 This function is an interface to the \m[blue]\fBstrptime(3)\fR\m[]\&\s-2\u[119]\d\s+2 function\&. The \fIdate\-str\fR argument is a string representation of a date and/or time, with \fIdate\-format\fR describing its syntax\&. If the parse of \fIdate\-str\fR succeeds, the following elements of \fInamespace\fR are set from the corresponding fields of struct tm: \fItm_sec\fR, \fItm_min\fR, \fItm_hour\fR, \fItm_mday\fR, \fItm_mon\fR, \fItm_year\fR, \fItm_wday\fR, \fItm_yday\fR, \fItm_isdst\fR, \fItm_zone\fR, and \fItm_gmtoff\fR\&. Additionally, a variable named \fIclock\fR is set to the Unix time that corresponds to the parsed date and time\&. Any existing elements of \fInamespace\fR are not modified\&. If \fIdate\-str\fR 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\*(Aqs date" is used)\&. .sp In the single\-argument usage, the current date and time are parsed and \fInamespace\fR is assigned values as previously described\&. .sp The return value is the "Unix time" equivalent of the resulting time and date\&. .sp .if n \{\ .RS 4 .\} .nf > 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 .fi .if n \{\ .RE .\} .sp .RE .PP \fBstrrstr\fR(\fIstring\fR, \fIsubstring\fR [, nocase]) .RS 4 Return the start of the last occurrence of \fIsubstring\fR within \fIstring\fR\&. The empty string is returned if \fIstring\fR is empty or if no occurrence of \fIsubstring\fR is found\&. If \fIsubstring\fR is empty, \fIstring\fR is returned\&. The optional \fInocase\fR literal argument requests case\-insensitive comparison\&. .sp .if n \{\ .RS 4 .\} .nf > strrstr("afoofoofooz", "foo") "fooz" > strrstr("afOOfoofooz", "FooF", nocase) "foofooz" > strrstr("afOOfoofooz", "ofoo",nocase) "ofooz" .fi .if n \{\ .RE .\} .sp .RE .PP \fBstrstr\fR(\fIstring\fR, \fIsubstring\fR [, nocase]) .RS 4 Return the start of the first occurrence of \fIsubstring\fR within \fIstring\fR\&. The empty string is returned if \fIstring\fR is empty or if no occurrence of \fIsubstring\fR is found\&. If \fIsubstring\fR is empty, \fIstring\fR is returned\&. The optional \fInocase\fR literal argument requests case\-insensitive comparison\&. .sp .if n \{\ .RS 4 .\} .nf > strstr("foobazbar", "baz") "bazbar" > strstr("foobazbar", "") "foobazbar" > strstr("foobazbar", "zzz") "" > strstr("", "zzz") "" > strstr("afoofoofooz", "foo") "foofoofooz" > strstr("fooZbar", "Ozb", nocase) "oZbar" .fi .if n \{\ .RE .\} .sp .RE .PP \fBstrtolower\fR(\fIstring\fR) .RS 4 A new string is returned where each uppercase character in \fIstring\fR is mapped to lowercase and all other characters are mapped to themselves\&. These two expressions are equivalent and have the value "hello, world 2008": .sp .if n \{\ .RS 4 .\} .nf strtolower("Hello, World 2008") strtr("Hello, World 2008", "A\-Z", "a\-z") .fi .if n \{\ .RE .\} .sp .RE .PP \fBstrtoupper\fR(\fIstring\fR) .RS 4 A new string is returned where each lowercase character in \fIstring\fR is mapped to uppercase and all other characters are mapped to themselves\&. These two expressions are equivalent and have the value "HELLO, WORLD 2008": .sp .if n \{\ .RS 4 .\} .nf strtoupper("Hello, World 2008") strtr("Hello, World 2008", "a\-z", "A\-Z") .fi .if n \{\ .RE .\} .sp .RE .PP \fBstrtr\fR(\fIinput\-string\fR, \fIstring1\fR, [\fIstring2\fR [,cds]]) .RS 4 This function performs string transliteration, like the \m[blue]\fBtr(1)\fR\m[]\&\s-2\u[120]\d\s+2 command and \fBPerl\fR\*(Aqs tr and y operators\&. The result is the transliterated string\&. The first argument is the input string to be transliterated (stdin in the \fBtr\fR command)\&. The second argument is the search list ("string1" in the \fBtr\fR command)\&. The third argument is the (possibly empty) replacement list ("string2" in the \fBtr\fR command); it may be omitted if no flag string argument follows\&. .sp The fourth, optional argument is a literal flag string made of the characters \*(Aqc\*(Aq, \*(Aqd\*(Aq, and \*(Aqs\*(Aq (in any order), which correspond to the flags of the same name in the \fBtr\fR command: .PP \fBc\fR .RS 4 Complement the set of values in \fIstring1\fR\&. .RE .PP \fBd\fR .RS 4 Delete characters in \fIstring1\fR from the input string\&. .RE .PP \fBs\fR .RS 4 Squeeze multiple occurrences of the characters listed in the last operand (either \fIstring1\fR or \fIstring2\fR) in the input into a single instance of the character\&. This occurs after all deletion and translation is completed\&. .RE .sp .sp .if n \{\ .RS 4 .\} .nf > strtr("AbCdEf", "A\-Z", "a\-z") "abcdef" > strtr("/a//b///c", "/", "", "s") "/a/b/c" .fi .if n \{\ .RE .\} .sp .RE .PP \fBsubset\fR(\fIformat\fR, \fIpurported\-subset\fR, \fIsuperset\fR [, nocase]) .RS 4 This function returns \fBTrue\fR if every element of the purported\-subset appears in superset\&. The \fIformat\fR 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\&. .sp Example: .sp .if n \{\ .RS 4 .\} .nf subset(",", ${Args::LAYERS:i}, "RELIEF:Foundation,GTOPO30:Foundation") .fi .if n \{\ .RE .\} .sp This call returns \fBTrue\fR if every element of the LAYERS parameter (case insensitive) appears in the given list, otherwise the expression is \fBFalse\fR\&. .RE .PP \fBsubstr\fR(\fIstring\fR, \fIstart\-position\fR, \fIlength\fR) .RS 4 This function returns the substring of \fIstring\fR beginning at \fIstart\-position\fR with length at most \fIlength\fR characters\&. The first character is in position one\&. If \fIstart\-position\fR is negative, the position is relative to the end of \fIstring\fR (\-1 specifies the last character in \fIstring\fR)\&. If the effective starting position is outside of \fIstring\fR, an empty string is returned\&. If \fIlength\fR 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 \fIlength\fR exceeds the actual number of characters returned\&. .sp .if n \{\ .RS 4 .\} .nf > substr("foozle", 3, 4) "ozle" > substr("foobar", \-3, 2) "ba" > substr("foobar", \-5, \-1) "oobar" > substr("foobar", 10, \-1) "" > substr("foobar", \-10, 3) "" .fi .if n \{\ .RE .\} .sp .RE .PP \fBsyntax\fR(\fItype\fR, \fIname\fR [, \fIflag\fR]) .RS 4 This function performs a syntax test, specified by \fItype\fR, on \fIname\fR\&. It returns 0 if the test fails, 1 or a \fItype\fR\-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 \fBDACS\fR\&. Note that these are purely syntactical checks\&. They do not test whether an object called \fIname\fR exists or is configured\&. .sp The following tests are recognized: .PP \fBsyntax\fR(charset, \fIname\fR, \fIcharset_spec\fR) .RS 4 Test if each of the characters in \fIname\fR is specified by \fIcharset_spec\fR, which is a character set specification as used by \m[blue]\fBstrtr()\fR\m[]\&\s-2\u[98]\d\s+2 ("the search list")\&. .RE .PP \fBsyntax\fR(dacsname, \fIname\fR) .RS 4 Test if \fIname\fR is valid as a \m[blue]\fB\fBDACS\fR name\fR\m[]\&\s-2\u[121]\d\s+2\&. If the string is recognized, one of the following values is returned to classify it: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} 1 if it is a \fBDACS\fR identity .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} 2 if it is a group name .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} 3 if it is a jurisdiction name .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} 4 if it is a federation name .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} 5 if it is an IP address in numeric dot notation .RE .sp .RE .PP \fBsyntax\fR(emailaddr, \fIname\fR) .RS 4 Test if \fIname\fR is a syntactically valid \m[blue]\fBRFC 822\fR\m[]\&\s-2\u[122]\d\s+2 email address\&. A successful test does not imply that a message can be delivered to the address\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br The implementation does not currently recognize valid addresses where the local\-part (the substring to the left of the \*(Aq@\*(Aq character) contains a quoted\-string component\&. .sp .5v .RE .RE .PP \fBsyntax\fR(expr, \fIname\fR) .RS 4 Test if \fIname\fR 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\&. .RE .PP \fBsyntax\fR(domainname, \fIname\fR) .RS 4 Test if \fIname\fR is a syntactically valid domain name (\m[blue]\fBRFC 952\fR\m[]\&\s-2\u[123]\d\s+2)\&. A successful test does not imply that \fIname\fR exists or has a DNS entry\&. .RE .PP \fBsyntax\fR(federation, \fIname\fR) .RS 4 Test if \fIname\fR is valid as a federation name (e\&.g\&., as the value of \m[blue]\fBFEDERATION_NAME\fR\m[]\&\s-2\u[124]\d\s+2)\&. .RE .PP \fBsyntax\fR(group, \fIname\fR) .RS 4 Test if \fIname\fR is valid as a group name\&. .RE .PP \fBsyntax\fR(hostname, \fIname\fR) .RS 4 Test if \fIname\fR is valid as a host name (an alphanumeric, followed by any number of alphanumerics and hyphens, but not ending with a hyphen; see \m[blue]\fBRFC 952\fR\m[]\&\s-2\u[123]\d\s+2 and \m[blue]\fBRFC 1123\fR\m[]\&\s-2\u[125]\d\s+2)\&. .RE .PP \fBsyntax\fR(ipaddr, \fIname\fR) .RS 4 Test if \fIname\fR is a valid Class C IPv4 address (\m[blue]\fBRFC 790\fR\m[]\&\s-2\u[126]\d\s+2)\&. .RE .PP \fBsyntax\fR(jurisdiction, \fIname\fR) .RS 4 Test if \fIname\fR is valid as a jurisdiction name (e\&.g\&., as the value of \m[blue]\fBJURISDICTION_NAME\fR\m[]\&\s-2\u[127]\d\s+2)\&. .RE .PP \fBsyntax\fR(namespace, \fIname\fR) .RS 4 Test if \fIname\fR is valid as the name of a \m[blue]\fBnamespace\fR\m[]\&\s-2\u[22]\d\s+2\&. .RE .PP \fBsyntax\fR(role, \fIname\fR) .RS 4 Test if \fIname\fR is valid as a \m[blue]\fBrole descriptor string\fR\m[]\&\s-2\u[121]\d\s+2\&. .RE .PP \fBsyntax\fR(uri, \fIname\fR) .RS 4 Test if \fIname\fR is a valid URI (\m[blue]\fBRFC 2396\fR\m[]\&\s-2\u[61]\d\s+2, but partially \m[blue]\fBRFC 3986\fR\m[]\&\s-2\u[62]\d\s+2)\&. It must consist of a scheme, authority component, path component, and optional query and fragment components\&. .RE .PP \fBsyntax\fR(username, \fIname\fR) .RS 4 Test if \fIname\fR is valid as a username (e\&.g\&., as the value of the \fIUSERNAME\fR argument to many \fBDACS\fR web services)\&. .RE .PP \fBsyntax\fR(variable, \fIname\fR) .RS 4 Test if \fIname\fR is valid as a \m[blue]\fBvariable reference\fR\m[]\&\s-2\u[22]\d\s+2\&. This does not test if the named variable exists\&. .RE .PP \fBsyntax\fR(varname, \fIname\fR) .RS 4 Test if \fIname\fR is a syntactically correct \m[blue]\fBvariable name\fR\m[]\&\s-2\u[22]\d\s+2, with or without a namespace\&. This does not test if the named variable exists\&. .RE .sp .sp .if n \{\ .RS 4 .\} .nf > syntax(federation, "FOO") 1 > syntax(dacsname, "FOO::BAZ:bar") 1 > syntax(dacsname, "FOO::") 4 > syntax(charset, "bobo17+", "a\-z0\-9") 0 > syntax(expr, \*(Aq1 + 1 + 1\*(Aq) 1 > syntax(variable, \*(Aq${1$}\*(Aq) 0 > syntax(variable, \*(Aq${Foo::baz:z}\*(Aq) 0 > syntax(varname, \*(AqFoo::baz\*(Aq) 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 .fi .if n \{\ .RE .\} .sp .RE .PP \fBtime\fR(\fIformat\fR [, \fItimeval\fR]) .br \fBtime\fR(\fIformat\fR, \fInamespace\fR) .RS 4 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 \m[blue]\fBstrptime()\fR\m[]\&\s-2\u[128]\d\s+2\&. If the second argument is absent, the result is the same as if a second argument were given as time("now")\&. The \m[blue]\fBlocaltime(3)\fR\m[]\&\s-2\u[129]\d\s+2 library function is used internally to perform the date calculations\&. .sp The \fIformat\fR argument, which is treated case\-insensitively, can be any of the following: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} If the argument is "now", the function\*(Aqs 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\*(Aqs value\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} If the argument is "sec" or "secs" or "seconds", the function\*(Aqs value is the system clock\*(Aqs seconds reading\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} If the argument is "min" or "mins" or "minutes", the function\*(Aqs value is the system clock\*(Aqs minutes reading\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} If the argument is "hour", the function\*(Aqs value is the system clock\*(Aqs hour reading (0 \- 23)\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} If the argument is "mday", the function\*(Aqs value is the day of the month (1 \- 31)\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} If the argument is "ismdaylast", the function\*(Aqs value is non\-zero if this is the last day of the month\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} If the argument is "mon" or "month", the function\*(Aqs value is the month of the year (0 \- 11)\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} If the argument is "year", the function\*(Aqs value is the year (from 1900 onward)\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} If the argument is "isleapyear", the function\*(Aqs value is non\-zero if this is a leap year\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} If the argument is "wday", the function\*(Aqs value is the day of the week (Sunday is 0)\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} If the argument is "yday", the function\*(Aqs value is the day of the year (0 \- 365)\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} If the argument is "isdst", the function\*(Aqs value is non\-zero if daylight saving time is in effect\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} If the argument is "zone", the function\*(Aqs value is system clock\*(Aqs time zone, abbreviated\&. If the time zone is not known, the value will be the empty string\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} If the argument is "gmtoff", the function\*(Aqs value is the offset (in seconds) of the system clock\*(Aqs time represented from UTC, with positive values indicating east of the Prime Meridian\&. .RE .sp .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br 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" (\fBTrue\fR 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"\&. .sp .5v .RE .RE .PP \fBtransform\fR(\fIinput\fR,\fIname\fR,\fIrules\fR,\fIdocs\fR [,\fIidents\fR]) .br \fBtransform\fR(\fIinput\fR,\fIconfig\fR,\fIname\fR,\fIrules\fR,\fIdocs\fR [,\fIidents\fR]) .RS 4 This function provides a simplified API for \m[blue]\fBdacstransform(1)\fR\m[]\&\s-2\u[130]\d\s+2 \- 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\&., \fI${Conf::transform_prefix}\fR)\&. The second form passes a configuration object returned by \m[blue]\fBtransform_config()\fR\m[]\&\s-2\u[131]\d\s+2\&. The \fIinput\fR argument is the text to be passed through the function\&. The \fIname\fR argument is equivalent to the value of the \fBdacstransform\fR \fB\-name\fR flag, \fIrules\fR is equivalent to the value of the \fB\-r\fR flag, \fIdocs\fR is equivalent to the value of the \fB\-docs\fR flag, and the optional \fIidents\fR argument is a whitespace\-separated list of identities in the \m[blue]\fBconcise user syntax\fR\m[]\&\s-2\u[132]\d\s+2\&. The function returns the transformed \fIinput\fR\&. .RE .PP \fBtransform_config\fR(\fIflags\fR) .RS 4 This function returns a configuration object that is passed to subsequent calls to \m[blue]\fBtransform()\fR\m[]\&\s-2\u[133]\d\s+2 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\&. .sp The following flags are recognized: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fB\-prefix \fR\fB\fIprefix\-string\fR\fR: The string used to introduce a directive, which must appear at the beginning of a line\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fB\-suffix \fR\fB\fIsuffix\-string\fR\fR: The string used to end a directive\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fB\-rprefix \fR\fB\fIregex\-prefix\fR\fR: A line whose beginning matches the specified regular expression introduces a directive\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fB\-rsuffix \fR\fB\fIregex\-suffix\fR\fR: The end of a directive is found by matching the specified regular expression\&. .RE .sp .RE .PP \fBtrim\fR(\fIstring\fR, \fIdelete\-set\fR [,\fIlimit\fR]) .RS 4 Delete each character in \fIdelete\-set\fR that appears at the end of \fIstring\fR, up to \fIlimit\fR characters\&. The \fIdelete\-set\fR is a search list specification as used by \m[blue]\fBstrtr()\fR\m[]\&\s-2\u[98]\d\s+2\&. If \fIlimit\fR is missing or zero, all of the characters in \fIstring\fR can potentially be deleted (leaving the empty string)\&. The new string is returned\&. .sp .if n \{\ .RS 4 .\} .nf > trim("abceffff", "f") "abce" > trim("abceffff", abf) "abce" > trim("a\en\en\en", "\en") "a" > trim("a", "a\-z") "" .fi .if n \{\ .RE .\} .sp .RE .PP \fBtypeof\fR([\fItypename\fR,] \fIexpression\fR) .RS 4 If there are two arguments and the first is a recognized \m[blue]\fBdata type name\fR\m[]\&\s-2\u[21]\d\s+2, the return value is 1 (\fBTrue\fR) if \fIexpression\fR has that type and 0 (\fBFalse\fR) otherwise\&. If there is one argument, the function yields a string that is the data type name of the evaluated expression\&. .sp .if n \{\ .RS 4 .\} .nf > typeof(4\&.5) "real" > typeof(integer, 4\&.5) 0 .fi .if n \{\ .RE .\} .sp .RE .PP \fBundef\fR() .RS 4 This function returns a special value that represents the "undefined value"\&. It is normally an error to use this value, just as it would be to reference an undefined variable\&. It can be used to undefine a configuration directive\&. The undefined value prints as the string ""\&. See \m[blue]\fBdacs\&.conf(5)\fR\m[]\&\s-2\u[10]\d\s+2\&. .RE .PP \fBuser\fR(\fIstring\fR) .RS 4 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 \fBTrue\fR for a set of credentials for those credentials to match\&. See \m[blue]\fBdacs(1)\fR\m[]\&\s-2\u[121]\d\s+2 for information about naming\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br 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 \m[blue]\fBACS_CREDENTIALS_LIMIT\fR\m[]\&\s-2\u[134]\d\s+2\&. .sp .5v .RE The \fIstring\fR argument (\fIEXP\fR) has the following syntax: .PP \fBFigure\ \&2.\ \&User Filter Expression Grammar\fR .sp .if n \{\ .RS 4 .\} .nf \fIEXP\fR \-> \fIE1\fR \fIE1\fR \-> \fIE2\fR | \fIE2\fR \fIOR\fR \fIE2\fR \fIE2\fR \-> \fIE3\fR | \fIE3\fR \fIAND\fR \fIE2\fR \fIE3\fR \-> \fIE4\fR | \fINOT\fR \fIE3\fR \fIE4\fR \-> \fIprimary\fR | "(" \fIE1\fR ")" \fIOR\fR \-> "or" | "||" \fIAND\fR \-> "and" | "&&" \fINOT\fR \-> "not" | "!" .fi .if n \{\ .RE .\} Whitespace (spaces and tabs) is permitted before and after lexical elements\&. Keywords are case sensitive except when otherwise stated\&. .sp A \fIprimary\fR, which evaluates to \fBTrue\fR or \fBFalse\fR, is one of the following: .PP \fIusername\fR .RS 4 \fBTrue\fR if the \fBDACS\fR identity \fIusername\fR matches\&. .sp .if n \{\ .RS 4 .\} .nf user("METALOGIC:auggie") user(":bobo") .fi .if n \{\ .RE .\} .sp If the jurisdiction name or federation name components are omitted, the \m[blue]\fBcurrent federation and jurisdiction\fR\m[]\&\s-2\u[121]\d\s+2 are implied\&. The jurisdiction name component may be specified as "*" (e\&.g\&., *:\fIusername\fR), in which case it will match \fIany\fR jurisdiction name in the current federation\&. In addition, both the federation name and the jurisdiction name components may be specified as "*" (e\&.g\&., *::*:\fIusername\fR), in which case it will match \fIany\fR federation name and \fIany\fR jurisdiction name\&. .RE .PP \fIjurisdiction\fR .RS 4 \fBTrue\fR if \fIjurisdiction\fR matches the name of the jurisdiction that created the credentials\&. .sp .if n \{\ .RS 4 .\} .nf user("METALOGIC:") user("DEMO::METALOGIC:") .fi .if n \{\ .RE .\} .sp .RE .PP \fIfederation\fR .RS 4 \fBTrue\fR if \fIfederation\fR matches the name of the federation that created the credentials\&. .sp .if n \{\ .RS 4 .\} .nf user("DEMO::") .fi .if n \{\ .RE .\} .sp .RE .PP \fIaddress\fR .RS 4 Given an argument acceptable to the \m[blue]\fBfrom()\fR\m[]\&\s-2\u[135]\d\s+2 predicate, the result is \fBTrue\fR if the credentials were generated by a user apparently located at \fIaddress\fR\&. .sp .if n \{\ .RS 4 .\} .nf user("10\&.0\&.0\&.123") user("10\&.0\&.0\&.0/24") user("example\&.com") .fi .if n \{\ .RE .\} .sp .RE .PP \fIgroup\fR .RS 4 \fBTrue\fR if the identity is a member of \fIgroup\fR, which is a \fBDACS\fR group\&. .sp .if n \{\ .RS 4 .\} .nf user("%METALOGIC:admin") .fi .if n \{\ .RE .\} .sp 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\*(Aqs 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 \m[blue]\fBdacs\&.groups(5)\fR\m[]\&\s-2\u[136]\d\s+2\&. .RE .PP namespace \fIns\fR .RS 4 The value of each element in \fIns\fR (a namespace) is evaluated as a \fIprimary\fR\&. The order in which the list is evaluated is unspecified\&. Processing of the list terminates with the first \fIprimary\fR that evaluates to \fBTrue\fR or when the list is exhausted\&. This \fIprimary\fR can appear in an element (so that one list can reference other lists) but beware of infinite recursion\&. .sp 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: .sp .if n \{\ .RS 4 .\} .nf setvar(load, APP_USERS, "/usr/local/dacs/app_users"); user("namespace APP_USERS") .fi .if n \{\ .RE .\} .sp .RE .PP style \fIstyle\-list\fR .RS 4 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 \m[blue]\fBstyles\fR\m[]\&\s-2\u[137]\d\s+2 associated with it that indicate which authentication method or methods were successfully applied and how (by what means) the credentials were generated within \fBDACS\fR\&. A primary is \fBTrue\fR if the tested credentials satisfy \fIall\fR of the keywords in the \fIstyle\-list\fR\&. .sp For example, this expression tests if both the passwd and certificate styles are associated with it: .sp .if n \{\ .RS 4 .\} .nf user("style passwd,cert") .fi .if n \{\ .RE .\} .sp 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: .sp .if n \{\ .RS 4 .\} .nf user("style passwd") and user("style CERT") .fi .if n \{\ .RE .\} .sp The following style keywords are understood: .PP acs .RS 4 \fBTrue\fR if the credentials were created during an authorization check by \fBdacs_acs\fR .RE .PP admin .RS 4 \fBTrue\fR if the credentials were created for use internal to \fBDACS\fR\&. .RE .PP alien .RS 4 \fBTrue\fR if the credentials were imported by \m[blue]\fBdacs_auth_agent(8)\fR\m[]\&\s-2\u[138]\d\s+2 in its "alien" mode, or by \m[blue]\fBdacs_auth_transfer(8)\fR\m[]\&\s-2\u[139]\d\s+2\&. .RE .PP cas .RS 4 \fBTrue\fR if the user was authenticated using CAS\&. .RE .PP cert[ificate] .RS 4 \fBTrue\fR if the user authenticated using an X\&.509 certificate\&. .RE .PP digest .RS 4 \fBTrue\fR if the user authenticated using \m[blue]\fBRFC 2617\fR\m[]\&\s-2\u[111]\d\s+2 Digest authentication\&. .RE .PP expr .RS 4 \fBTrue\fR if the user was authenticated using an expression\&. .RE .PP gen[erated] .RS 4 \fBTrue\fR if the credentials were generated by a \fBDACS\fR utility (e\&.g\&., \m[blue]\fBdacscookie(1)\fR\m[]\&\s-2\u[140]\d\s+2)\&. .RE .PP import[ed] .RS 4 \fBTrue\fR if the credentials were imported by \m[blue]\fBdacs_auth_agent(8)\fR\m[]\&\s-2\u[138]\d\s+2 or \m[blue]\fBdacs_auth_transfer(8)\fR\m[]\&\s-2\u[139]\d\s+2\&. .RE .PP infocard .RS 4 \fBTrue\fR if the user was authenticated using an InfoCard\&. .RE .PP nat[ive] .RS 4 \fBTrue\fR if the user was authenticated using the native authentication style\&. .RE .PP managed_infocard .RS 4 \fBTrue\fR if the user was authenticated using a managed InfoCard\&. .RE .PP pass[word] .br passwd .RS 4 \fBTrue\fR if the user authenticated using a password\&. .RE .PP prompt[ed] .RS 4 \fBTrue\fR if the user was authenticated using the prompted authentication style\&. .RE .PP rlink .RS 4 \fBTrue\fR if the user was authenticated using an \m[blue]\fBRlink\fR\m[]\&\s-2\u[101]\d\s+2\&. .RE .PP selfissued_infocard .RS 4 \fBTrue\fR if the user was authenticated using a self\-issued InfoCard\&. .RE .PP simple .RS 4 \fBTrue\fR if the user authenticated without using a password\&. .RE .sp 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 \m[blue]\fBdacs_authenticate(8)\fR\m[]\&\s-2\u[9]\d\s+2 for additional information\&. .RE .PP importedby \fIjurisdiction\fR .RS 4 The keyword importedby is followed by the name of a jurisdiction within the current federation; the result is \fBTrue\fR if the credentials were imported using \m[blue]\fBdacs_auth_transfer(8)\fR\m[]\&\s-2\u[139]\d\s+2 at that jurisdiction\&. .sp .if n \{\ .RS 4 .\} .nf user("importedby METALOGIC") .fi .if n \{\ .RE .\} .sp .RE .PP version \fIprotocol\-version\fR .RS 4 The keyword version is followed by a \fBDACS\fR protocol version number (every release of \fBDACS\fR defines this as the value of the compile\-time symbol DACS_VERSION_NUMBER); the result is \fBTrue\fR if the credentials match that protocol version number\&. .sp .if n \{\ .RS 4 .\} .nf user("version 1\&.4") .fi .if n \{\ .RE .\} .sp .RE .PP authenticated, unauthenticated .RS 4 Either of two keywords: authenticated (or simply auth) or unauthenticated (or simply unauth)\&. The former is \fBTrue\fR if the user is authenticated, while the latter is \fBTrue\fR if the user is not authenticated\&. A case\-insensitive string comparison is used to match these special names\&. .sp .if n \{\ .RS 4 .\} .nf user("auth") user("unauth") .fi .if n \{\ .RE .\} .sp .RE .PP mine .RS 4 The keyword "mine" (case insensitive) is \fBTrue\fR if the user was authenticated by the current jurisdiction\&. .sp .if n \{\ .RS 4 .\} .nf user("mine") .fi .if n \{\ .RE .\} .sp .RE .PP any .RS 4 The keyword "any" (case insensitive) is always \fBTrue\fR\&. .sp .if n \{\ .RS 4 .\} .nf user("any") .fi .if n \{\ .RE .\} .sp .RE .PP none .RS 4 The keyword "none" (case insensitive) is always \fBFalse\fR\&. .sp .if n \{\ .RS 4 .\} .nf user("none") .fi .if n \{\ .RE .\} .sp .RE .sp 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 (\m[blue]\fBdacs\&.conf(5)\fR\m[]\&\s-2\u[10]\d\s+2)\&. The method used to compare federation names, jurisdiction names, and usernames can also be specified by following the \fIprimary\fR with a \fImode\fR\&. If the value of \fImode\fR (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)\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBImportant\fR .ps -1 .br Keep in mind that \fBuser()\fR can return \fBFalse\fR because no credentials matched the user filter expression and because there are no credentials at all (i\&.e\&., the user is unauthenticated)\&. For example, .sp .if n \{\ .RS 4 .\} .nf user("not METALOGIC:rmorriso") .fi .if n \{\ .RE .\} .sp will return \fBTrue\fR if the user\*(Aqs identity is not METALOGIC:rmorriso, even if the user is not authenticated\&. It may therefore be necessary to explicitly test for an authenticated user: .sp .if n \{\ .RS 4 .\} .nf user("not METALOGIC:rmorriso and auth") .fi .if n \{\ .RE .\} .sp .5v .RE Here are examples of the \fBuser()\fR function\&. Note that any non\-zero expression value implies \fBTrue\fR\&. .sp .RS 4 .ie n \{\ \h'-04' 1.\h'+01'\c .\} .el \{\ .sp -1 .IP " 1." 4.2 .\} .sp .if n \{\ .RS 4 .\} .nf user("METALOGIC:") .fi .if n \{\ .RE .\} .sp Return \fBTrue\fR if the client was authenticated by the jurisdiction METALOGIC in this federation .RE .sp .RS 4 .ie n \{\ \h'-04' 2.\h'+01'\c .\} .el \{\ .sp -1 .IP " 2." 4.2 .\} .sp .if n \{\ .RS 4 .\} .nf user("METALOGIC:rmorriso") .fi .if n \{\ .RE .\} .sp Return \fBTrue\fR if the client was authenticated as the user METALOGIC:rmorriso .RE .sp .RS 4 .ie n \{\ \h'-04' 3.\h'+01'\c .\} .el \{\ .sp -1 .IP " 3." 4.2 .\} .sp .if n \{\ .RS 4 .\} .nf user("DEMO::METALOGIC:rmorriso") .fi .if n \{\ .RE .\} .sp Return \fBTrue\fR if the client was authenticated by the given federation and jurisdiction as rmorriso .RE .sp .RS 4 .ie n \{\ \h'-04' 4.\h'+01'\c .\} .el \{\ .sp -1 .IP " 4." 4.2 .\} .sp .if n \{\ .RS 4 .\} .nf user("%METALOGIC:admin") .fi .if n \{\ .RE .\} .sp Return \fBTrue\fR if the client is a member of the group METALOGIC:admin .RE .sp .RS 4 .ie n \{\ \h'-04' 5.\h'+01'\c .\} .el \{\ .sp -1 .IP " 5." 4.2 .\} .sp .if n \{\ .RS 4 .\} .nf user("*:rmorriso") .fi .if n \{\ .RE .\} .sp Return \fBTrue\fR if the client was authenticated as the username rmorriso by any jurisdiction in this federation .RE .sp .RS 4 .ie n \{\ \h'-04' 6.\h'+01'\c .\} .el \{\ .sp -1 .IP " 6." 4.2 .\} .sp .if n \{\ .RS 4 .\} .nf user("auth") .fi .if n \{\ .RE .\} .sp Return \fBTrue\fR if the client was authenticated anywhere .RE .sp .RS 4 .ie n \{\ \h'-04' 7.\h'+01'\c .\} .el \{\ .sp -1 .IP " 7." 4.2 .\} .sp .if n \{\ .RS 4 .\} .nf user("UnAuthenticated") .fi .if n \{\ .RE .\} .sp Return \fBTrue\fR if the client is not authenticated .RE .sp .RS 4 .ie n \{\ \h'-04' 8.\h'+01'\c .\} .el \{\ .sp -1 .IP " 8." 4.2 .\} .sp .if n \{\ .RS 4 .\} .nf user("10\&.0\&.0\&.123") .fi .if n \{\ .RE .\} .sp Return \fBTrue\fR if the client was authenticated through a request from a host having the IP address 10\&.0\&.0\&.123 .RE .sp .RS 4 .ie n \{\ \h'-04' 9.\h'+01'\c .\} .el \{\ .sp -1 .IP " 9." 4.2 .\} .sp .if n \{\ .RS 4 .\} .nf user("not 10\&.0\&.0\&.123") .fi .if n \{\ .RE .\} .sp Return \fBTrue\fR 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) .RE .sp .RS 4 .ie n \{\ \h'-04'10.\h'+01'\c .\} .el \{\ .sp -1 .IP "10." 4.2 .\} .sp .if n \{\ .RS 4 .\} .nf user("ANY") .fi .if n \{\ .RE .\} .sp Always return \fBTrue\fR .RE .sp .RS 4 .ie n \{\ \h'-04'11.\h'+01'\c .\} .el \{\ .sp -1 .IP "11." 4.2 .\} .sp .if n \{\ .RS 4 .\} .nf user("any") gt 1 .fi .if n \{\ .RE .\} .sp Return \fBTrue\fR if the client has more than one set of current credentials (i\&.e\&., has authenticated as two or more identities) .RE .sp .RS 4 .ie n \{\ \h'-04'12.\h'+01'\c .\} .el \{\ .sp -1 .IP "12." 4.2 .\} .sp .if n \{\ .RS 4 .\} .nf user(":rmorriso") .fi .if n \{\ .RE .\} .sp Return \fBTrue\fR if the client was authenticated as rmorriso by this jurisdiction .RE .sp .RS 4 .ie n \{\ \h'-04'13.\h'+01'\c .\} .el \{\ .sp -1 .IP "13." 4.2 .\} .sp .if n \{\ .RS 4 .\} .nf user(":rmorriso nocase") .fi .if n \{\ .RE .\} .sp Return \fBTrue\fR if the client was authenticated as rmorriso, case\-insensitively, by this jurisdiction .RE .sp .RS 4 .ie n \{\ \h'-04'14.\h'+01'\c .\} .el \{\ .sp -1 .IP "14." 4.2 .\} .sp .if n \{\ .RS 4 .\} .nf user("metalogic:RMORRISO nocase") .fi .if n \{\ .RE .\} .sp Return \fBTrue\fR if the client was authenticated as the user metalogic:RMORRISO, but comparing the jurisdiction name, username, and implied federation name case\-insensitively .RE .sp .RS 4 .ie n \{\ \h'-04'15.\h'+01'\c .\} .el \{\ .sp -1 .IP "15." 4.2 .\} .sp .if n \{\ .RS 4 .\} .nf user("METALOGIC:rmorriso default") .fi .if n \{\ .RE .\} .sp Equivalent to user("METALOGIC:rmorriso"), return \fBTrue\fR 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\*(Aqs default .RE .sp .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBTip\fR .ps -1 .br The following two tests are not equivalent: .sp .if n \{\ .RS 4 .\} .nf user("auth") user("DSS:auth") .fi .if n \{\ .RE .\} .sp The first is \fBTrue\fR 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\&. .sp .5v .RE .RE .PP \fBustamp\fR(\fIop\fR, \fIvfs\-ref\fR [,\fIargs\fR \&.\&.\&.]) .RS 4 This function generates a string called a \fIstamp\fR that is globally unique and sequenced, with high probability\&. It has the following syntax: .sp .if n \{\ .RS 4 .\} .nf h=\fIhostid\fR, s=\fIseqno\fR .fi .if n \{\ .RE .\} .sp A \fIhostid\fR consists of one or more characters from the same set used for a \m[blue]\fBDACS username\fR\m[]\&\s-2\u[141]\d\s+2\&. A \fIseqno\fR consists of two elements, separated by a colon, each of which is an unsigned decimal value\&. .sp The first component of a stamp, the \fIhostid\fR, 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 \fIvfs\-ref\fR, which may be an absolute pathname, an item type, or a \m[blue]\fBVFS URI\fR\m[]\&\s-2\u[30]\d\s+2\&. If \fIvfs\-ref\fR does not exist, it is created and a new value is stored in it\&. .sp Note that by default, \fIhostid\fR identifies a host, not a jurisdiction\&. If required, it is possible to configure unique stamps for each jurisdiction on a host\&. .sp The second component (\fIseqno\fR) is a sequence number string relative to \fIhostid\fR\&. 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 \fIstamp1\fR compares less than \fIstamp2\fR, then \fIstamp1\fR was created before \fIstamp2\fR\&. Comparison of sequence numbers is performed on matching elements numerically, left to right\&. Two \fIhostid\fR components are compared case insensitively\&. No ordering is necessarily implied by stamps created by different hosts\&. .sp Sequence number state information is stored in a file that must be specified using the configuration variable \fI${Conf::ustamp_seqno}\fR; e\&.g\&., .sp .if n \{\ .RS 4 .\} .nf EVAL ${Conf::ustamp_seqno} = "${Conf::DACS_HOME}/seqno" .fi .if n \{\ .RE .\} .sp 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\&. .sp 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\&. .sp The following operations are recognized: .PP \fBustamp\fR(clock, \fIvfs\-uri\fR) .RS 4 The host\*(Aqs system clock is used for the stamp\*(Aqs 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\&. .RE .PP \fBustamp\fR(ntpclock, \fIvfs\-uri\fR, \fIntp_host\fR) .RS 4 \fIThis operation is not implemented\fR\&. Rather than using the system clock, this operation obtains the current time from \fIntp_host\fR, which is assumed to be more reliable than the system clock in that it will never be reset to an earlier time\&. The \fIntp_host\fR 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\&. .RE .PP \fBustamp\fR(user, \fIvfs\-uri\fR, \fIseqno\fR) .RS 4 Instead of incorporating the current time into the stamp\*(Aqs sequence number, this operation uses a user\-supplied string that is assumed to have the necessary syntax and characteristics\&. .RE .sp Examples: .sp .if n \{\ .RS 4 .\} .nf > ustamp(clock, "${Conf::DACS_HOME}/hostid") "h=2fbae312ddc1d2ae388cea1b57a47c66, s=1185565675:9" .fi .if n \{\ .RE .\} .sp .RE .PP \fBvaluesof\fR(\fIalist\fR) .RS 4 If its argument is a single pair, the pair\*(Aqs 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 \m[blue]\fBkeysof()\fR\m[]\&\s-2\u[18]\d\s+2\&. .sp Examples: .sp .if n \{\ .RS 4 .\} .nf > valuesof({red, 17}) 17 > valuesof({red, 17, blue, 100}) [17, 100] .fi .if n \{\ .RE .\} .sp .RE .PP \fBvar\fR(\fIop\fR, \fInamespace\fR, \fIvariable\-name\fR [, \fIargs\fR \&.\&.\&.]) .RS 4 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 \fBvar()\fR can be specified by an expression\&. .sp The following operations are available: .PP \fBvar\fR(delete, \fInamespace\fR, \fIvariable\-name\fR) .RS 4 Delete (undefine) the variable named \fIvariable\-name\fR within \fInamespace\fR\&. If the variable is deleted, 1 is returned, and if it does not exist, 0 is returned\&. .RE .PP \fBvar\fR(exists, \fInamespace\fR, \fIvariable\-name\fR) .RS 4 Test if the variable named \fIvariable\-name\fR within \fInamespace\fR exists, returning 1 if so and 0 if not\&. .RE .PP \fBvar\fR(get, \fInamespace\fR, \fIvariable\-name\fR [, \fIaltval\fR]) .RS 4 Return the value of the variable named \fIvariable\-name\fR within \fInamespace\fR\&. If the variable does not exist, \fIaltval\fR is returned if given, otherwise the empty string is returned (which could potentially be confused with a legitimate value)\&. .RE .PP \fBvar\fR(set, \fInamespace\fR, \fIvariable\-name\fR, \fIvalue\fR) .RS 4 Set the value of the variable named \fIvariable\-name\fR within \fInamespace\fR to \fIvalue\fR\&. If \fInamespace\fR or \fIvariable\-name\fR do not exist they are created\&. If the variable already exists, its value is replaced\&. The function returns \fIvalue\fR\&. .RE .sp Examples: .sp .if n \{\ .RS 4 .\} .nf > ${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 .fi .if n \{\ .RE .\} .sp .RE .PP \fBvfs\fR(\fIop\fR, \fIvfs\-ref\fR [, \fIargument\fR \&.\&.\&.]) .RS 4 This function is an interface to the \fBDACS\fR virtual filestore subsystem, described in \m[blue]\fBdacs\&.vfs(5)\fR\m[]\&\s-2\u[142]\d\s+2\&. Please refer to \m[blue]\fBdacs\&.conf(5)\fR\m[]\&\s-2\u[30]\d\s+2 and \m[blue]\fBdacsvfs(1)\fR\m[]\&\s-2\u[143]\d\s+2 for details and examples\&. .sp 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 \m[blue]\fBVFS\fR\m[]\&\s-2\u[30]\d\s+2 directive, or a \m[blue]\fBVFS URI\fR\m[]\&\s-2\u[144]\d\s+2\&. Zero or more arguments may follow, depending on \fIop\fR\&. For most operations, the third argument will be the key that identifies the object of interest\&. The underlying filestore is implicitly opened and closed\&. .sp An operation that fails abnormally triggers a fatal error\&. .sp The following operations (\fIop\fR) are available: .PP vfs(control, \fIvfs\-ref\fR, \fIc_op\fR [, \fIargument\fR \&.\&.\&.] .RS 4 Perform a configuration operation, specified by \fIc_op\fR, on the filestore\&. Zero or more arguments may follow \fIc_op\fR, depending on the semantics of \fIc_op\fR\&. Not all \fIc_op\fR requests are valid for a given storage scheme or have an effect\&. \fBTrue\fR is returned if successful, \fBFalse\fR otherwise\&. Recognized \fIc_op\fR specifiers are: .PP flush .RS 4 For dacs\-kwv type schemes, if modified data has been buffered, write it to the underlying storage layer\&. .RE .PP get_container .RS 4 For most schemes, return a URI for the underlying object that stores the instance\*(Aqs data (e\&.g\&., the URI for a filename)\&. .RE .PP set_cookies .RS 4 For an http or https scheme, each argument is an HTTP cookie to submit with each request\&. (NOT IMPLEMENTED)\&. .RE .PP set_field_sep \fIfield_sep\fR .RS 4 For dacs\-kwv type schemes, set the field separator string to \fIfield_sep\fR\&. .RE .PP set_lock \fImode\fR .RS 4 For a native filesystem object (the fs scheme), set or unset a lock on the underlying storage object according to \fImode\fR\&. (NOT IMPLEMENTED\&.) .RE .sp .RE .PP vfs(defined, \fIitem\-type\fR) .RS 4 Test if the specified \fIitem\-type\fR has been defined by a \m[blue]\fBVFS\fR\m[]\&\s-2\u[30]\d\s+2 directive\&. .sp .if n \{\ .RS 4 .\} .nf vfs(defined, "passwds") .fi .if n \{\ .RE .\} .sp .RE .PP vfs(delete, \fIvfs\-ref\fR [, \fIkey\fR]) .RS 4 Delete the referenced object\&. .RE .PP vfs(enabled [, \fIstore\-name\fR]) .RS 4 With an argument, test if the specified \fIstore\-name\fR can be used\&. With no argument, return a \m[blue]\fBlist\fR\m[]\&\s-2\u[86]\d\s+2 of enabled store names\&. .sp .if n \{\ .RS 4 .\} .nf vfs(enabled, "db") ? print("yes") : print("no"); .fi .if n \{\ .RE .\} .sp .RE .PP vfs(exists, \fIvfs\-ref\fR [, \fIkey\fR]) .RS 4 Test whether the referenced object exists, returning \fBTrue\fR or \fBFalse\fR\&. .sp .if n \{\ .RS 4 .\} .nf vfs(exists, "/usr/local/dacs/conf/passwd") vfs(exists, "file:///usr/local/dacs/conf/passwd") .fi .if n \{\ .RE .\} .sp .RE .PP vfs(get, \fIvfs\-ref\fR [, \fIkey\fR]) .RS 4 Retrieve the referenced object as a string\&. .RE .PP vfs(getsize, \fIvfs\-ref\fR [, \fIkey\fR]) .RS 4 Return the length, in bytes, of the referenced object\&. .RE .PP vfs(list, \fIvfs\-ref\fR) .RS 4 List the keys of all objects in the store\&. .RE .PP vfs(load, \fIvfs\-ref\fR [, \fIkey\fR]) .RS 4 The load operator returns the contents of the object as a list of strings, one element per line\&. Typically, the object is a file that consists of newline\-separated text\&. The first line is assigned to list element \fB0\fR, the second to element \fB1\fR, and so on\&. .RE .PP vfs(loadrc, \fIvfs\-ref\fR [, \fIkey\fR]) .RS 4 This operator is similar to the load operator but ignores comment lines, making it a convenient shorthand for loading configuration files, which often include blank lines and line\-spanning comments\&. By default, a line that has any character in the string "#\en" as its first non\-whitespace character is discarded\&. This behaviour can be overridden by changing the value of \fI${Expr::rc_chars}\fR\&. If \fI${Expr::rc_chars}\fR is the empty string, only empty lines or lines consisting entirely of whitespace are discarded\&. An explicit newline in \fI${Expr::rc_chars}\fR matches blank lines\&. .sp Consider the following example: .sp .if n \{\ .RS 4 .\} .nf > ($pwd = vfs(loadrc, "/etc/passwd")) && "ok" 1 > length($pwd) 33 > $pwd[0] "root:*:0:0:Charlie &:/root:/bin/csh" .fi .if n \{\ .RE .\} .sp Here, there are 33 non\-comment, non\-empty lines in /etc/passwd and the first one is printed\&. .RE .PP vfs(put, \fIvfs\-ref\fR, \fIvalue\fR) .br vfs(put, \fIvfs\-ref\fR, \fIkey\fR, \fIvalue\fR) .RS 4 Store an item under the given key, replacing any existing instance\&. The value is null\-terminated\&. .RE .PP vfs(rename, \fIvfs\-ref\fR, \fIoldkey\fR, \fInewkey\fR) .RS 4 Change the key associated with an existing item from \fIoldkey\fR to \fInewkey\fR\&. .RE .PP vfs(uri, \fIitem\-type\fR) .RS 4 If \fIitem\-type\fR has been defined by a \m[blue]\fBVFS\fR\m[]\&\s-2\u[30]\d\s+2 directive, return its URI, otherwise the empty string\&. .sp .if n \{\ .RS 4 .\} .nf > vfs(uri, "passwds") "[passwds]dacs\-kwv\-fs:/usr/local/dacs/conf/passwd?field_sep=:" .fi .if n \{\ .RE .\} .sp .RE .sp This statement sets a variable to the contents of the file /tmp/somefile: .sp .if n \{\ .RS 4 .\} .nf ${somefile} = vfs(get, "file:///tmp/somefile") .fi .if n \{\ .RE .\} .sp As do this equivalent statements: .sp .if n \{\ .RS 4 .\} .nf ${somefile} = vfs(get, "/tmp/somefile") ${somefile} = get("/tmp/somefile") .fi .if n \{\ .RE .\} .sp This expression lists the files in the /tmp directory: .sp .if n \{\ .RS 4 .\} .nf vfs(list,"dacs\-fs:/tmp") .fi .if n \{\ .RE .\} .sp 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: .sp .if n \{\ .RS 4 .\} .nf 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"); .fi .if n \{\ .RE .\} .sp This rule fragment denies access if the user has already been granted access five times: .sp .if n \{\ .RS 4 .\} .nf 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); } .fi .if n \{\ .RE .\} .sp The item type counter_db would be configured in dacs\&.conf; e\&.g\&., .sp .if n \{\ .RS 4 .\} .nf VFS "[counter_db]dacs\-db:/usr/local/dacs/federations/counters\&.db" .fi .if n \{\ .RE .\} .sp .RE .SH "SEE ALSO" .PP \m[blue]\fBdacsexpr(1)\fR\m[]\&\s-2\u[1]\d\s+2 .SH "BUGS" .PP 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\&. Over time, regular\-ness of the language has drifted a little\&. .PP A way to handle errors and exceptions (such as with try/catch/throw statements) would be nice\&. Even a simple "trap" function would be useful\&. 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\&. .PP Various aspects of variables and namespaces are not implemented\&. A namespace cannot be copied by assignment; use \fBsetvar()\fR\&. .PP Real numbers are second\-class citizens\&. There are no square root or trig functions, for instance\&. .PP Some functionality, such as generation of one\-time passwords using HOTP and TOTP (see \m[blue]\fBdacstoken(1)\fR\m[]\&\s-2\u[145]\d\s+2), has not been provided\&. .PP Input and output processing is still rather limited, but maybe that\*(Aqs a feature\&. .PP Having to use ":" instead of "\&.\&." when matching octet ranges with \m[blue]\fBfrom()\fR\m[]\&\s-2\u[135]\d\s+2 is unfortunate but avoids pesky period proliferation\&. .PP Some of the more esoteric functions and modes of operation exist primarily to expose \fBDACS\fR core code for testing purposes\&. Some of these functions do not have particularly efficient implementations\&. .PP Expressions are not intended to be used for long\-running programs, only short computations\&. .PP The string length argument taken by a few functions (like \m[blue]\fBdigest()\fR\m[]\&\s-2\u[78]\d\s+2) is probably unnecessary in practice since the \m[blue]\fBsubstr()\fR\m[]\&\s-2\u[146]\d\s+2 function can be used\&. The length argument should be removed or perhaps replaced by a more versatile range\-specifying argument\&. .SH "AUTHOR" .PP Distributed Systems Software (\m[blue]\fBwww\&.dss\&.ca\fR\m[]\&\s-2\u[147]\d\s+2) .SH "COPYING" .PP Copyright \(co 2003\-2018 Distributed Systems Software\&. See the \m[blue]\fBLICENSE\fR\m[]\&\s-2\u[148]\d\s+2 file that accompanies the distribution for licensing information\&. .SH "NOTES" .IP " 1." 4 dacsexpr(1) .RS 4 \%http://dacs.dss.ca/man/dacsexpr.1.html .RE .IP " 2." 4 Perl .RS 4 \%http://www.perl.org/ .RE .IP " 3." 4 PHP .RS 4 \%http://www.php.net .RE .IP " 4." 4 Tcl .RS 4 \%http://www.tcl.tk/about .RE .IP " 5." 4 isprint(3) .RS 4 \%https://www.freebsd.org/cgi/man.cgi?query=isprint&apropos=0&sektion=3&manpath=FreeBSD+10.3-RELEASE&format=html .RE .IP " 6." 4 print() .RS 4 \%http://dacs.dss.ca/man/#print .RE .IP " 7." 4 cast .RS 4 \%http://dacs.dss.ca/man/#cast .RE .IP " 8." 4 modifier flag .RS 4 \%http://dacs.dss.ca/man/#variable_modifiers .RE .IP " 9." 4 dacs_authenticate(8) .RS 4 \%http://dacs.dss.ca/man/dacs_authenticate.8.html .RE .IP "10." 4 dacs.conf(5) .RS 4 \%http://dacs.dss.ca/man/dacs.conf.5.html .RE .IP "11." 4 dacs_acs(8) .RS 4 \%http://dacs.dss.ca/man/dacs_acs.8.html .RE .IP "12." 4 environ(7) .RS 4 \%https://www.freebsd.org/cgi/man.cgi?query=environ&apropos=0&sektion=7&manpath=FreeBSD+10.3-RELEASE&format=html .RE .IP "13." 4 exec() .RS 4 \%http://dacs.dss.ca/man/#exec .RE .IP "14." 4 list() .RS 4 \%http://dacs.dss.ca/man/#list .RE .IP "15." 4 length() .RS 4 \%http://dacs.dss.ca/man/#length .RE .IP "16." 4 strchars() .RS 4 \%http://dacs.dss.ca/man/#strchars .RE .IP "17." 4 expression grammar .RS 4 \%http://dacs.dss.ca/man/#expression_grammar .RE .IP "18." 4 keysof() .RS 4 \%http://dacs.dss.ca/man/#keysof .RE .IP "19." 4 valuesof() .RS 4 \%http://dacs.dss.ca/man/#valuesof .RE .IP "20." 4 alist() .RS 4 \%http://dacs.dss.ca/man/#alist .RE .IP "21." 4 supported data types .RS 4 \%http://dacs.dss.ca/man/#data_types .RE .IP "22." 4 variable reference .RS 4 \%http://dacs.dss.ca/man/#variables .RE .IP "23." 4 dacs_notices(8) .RS 4 \%http://dacs.dss.ca/man/dacs_notices.8.html .RE .IP "24." 4 alist construction operator .RS 4 \%http://dacs.dss.ca/man/#alists .RE .IP "25." 4 listref() .RS 4 \%http://dacs.dss.ca/man/#listref .RE .IP "26." 4 Argon2 .RS 4 \%https://en.wikipedia.org/wiki/Argon2 .RE .IP "27." 4 Password Hashing Competition .RS 4 \%https://password-hashing.net/ .RE .IP "28." 4 draft-irtf-cfrg-argon2-03 .RS 4 \%https://tools.ietf.org/id/draft-irtf-cfrg-argon2-03.txt .RE .IP "29." 4 phc-winner-argon2 .RS 4 \%https://github.com/p-h-c/phc-winner-argon2 .RE .IP "30." 4 VFS .RS 4 \%http://dacs.dss.ca/man/dacs.conf.5.html#VFS .RE .IP "31." 4 revocation list .RS 4 \%http://dacs.dss.ca/man/dacs.acls.5.html#revocation_list .RE .IP "32." 4 access control rule .RS 4 \%http://dacs.dss.ca/man/dacs.acls.5.html .RE .IP "33." 4 on_success() .RS 4 \%http://dacs.dss.ca/man/#on_success .RE .IP "34." 4 AUTH_SUCCESS .RS 4 \%http://dacs.dss.ca/man/dacs.conf.5.html#AUTH_SUCCESS .RE .IP "35." 4 ACS_SUCCESS .RS 4 \%http://dacs.dss.ca/man/dacs.conf.5.html#ACS_SUCCESS .RE .IP "36." 4 RFC 4180 .RS 4 \%http://www.rfc-editor.org/rfc/rfc4180.txt .RE .IP "37." 4 ADMIN_IDENTITY .RS 4 \%http://dacs.dss.ca/man/dacs.conf.5.html#ADMIN_IDENTITY .RE .IP "38." 4 approval stamp .RS 4 \%http://dacs.dss.ca/man/dacs_acs.8.html#dacs_approval .RE .IP "39." 4 dacs64 decoding .RS 4 \%http://dacs.dss.ca/man/dacs.exprs.5.html#encode .RE .IP "40." 4 dacs_list_jurisdictions(8) .RS 4 \%http://dacs.dss.ca/man/dacs_list_jurisdictions.8.html .RE .IP "41." 4 dacsauth(1) .RS 4 \%http://dacs.dss.ca/man/dacsauth.1.html .RE .IP "42." 4 dacscheck(1) .RS 4 \%http://dacs.dss.ca/man/dacscheck.1.html .RE .IP "43." 4 encode() .RS 4 \%http://dacs.dss.ca/man/#encode .RE .IP "44." 4 cryptographic hash .RS 4 \%http://en.wikipedia.org/wiki/Message_digest .RE .IP "45." 4 MD5 Message-Digest Algorithm .RS 4 \%http://en.wikipedia.org/wiki/MD5 .RE .IP "46." 4 RFC 6194 .RS 4 \%https://tools.ietf.org/html/rfc6194 .RE .IP "47." 4 FIPS 180-4 .RS 4 \%http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf .RE .IP "48." 4 FIPS PUB 202, August/2015 .RS 4 \%http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf .RE .IP "49." 4 RFC 7693 .RS 4 \%https://tools.ietf.org/html/rfc7693 .RE .IP "50." 4 dacs(1) .RS 4 \%http://dacs.dss.ca/man/dacs.1.html#digests-arg .RE .IP "51." 4 dacsversion(1) .RS 4 \%http://dacs.dss.ca/man/dacsversion.1.html .RE .IP "52." 4 dacs_version(8) .RS 4 \%http://dacs.dss.ca/man/dacs_version.8.html .RE .IP "53." 4 pbkdf2() .RS 4 \%http://dacs.dss.ca/man/#pbkdf2 .RE .IP "54." 4 scrypt() .RS 4 \%http://dacs.dss.ca/man/#scrypt .RE .IP "55." 4 hash() .RS 4 \%http://dacs.dss.ca/man/#hash .RE .IP "56." 4 decode() .RS 4 \%http://dacs.dss.ca/man/#decode .RE .IP "57." 4 radix-85 .RS 4 \%http://en.wikipedia.org/wiki/Ascii85 .RE .IP "58." 4 RFC 4648 .RS 4 \%https://tools.ietf.org/html/rfc4648 .RE .IP "59." 4 RFC 2045 .RS 4 \%http://www.rfc-editor.org/rfc/rfc2045.txt .RE .IP "60." 4 RFC 1738 .RS 4 \%http://www.rfc-editor.org/rfc/rfc1738.txt .RE .IP "61." 4 RFC 2396 .RS 4 \%http://www.rfc-editor.org/rfc/rfc2396.txt .RE .IP "62." 4 RFC 3986 .RS 4 \%http://www.rfc-editor.org/rfc/rfc3986.txt .RE .IP "63." 4 execv(3) .RS 4 \%https://www.freebsd.org/cgi/man.cgi?query=execv&apropos=0&sektion=3&manpath=FreeBSD+10.3-RELEASE&format=html .RE .IP "64." 4 basename(1) .RS 4 \%https://www.freebsd.org/cgi/man.cgi?query=basename&apropos=0&sektion=1&manpath=FreeBSD+10.3-RELEASE&format=html .RE .IP "65." 4 dirname(1) .RS 4 \%https://www.freebsd.org/cgi/man.cgi?query=dirname&apropos=0&sektion=1&manpath=FreeBSD+10.3-RELEASE&format=html .RE .IP "66." 4 stat .RS 4 \%http://dacs.dss.ca/man/#stat .RE .IP "67." 4 stat(1) .RS 4 \%https://www.freebsd.org/cgi/man.cgi?query=stat&apropos=0&sektion=1&manpath=FreeBSD+10.3-RELEASE&format=html .RE .IP "68." 4 stat(2) .RS 4 \%https://www.freebsd.org/cgi/man.cgi?query=stat&apropos=0&sektion=2&manpath=FreeBSD+10.3-RELEASE&format=html .RE .IP "69." 4 printf(3) .RS 4 \%https://www.freebsd.org/cgi/man.cgi?query=printf&apropos=0&sektion=3&manpath=FreeBSD+10.3-RELEASE&format=html .RE .IP "70." 4 test(1) .RS 4 \%https://www.freebsd.org/cgi/man.cgi?query=test&apropos=0&sektion=1&manpath=FreeBSD+10.3-RELEASE&format=html .RE .IP "71." 4 mod_authz_host .RS 4 \%http://httpd.apache.org/docs/2.4/mod/mod_authz_host.html .RE .IP "72." 4 RFC 1035 .RS 4 \%http://www.rfc-editor.org/rfc/rfc1035.txt .RE .IP "73." 4 CIDR notation .RS 4 \%http://en.wikipedia.org/wiki/CIDR_notation .RE .IP "74." 4 RFC 1338 .RS 4 \%http://www.rfc-editor.org/rfc/rfc1338.txt .RE .IP "75." 4 range specification .RS 4 \%http://dacs.dss.ca/man/#range-spec .RE .IP "76." 4 regmatch() .RS 4 \%http://dacs.dss.ca/man/#regmatch .RE .IP "77." 4 user() .RS 4 \%http://dacs.dss.ca/man/#user .RE .IP "78." 4 digest() .RS 4 \%http://dacs.dss.ca/man/#digest .RE .IP "79." 4 RFC 5869 .RS 4 \%http://www.rfc-editor.org/rfc/rfc5869.txt .RE .IP "80." 4 \fICryptographic Extraction and Key Derivation: The HKDF Scheme\fR .RS 4 \%http://eprint.iacr.org/2010/264 .RE .IP "81." 4 HMAC compatible .RS 4 \%http://dacs.dss.ca/man/#hmac .RE .IP "82." 4 message authentication code .RS 4 \%http://en.wikipedia.org/wiki/Message_Authentication_Code .RE .IP "83." 4 Keyed-Hash Message Authentication Code (HMAC) .RS 4 \%http://csrc.nist.gov/publications/fips/fips198-1/FIPS-198-1_final.pdf .RE .IP "84." 4 Secure Hash Standard functions .RS 4 \%http://dacs.dss.ca/man/dacs.conf.5.html#SHA_functions .RE .IP "85." 4 RFC 2253 .RS 4 \%http://www.rfc-editor.org/rfc/rfc2253.txt .RE .IP "86." 4 list construction operator .RS 4 \%http://dacs.dss.ca/man/#lists .RE .IP "87." 4 dacspasswd(1) .RS 4 \%http://dacs.dss.ca/man/dacspasswd.1.html .RE .IP "88." 4 PASSWORD_DIGEST .RS 4 \%http://dacs.dss.ca/man/dacs.conf.5.html#PASSWORD_DIGEST .RE .IP "89." 4 PASSWORD_SALT_PREFIX .RS 4 \%http://dacs.dss.ca/man/dacs.conf.5.html#PASSWORD_SALT_PREFIX .RE .IP "90." 4 local_passwd_authenticate .RS 4 \%http://dacs.dss.ca/man/dacs_authenticate.8.html#local_passwd_authenticate .RE .IP "91." 4 vfs() .RS 4 \%http://dacs.dss.ca/man/#vfs .RE .IP "92." 4 PASSWORD_CONSTRAINTS .RS 4 \%http://dacs.dss.ca/man/dacs.conf.5.html#PASSWORD_CONSTRAINTS .RE .IP "93." 4 dacs.conf(5) .RS 4 \%http://dacs.dss.ca/man/dacs.conf.5.html#interpolation .RE .IP "94." 4 RFC 2898 .RS 4 \%http://www.rfc-editor.org/rfc/rfc2898.txt .RE .IP "95." 4 RFC 3962 .RS 4 \%http://www.rfc-editor.org/rfc/rfc3962.txt .RE .IP "96." 4 LOG_FILTER .RS 4 \%http://dacs.dss.ca/man/dacs.conf.5.html#LOG_FILTER .RE .IP "97." 4 cryptographically strong pseudo-random values .RS 4 \%http://www.openssl.org/docs/crypto/RAND_bytes.html .RE .IP "98." 4 strtr() .RS 4 \%http://dacs.dss.ca/man/#strtr .RE .IP "99." 4 ACS_ERROR_HANDLER .RS 4 \%http://dacs.dss.ca/man/dacs.conf.5.html#ACS_ERROR_HANDLER .RE .IP "00." 4 ErrorDocument directive .RS 4 \%http://httpd.apache.org/docs/2.4/mod/core.html#errordocument .RE .IP "01." 4 Rlinks .RS 4 \%http://dacs.dss.ca/man/dacs_acs.8.html#rlinks .RE .IP "02." 4 permalinks .RS 4 \%http://en.wikipedia.org/wiki/Permalink .RE .IP "03." 4 linkback .RS 4 \%http://en.wikipedia.org/wiki/Linkback .RE .IP "04." 4 regex(3) .RS 4 \%https://www.freebsd.org/cgi/man.cgi?query=regex&apropos=0&esektion=3&emanpath=FreeBSD+10.3-RELEASE&format=html .RE .IP "05." 4 re_format(7) .RS 4 \%https://www.freebsd.org/cgi/man.cgi?query=re_format&sektion=7&apropos=0&manpath=FreeBSD+10.3-RELEASE&format=html .RE .IP "06." 4 access control rules .RS 4 \%http://dacs.dss.ca/man/dacs.acls.5.html#elements .RE .IP "07." 4 scrypt .RS 4 \%https://en.wikipedia.org/wiki/Scrypt .RE .IP "08." 4 The scrypt key derivation function .RS 4 \%http://www.tarsnap.com/scrypt.html .RE .IP "09." 4 draft-josefsson-scrypt-kdf-03 .RS 4 \%https://tools.ietf.org/html/draft-josefsson-scrypt-kdf-03 .RE .IP "10." 4 read-only namespace .RS 4 \%http://dacs.dss.ca/man/#reserved_namespaces .RE .IP "11." 4 RFC 2617 .RS 4 \%http://www.rfc-editor.org/rfc/rfc2617.txt .RE .IP "12." 4 copy .RS 4 \%http://dacs.dss.ca/man/#setvar-copy .RE .IP "13." 4 query .RS 4 \%http://dacs.dss.ca/man/#setvar-query .RE .IP "14." 4 cgiparse(8) .RS 4 \%http://dacs.dss.ca/man/cgiparse.8.html .RE .IP "15." 4 split .RS 4 \%http://dacs.dss.ca/man/#setvar-split .RE .IP "16." 4 sleep(3) .RS 4 \%https://www.freebsd.org/cgi/man.cgi?query=sleep&apropos=0&sektion=3&manpath=FreeBSD+10.3-RELEASE&format=html .RE .IP "17." 4 sprintf(3) .RS 4 \%https://www.freebsd.org/cgi/man.cgi?query=sprintf&apropos=0&sektion=3&manpath=FreeBSD+10.3-RELEASE&format=html .RE .IP "18." 4 strftime(3) .RS 4 \%https://www.freebsd.org/cgi/man.cgi?query=strftime&apropos=0&sektion=3&manpath=FreeBSD+10.3-RELEASE&format=html .RE .IP "19." 4 strptime(3) .RS 4 \%https://www.freebsd.org/cgi/man.cgi?query=strptime&apropos=0&sektion=3&manpath=FreeBSD+10.3-RELEASE&format=html .RE .IP "20." 4 tr(1) .RS 4 \%https://www.freebsd.org/cgi/man.cgi?query=tr&apropos=0&sektion=1&manpath=FreeBSD+10.3-RELEASE&format=html .RE .IP "21." 4 \fBDACS\fR name .RS 4 \%http://dacs.dss.ca/man/dacs.1.html#naming .RE .IP "22." 4 RFC 822 .RS 4 \%http://www.rfc-editor.org/rfc/rfc822.txt .RE .IP "23." 4 RFC 952 .RS 4 \%http://www.rfc-editor.org/rfc/rfc952.txt .RE .IP "24." 4 FEDERATION_NAME .RS 4 \%http://dacs.dss.ca/man/dacs.conf.5.html#FEDERATION_NAME .RE .IP "25." 4 RFC 1123 .RS 4 \%http://www.rfc-editor.org/rfc/rfc1123.txt .RE .IP "26." 4 RFC 790 .RS 4 \%http://www.rfc-editor.org/rfc/rfc790.txt .RE .IP "27." 4 JURISDICTION_NAME .RS 4 \%http://dacs.dss.ca/man/dacs.conf.5.html#JURISDICTION_NAME .RE .IP "28." 4 strptime() .RS 4 \%http://dacs.dss.ca/man/#strptime .RE .IP "29." 4 localtime(3) .RS 4 \%https://www.freebsd.org/cgi/man.cgi?query=localtime&apropos=0&sektion=3&manpath=FreeBSD+10.3-RELEASE&format=html .RE .IP "30." 4 dacstransform(1) .RS 4 \%http://dacs.dss.ca/man/dacstransform.1.html .RE .IP "31." 4 transform_config() .RS 4 \%http://dacs.dss.ca/man/#transform_config .RE .IP "32." 4 concise user syntax .RS 4 \%http://dacs.dss.ca/man/dacs.1.html#concise_user_syntax .RE .IP "33." 4 transform() .RS 4 \%http://dacs.dss.ca/man/#transform .RE .IP "34." 4 ACS_CREDENTIALS_LIMIT .RS 4 \%http://dacs.dss.ca/man/dacs.conf.5.html#ACS_CREDENTIALS_LIMIT .RE .IP "35." 4 from() .RS 4 \%http://dacs.dss.ca/man/#from .RE .IP "36." 4 dacs.groups(5) .RS 4 \%http://dacs.dss.ca/man/dacs.groups.5.html .RE .IP "37." 4 styles .RS 4 \%http://dacs.dss.ca/man/dacs_authenticate.8.html#STYLE .RE .IP "38." 4 dacs_auth_agent(8) .RS 4 \%http://dacs.dss.ca/man/dacs_auth_agent.8.html .RE .IP "39." 4 dacs_auth_transfer(8) .RS 4 \%http://dacs.dss.ca/man/dacs_auth_transfer.8.html .RE .IP "40." 4 dacscookie(1) .RS 4 \%http://dacs.dss.ca/man/dacscookie.1.html .RE .IP "41." 4 DACS username .RS 4 \%http://dacs.dss.ca/man/dacs.1.html#dacs_identity .RE .IP "42." 4 dacs.vfs(5) .RS 4 \%http://dacs.dss.ca/man/dacs.vfs.5.html .RE .IP "43." 4 dacsvfs(1) .RS 4 \%http://dacs.dss.ca/man/dacsvfs.1.html .RE .IP "44." 4 VFS URI .RS 4 \%http://dacs.dss.ca/man/man/dacs.conf.5.html#VFS .RE .IP "45." 4 dacstoken(1) .RS 4 \%http://dacs.dss.ca/man/dacstoken.1.html .RE .IP "46." 4 substr() .RS 4 \%http://dacs.dss.ca/man/#substr .RE .IP "47." 4 www.dss.ca .RS 4 \%http://www.dss.ca .RE .IP "48." 4 LICENSE .RS 4 \%http://dacs.dss.ca/man/../misc/LICENSE .RE