chiark / gitweb /
Version number management changes.
[userv.git] / spec.sgml.in
diff --git a/spec.sgml.in b/spec.sgml.in
new file mode 100644 (file)
index 0000000..5fc9ce6
--- /dev/null
@@ -0,0 +1,1355 @@
+<!doctype debiandoc system>
+
+<book>
+<title>User service daemon and client specification
+<author>Ian Jackson <email>ian@chiark.greenend.org.uk
+<version></version>
+
+<abstract>
+This is a specification for a Unix system facility to allow one
+program to invoke another when only limited trust exists
+between them.
+
+<copyright>
+Copyright 1996-1997 Ian Jackson.
+<p>
+
+<prgn/userv/ is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+<p>
+
+This program is distributed in the hope that it will be useful, but
+<em/without any warranty/; without even the implied warranty of
+<em/merchantability/ or <em/fitness for a particular purpose/.  See
+the GNU General Public License for more details.
+<p>
+
+You should have received a copy of the GNU General Public License
+along with <prgn/userv/; if not, write to the Free Software
+Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+<toc sect>
+
+<chapt id="intro">Introduction
+<p>
+There is a daemon which invokes user service programs (henceforth
+`services') in response to requests by callers of a companion client
+program (henceforth the `client') and according to rules set forth in
+system-wide and user-specific configuration files.  The companion
+client program is setuid root, and negotiates with the daemon through
+an <prgn/AF_UNIX/ socket and associated objects in a system-wide
+private directory set aside for the purpose.  The user who wishes the
+service to be performed and calls the client is called the `calling
+user'; the process which calls the client is called the `calling
+process'.
+
+<p>
+The daemon and the client are responsible for ensuring that
+information is safely carried across the security boundary between the
+two users, and that the processes on either side cannot interact with
+each other in any unexpected ways.
+
+<chapt id="client">Client program usage
+
+<p>
+<example>
+userv <var/options/ [--] <var/service-user/ <var/service-name/ [<var/argument/ ...]
+userv <var/options/ -B|--builtin [--] <var/builtin-service/ [<var/info-argument/ ...]
+</example>
+<p>
+
+<var/service-user/ specifies which user is to provide the service.
+The user may be a login name or a numeric uid, or <tt/-/ to indicate
+that the service user is to be the same as the calling user.
+<p>
+
+The service name is interpreted by the userv<footnote><prgn/userv/ is
+short for `user services', and is pronounced `you-serve'.</footnote>
+daemon on behalf of the service user.  It will often be the name of a
+program.
+
+<sect>Options
+<p>
+
+Single-letter options may be combined as is usual with Unix programs,
+and the value for such an option may appear in the same argument or in
+the next.
+
+<taglist>
+<tag/<tt/-B//
+<tag/<tt/--builtin//
+<item>
+Requests that a builtin service be provided.  This is equivalent to
+using the <prgn/--override/ option to specify a string consisting of
+<prgn/execute-builtin/ followed by the <var/builtin-service/
+requested, and requesting a service user of <tt/-/ (indicating the
+calling user).
+<p>
+
+If the builtin service being requested requires a
+<var/service-argument/ then this must be supplied to the client in the
+same argument as the <var/builtin-service/.  See <ref
+id="dirs-execution"> for details of the builtin services available,
+and <ref id="optoverride"> for details of the <prgn/--override/
+options.
+<p>
+
+The actual service name passed will be the <var/builtin-service/; note
+that this actual service name (as opposed to the override data) and
+the <var/info-argument/s supplied will be ignored by most builtin
+services; the override mechanism and <prgn/execute-builtin/ will be
+used to ensure that the right builtin service is called with the right
+<var/service-argument/s.
+
+<tag/<tt/-f<var/fd/[<var/modifiers/]=<var/filename///
+<tag/<tt/--file <var/fd/[<var/modifiers/]=<var/filename///
+<item>
+Requests that data be copied in and out of the service using pipes.
+For each file or descriptor this will be done by creating a pipe, one
+end of which is passed to the service program and the other end of
+which is passed to a copy of <prgn/cat/ invoked by the client; the
+other file descriptor passed to <prgn/cat/ will be one inherited by
+the client program from the caller or one opened by the client program
+on behalf of the caller.
+<p>
+
+The descriptor in the service program that should be connected must be
+specified as <var/fd/, either as a decimal number or as one of the
+strings <tt/stdin/, <tt/stdout/ or <tt/stderr/.  The next argument is
+a filename which will be opened by the client with the privileges of
+the calling user.
+
+<p>
+<var/modifiers/ is used to specify whether the file or descriptor is
+to be read from or written to.  It consists of a series of words
+separated by commas.  A comma may separate the <var/modifiers/ from
+the <var/fd/ and is required if <var/fd/ is not numeric.
+
+<p>
+The modifier words are:
+<taglist compact>
+<tag/<tt/read//
+<item>
+<tt/O_RDONLY/: Allow reading and not writing.  May not be used with
+<tt/write/ or things that imply it.
+
+<tag/<tt/write//
+<item>
+<tt/O_WRONLY/: Allow writing and not reading.  <em/Doesn't truncate or
+create/ without <tt/truncate/ or <tt/create/.  <tt/write/ or things
+that imply it may not be used with <tt/read/.
+
+<tag/<tt/overwrite//
+<item>
+Equivalent to <tt/write,create,truncate/.
+
+<tag/<tt/create//
+<tag/<tt/creat//
+<item>
+<tt/O_CREAT/: Creates the file if necessary.  Implies <tt/write/.
+
+<tag/<tt/exclusive//
+<tag/<tt/excl//
+<item>
+<tt/O_EXCL/: Fails if the file already exists.  Implies <tt/write/ and
+<tt/create/.  May not be used with <tt/truncate/.
+
+<tag/<tt/truncate//
+<tag/<tt/trunc//
+<item>
+<tt/O_TRUNC/: Truncate any existing file.  Implies <tt/write/.
+May not be used with <tt/exclusive/.
+
+<tag/<tt/append//
+<item>
+<tt/O_APPEND/: All writes will append to the file.  Implies <tt/write/
+(but not <tt/create/).
+
+<tag/<tt/sync//
+<item>
+<tt/O_SYNC/: Do writes synchronously.  Implies <tt/write/.
+
+<tag/<tt/wait//
+<tag/<tt/nowait//
+<tag/<tt/close//
+<item>
+
+These modifiers control the behaviour of the client, with respect to
+the pipes carrying data to and from the service, when the service
+terminates.  See below.
+
+<tag/<tt/fd//
+<item>
+The <var/filename/ is not a filename but a numeric file descriptor.
+One or both of <tt/read/ and <tt/write/ must be specified, and no
+other words are allowed.  The <var/filename/ may also be <tt/stdin/,
+<tt/stdout/ or <tt/stderr/ for file descriptor 0, 1 or 2 respectively.
+
+</taglist>
+<p>
+
+If no <var/modifiers/ which imply <tt/read/ or <tt/write/ are used it
+is as if <tt/read/ had been specified, except that if the
+filedescriptor 1 or 2 of the service is being opened (either specified
+numerically or with <tt/stdout/ or <tt/stderr/) it is as if
+<tt/overwrite/ had been specified (or <tt/write/ if only <tt/fd/ was
+specified).
+<p>
+
+The client will also use <tt/O_NOCTTY/ when opening files specified by
+the caller, to avoid changing its controlling terminal.
+<p>
+
+By default stdin, stdout and stderr of the service will be connected
+to the corresponding descriptors on the client.  Diagnostics from
+the client and daemon will also appear on stderr.
+<p>
+
+If <tt/wait/ is specified, the client will wait for the pipe to be
+closed, and only exit after this has happened.  This means that either
+the receiving end of the pipe connection was closed while data was
+still available at the sending end, or that the end of file was
+reached on the reading file descriptor.  Errors encountered reading or
+writing in the client at this stage will be considered a system error
+and cause the client to exit with status 255, but will not cause
+disconnection at the service side since the service has already
+exited.
+<p>
+
+If <tt/close/ is specified the client will immediately close the pipe
+connection by killing the relevant copy of <prgn/cat/.  If the service
+uses the descriptor it will get <prgn/SIGPIPE/ (or <prgn/EPIPE/) for a
+writing descriptor or end of file for a reading one; the descriptor
+opened by or passed to the client will also be closed.
+<p>
+
+If <tt/nowait/ is specified then the client will not wait and the
+connection will remain open after the client terminates.  Data may
+continue to be passed between the inheritors of the relevant
+descriptor on the service side and the corresponding file or
+descriptor on the client side until either side closes their
+descriptor.  This should not usually be specified for stderr (or
+stdout if <tt/--signals stdout/ is used) since diagnostics from
+the service side may arrive after the client has exited and be
+confused with expected output.
+<p>
+
+The default is <tt/wait/ for writing file descriptors and <tt/close/
+for reading ones.
+
+<tag/<tt/-w<var/fd/=<var/action///
+<tag/<tt/--fdwait<var/fd/=<var/action///
+<item>
+Sets the action on termination of the service for the specified file
+descriptor; <var/action/ must be <tt/wait/, <tt/nowait/ or <tt/close/
+as described above.  The file descriptor must be specified as open
+when this option is encountered; this option is overridden by any
+later <prgn/--file/ or <prgn/--fdwait/ option - even by a
+<prgn/--file/ which does not specify an action on termination (in this
+case the default will be used, as described above).
+
+<tag/<tt/-D<var/name/=<var/value///
+<tag/<tt/--defvar <var/name/=<var/value///
+<item>
+Set a user-defined variable <var/name/ to <var/value/.  These
+user-defined variables are made available in the configuration
+language as the parameters <tt/u-<var/name// and are passed to the
+service in environment variables <tt/USERV_U_<var/name//.  <var/name/
+may contain only alphanumerics and underscores, and must start with a
+letter.  If several definitions are given for the same <var/name/ then
+only the last is effective.
+
+<tag/<tt/-t <var/seconds///
+<tag/<tt/--timeout <var/seconds///
+<item>
+Time out the service if it takes longer than <var/seconds/ seconds (a
+positive integer, in decimal).  Timeout will produce a diagnostic on
+stderr and an exit status of 255.  If <var/seconds/ is zero then no
+timeout will be implemented (this is the default).
+
+<tag/<tt/-S/ <var/method//
+<tag/<tt/--signals/ <var/method//
+<item>
+Affects the handling of the exit status when the service terminates
+due to a signal.  (The client will always finish by calling
+<prgn/_exit/, so that only numbers from 0 to 255 can be returned and
+not the full range of numbers and signal indications which can be
+returned by the <prgn/wait/ family of system calls.)
+<p>
+
+The <var/method/ may be one of the following:
+<taglist compact>
+<tag/<var/status/
+<item>
+The client's exit status will be <var/status/.  This will not be
+distinguishable from the service really having exited with code
+<var/status/.  This method is the default, with a <var/status/ of 254.
+
+<tag/<tt/number//
+<tag/<tt/number-nocore//
+<item>
+The client's exit status will be the number of the signal which caused
+the termination of the service.  If <tt/number/ is used rather than
+<tt/number-nocore/ then 128 will be added if the service dumped core.
+<tt/number/ is very like the exit code mangling done by the Bourne
+shell.
+
+<tag/<tt/highbit//
+<item>The client's exit status will be the number of the signal with
+128 added.  If the service exits normally with an exit code of greater
+than 127 then 127 will be returned.
+
+<tag/<tt/stdout//
+<item>
+The service's numeric wait status as two decimal numbers (high byte
+first) and a textual description of its meaning will be printed to the
+client's standard output.  It will be preceded by a newline and
+followed by an extra newline, and the numbers are separated from each
+other and from the textual description by single spaces.  The exit
+status of the client will be zero, unless a system error occurs in
+which case no exit status and description will be printed to stdout,
+and an error message will be printed to stderr as usual.
+</taglist>
+
+<p>
+Problems such as client usage errors, the service not being found or
+permission being denied or failure of a system call are system errors.
+An error message describing the problem will be printed on the
+client's stderr, and the client's exit status will be 255.  If the
+client dies due to a signal this should be treated as a serious system
+error.
+
+<tag/<tt/-H//
+<tag/<tt/--hidecwd//
+<item>
+Prevents the calling process's current directory name from being
+passed to the service; the null string will be passed instead.
+
+<tag/<tt/-P//
+<tag/<tt/--sigpipe//
+<item>
+If the service program is terminated due to a <prgn/SIGPIPE/ the exit
+status of the client will be zero, even if it would have been
+something else according to the exit status method specified.  This
+option has no effect on the code and description printed if the exit
+status method <tt/stdout/ is in use.
+
+<tag/<tt/-h//
+<tag/<tt/--help//
+<tag/<tt/--copyright//
+<item>
+<tt/-h/ or <tt/--help/ prints the client's usage message;
+<tt/--copyright/ prints the copyright and lack of warranty notice.
+
+</taglist>
+
+<sect id="optoverride">Security-overriding options
+<p>
+
+There are also some options which are available for debugging and to
+allow the system administrator to override a user's policy.  These
+options are available only if the client is called by root or if the
+calling user is the same as the service user.
+
+<taglist>
+
+<tag/<tt/--override <var/configuration-data///
+<tag/<tt/--override-file <var/filename///
+<item>
+Do not read the usual configuration files.  Instead, the client sends
+<var/configuration-data/ (followed by a newline) or the contents of
+<var/filename/ (which is opened in the context of the client) to the
+daemon and the daemon uses that data instead.  The
+<var/configuration-data/ must all be in one argument.  It will have a
+single newline appended so that a single directive can easily be
+given, but if more than one directive is required it will have to
+contain one or more real newlines.
+
+<tag/<tt/--spoof-user <var/user///
+<item>
+Pretend to the service that it is being called by <var/user/ (which
+may be a username or a uid).  This will also affect the group and
+supplementary groups supplied to the service; they will be the
+standard group and supplementary groups for <var/user/.
+
+</taglist>
+
+
+<chapt id="envir">Execution environment of the service program
+<p>
+
+The daemon which is handling the service user side of things will read
+configuration files to decide what to do.  If it decides to allow the
+service to be provided it will fork a subprocess to execute the
+service.
+<p>
+
+The service will have no controlling terminal, but it will be a
+process group leader.
+<p>
+
+If the client is killed or times out or a file or descriptor being
+read or written by the client process gets an error then the service
+will be disconnected from the client.  The client will return an exit
+status of 255 and some the service's pipes may be closed at the other
+end.  The service will become a child of <prgn/init/.  The service may
+well not notice the disconnection, though writing to a pipe after this
+may produce a <prgn/SIGPIPE/ and the facility exists to have a
+<prgn/SIGHUP/ sent to the service on disconnection.
+
+<sect>File descriptors
+<p>
+
+The service program's standard filedescriptors, and possibly other
+file descriptors, will be connected to pipes or to
+<prgn>/dev/null</>.  The <prgn/userv/ client/daemon pair will arrange
+that data is copied between the files or file descriptors specified to
+to the client by the caller and these these pipes.
+<p>
+
+Pipes which may be written to will be closed if a write error occurs
+on the corresponding client-side file or descriptor, which may result
+in a <prgn/SIGPIPE/ in the service program; pipes open for reading
+will get <prgn/EOF/ if the client-side file descriptor gets <prgn/EOF/
+or an error.
+<p>
+
+If the service closes one of its reading file descriptors the writing
+end of the corresponding pipe will generate a <prgn/SIGPIPE/ when
+attempts are made by the client/daemon pair to write to it.  This will
+not be considered an error; rather, the relevant pipe will be
+discarded and the corresponding file or file descriptor held by the
+client will be closed.
+<p>
+
+Likewise, if one of the file descriptors held by the client for
+writing by the service is a pipe whose other end is closed by the
+caller then the client/daemon pair will see an error when trying to
+copy data provided by the service.  This too will not be considered an
+error; rather, the pipe correspondong to that descriptor will be
+closed and any further writes will cause the service to get a
+<prgn/SIGPIPE/.
+<p>
+
+Note that not all write errors or broken pipes on file descriptors may
+be visible to the service, since buffered data may be discarded by the
+operating system and there will be a finite interval between the error
+happening and the service being disconnected from the client or the
+next write causing a <prgn/SIGPIPE/.
+<p>
+
+Read errors on file descriptors (and disconnection) will only be
+visible to the service and distinguishable from normal end of file if
+<prgn/disconnect-hup/ is in effect.
+<p>
+
+Read and write errors (other than broken pipes, as described above)
+will always be visible to the caller; they are system errors, and will
+therefore cause the client to print an error message to stderr and
+return with an exit status of 255.
+<p>
+
+If the main service program process exits while it still has running
+children any file descriptors held by those children can remain open,
+depending on the use of <tt/wait/, <tt/nowait/ or <tt/close/ for the
+relevant file descriptor in the client's arguments.  By default
+writing filedescriptors remain open and the client will wait for them
+to be closed at the service end, and reading file descriptors are
+closed immediately.  These leftover child processes will not get a any
+<prgn/SIGHUP/ even if a read or write error occurs or the client
+disconnects before then.
+
+<sect>Environment
+<p>
+
+The service will have some information in environment variables:
+<taglist compact>
+<tag/<tt/USERV_USER//
+<item>
+The login name of the calling user.  If the <prgn/LOGNAME/ variable is
+set (or, if that is unset, if the <prgn/USER/ variable is set) in the
+environment passed to the client by the caller then the password entry
+for that login name will be looked up; if that password entry's uid is
+the same as that of the calling process then that login name will be
+used, otherwise (or if neither <prgn/LOGNAME/ nor <prgn/USER/ is set)
+the calling process's uid will be looked up to determine their login
+name (and if this lookup fails then the service will not be invoked).
+
+<tag/<tt/USERV_UID//
+<item>
+The uid of the calling process.
+
+<tag/<tt/USERV_GID//
+<item>
+The gid and supplementary group list of the calling process: first the
+group in gid and then those in the supplementary group list, in
+decimal, separated by spaces.
+
+<tag/<tt/USERV_GROUP//
+<item>
+The group names of the calling process, listed in the same way as the
+ids are in <prgn/USERV_GID/.  If no name can be found for any of the
+calling process's group(s) then the service will not be invoked.
+
+<tag/<tt/USERV_CWD//
+<item>
+The client's current working directory name (this directory may not be
+accessible to the service).  If it could not be determined or the
+<prgn/--hidecwd/ flag was used then this variable will be set to an
+empty string (this is not considered an error).
+
+<tag/<tt/USERV_SERVICE//
+<item>
+The service name requested by the caller.
+
+<tag/<tt/USERV_U_<var/name///
+<item>
+The value supplied to the client by the caller using -D<var/name/.
+
+</taglist>
+
+<prgn/HOME/, <prgn/PATH/, <prgn/SHELL/, <prgn/LOGNAME/ and <prgn/USER/
+will be set appropriately (according to the details of the service
+user).
+
+
+<chapt id="config">Service-side configuration
+<p>
+
+Which services may be run by whom and under what conditions is
+controlled by configuration files.
+<p>
+
+The daemon will read these files in order.  Certain directives in the
+files modify the daemon's execution settings for invoking the service,
+for example allowing certain file descriptors to be specified by the
+client or specifying which program to execute to provide the service.
+<p>
+
+The <em/last/ instance of each such setting will take effect.  The
+directives which specify which program to execute will not stop the
+configuration file from being read; they will be remembered and will
+only take effect if they are not overridden by a later directive.
+<p>
+
+The daemon will first read <tt>/etc/userv/system.default</>.  Then, by
+default (this behaviour may be modified), it will read a per-user file
+<tt>~/.userv/rc</>, if it exists and the service user's shell is in
+<tt>/etc/shells</>.  Finally it will read
+<tt>/etc/userv/system.override</>.
+<p>
+
+When it has read all of these files it will act according to the
+currently values of of the execution settings.
+
+<sect>Configuration file syntax
+<p>
+
+The configuration file is a series of directives, usually one per
+line.  The portion of a line following a hash character <tt/#/ is
+taken as a comment and ignored.  Each directive consists of a series
+of tokens separated by linear whitespace (spaces and tabs); tokens may
+be words consisting of non-space characters, or, where a string is
+required, a string in double quotes.  Double-quoted strings may
+contain the following backslash escapes:
+
+<taglist compact>
+<tag/<tt/\n//<item>newline
+<tag/<tt/\t//<item>tab
+<tag/<tt/\r//<item>carriage return
+<tag/<tt/\<var/OOO///<item>character whose octal code is <var/OOO/
+<tag/<tt/\x<var/XX///<item>character whose hex code is <var/XX/
+<tag/<tt/\<var/punctuation///<item>literal punctuation character (eg <tt/\\/, <tt/\"/)
+<tag/<tt/\<var/newline// (ie, backslash at end of line)/
+<item>string continues on next line
+</taglist>
+<p>
+
+Relative pathnames in directives are relative to the service program's
+current directory (usually the service user's home directory).
+Pathnames starting with the two characters <tt>~/</> are taken to be
+relative to the service user's home directory.
+
+<sect id="directives">Configuration file directives
+<p>
+
+<sect1 id="dirs-immediate">Immediate directives
+<p>
+
+The following directives take effect immediately:
+
+<taglist>
+<tag/<tt/cd <var/pathname///
+<item>
+Change directory in the service program.  <prgn/cd/ is cumulative.  It
+is an error if the directory cannot be changed to.
+<p>
+
+<prgn/cd/ should not be used between <prgn/execute-from-directory/ and
+the invocation of the service program, as the test for the
+availability of the service program would be done with the old current
+directory and the actual execution with the new (probably causing an
+error).
+
+<tag/<tt/eof//
+<item>
+Stop reading the configuration file in question, as if end of file had
+been reached.  Any control constructs (<prgn/if/, <prgn/catch-quit/ or
+<prgn/errors-push/) which were started in that file will be considered
+finished.  Parsing will continue in the file which caused the file
+containing the <prgn/eof/ to be read.
+
+<tag/<tt/quit//
+<item>
+Stop reading configuration files and act immediately on the current
+settings.  The behaviour of <prgn/quit/ is subject to the
+<prgn/catch-quit/ control construct.
+
+<tag/<tt/include <var/filename///
+<tag/<tt/include-ifexist <var/filename///
+<item>
+Read the configuration file <var/filename/, and then return to this
+file and continue parsing it with the next directive.  It is an error
+if the file cannot be opened and read, unless <prgn/include-ifexist/
+is used and the file does not exist, in which case the directive is
+silently ignored.
+
+<tag/<tt/include-lookup <var/parameter/ <var/directory///
+<tag/<tt/include-lookup-all <var/parameter/ <var/directory///
+<item>
+Read the configuration file in <var/directory/ whose name is the value
+of <var/parameter/ (see the description of <prgn/if/, <ref
+id="dirs-control">).  If <var/parameter/ has several values they will
+be tried in order; with <prgn/include-lookup/ this search will stop
+when one is found, but with <prgn/include-lookup-all/ the search will
+continue and any files appropriate to other values will be read too.
+<p>
+
+If none of the parameter's values had a corresponding file then the
+file <tt/:default/ will be read, if it exists.  If <var/parameter/'s
+list of values was empty then the file <tt/:none/ will be tried first
+and read if it exists, otherwise <tt/:default/ will be tried.
+<p>
+
+It is not an error for any of the files (including <tt/:default/) not
+to exist, but it is an error if a file exists and cannot be read or if
+the directory cannot be accessed.
+
+<p>
+A translation will be applied to values before they are used to
+construct a filename, so that the lookup cannot access dotfiles or
+files in other directories: values starting with full stops will have
+a colon prepended (making <tt/:./), colons will be doubled, and each
+slash will be replaced with a colon followed by a hyphen <tt>:-</>.  A
+parameter value which is the empty string will be replaced with
+<tt/:empty/ (note that this is different from a parameter not having
+any values).
+
+<tag/<tt/include-directory <var/directory///
+<item>
+Read configuration from all files in directory <var/directory/ which
+are plain files whose names consist only of alphanumerics and hyphens
+and start with an alphanumeric.  They will be read in lexical order.
+It is an error for the directory not to exist or for it or any of the
+files found not to be read successfully, or for anything with an
+appropriate name not to be a plain file or a symbolic link to a plain
+file.
+
+<tag/<tt/error <var/text ...///
+<item>
+Causes an error whose message includes the descriptive string
+<var/text/.  <var/text/ may consist of several tokens with intervening
+whitespace.  The whitespace will be included in the message as found
+in the configuration file: all the characters until the end of the
+line will be included verbatim, unless they are part of a
+double-quoted string, in which case the usual meaning of the string
+(i.e., after backslash escape processing) will be used.  Comments and
+linear whitespace at the end of the line (or just before the comment)
+will still be ignored.
+
+<tag/<tt/message <var/text ...///
+<item>
+Causes a message including the descriptive string <var/text/ to be
+delivered as if it were an error message, but does not actually cause
+an error.
+</taglist>
+
+<sect1 id="dirs-delayed">Directives with delayed effect
+<p>
+
+The following directives have no immediate effect, but are remembered
+and have an effect on later processing of the configuration files.
+
+<taglist>
+<tag/<tt/user-rcfile <var/filename///
+<item>
+Specifies that the file <var/filename/ should be read instead of the
+user's <tt>~/.userv/rc</>.  This does <em/not/ happen immediately;
+instead, the setting is remembered and used after the
+<prgn/system.default/ configuration file has been read.  This
+directive has no effect in a user's configuration file or in the
+<prgn/system.override/ file, as the user's configuration file has
+already been found and read by then and will not be re-read.
+
+<tag/<tt/errors-to-stderr//
+<item>
+Causes error messages to be delivered to the client's stderr.
+
+<tag/<tt/errors-to-file/ <var/filename//
+<item>
+Error messages will be written to <var/filename/, which will be opened
+in the context of and with the privileges of the service user.
+
+<tag/<tt/errors-to-syslog/ [<var/facility/ [<var/level/]]/
+<item>
+Error messages will be delivered using <prgn/syslog/.  The default
+<var/facility/ is <tt/daemon/; the default <var/level/ is <tt/error/.
+</taglist>
+
+<sect1 id="dirs-control">Control structure directives
+<p>
+
+The following directives are used to create control structures.  If
+the end of the file is encountered before the end of any control
+structure which was started inside it then that control structure is
+considered finished.  This is not an error.
+
+<taglist>
+<tag/<tt/if <var/condition///
+<tag/<tt/elif <var/condition///
+<tag/<tt/else//
+<tag/<tt/fi//
+<item>
+Lines following <prgn/if/ are interpreted only if the condition is
+true.  Many conditions are properties of parameter values.  Most
+parameters have a single string as a value; however, some may yield
+zero or several strings, in which case the condition is true if it is
+true of any of the strings individually.  Parameters are described
+below.
+<p>
+
+The conditions are:
+
+<taglist compact>
+<tag/<tt/glob <var/parameter/ <var/glob-pattern/ ...//
+<item>
+The value of the parameter whose name is given matches one of the glob
+patterns (anchored at both ends; backslashes can be used to escape
+metacharacters).
+
+<tag/<tt/range <var/parameter/ <var/min/ <var/max///
+<item>
+The value of the parameter is a nonnegative integer and lies within
+the range specified.  <var/min/ or <var/max/ may be <tt/$/ to indicate
+no lower or upper limit, respectively.
+
+<tag/<tt/grep <var/parameter/ <var/filename///
+<item>
+The <var/filename/ refers to a file one of whose lines is the value of
+the parameter (leading or trailing whitespace on each line and empty
+lines in the file are ignored).  It is an error for the file not to be
+opened and read.
+
+<tag/<tt/! <var/condition///
+<item>
+The <var/condition/ is <em/not/ true.
+
+<tag/Conjunctions: <tt/&amp;/ and <tt/|//
+<item>
+<example>
+( <var/condition/
+&amp; <var/condition/
+&amp; <var/condition/
+...
+)
+</example>
+is true if all the listed conditions are true; where <tt/|/ is used it
+is true if any of them is true.  Newlines must be used to separate one
+condition from the next, as shown, and the parentheses are mandatory.
+These conjunctions do not do lazy evaluation.
+</taglist>
+<p>
+
+The parameters are:
+
+<taglist compact>
+<tag/<tt/service//
+<item>
+The service name specified when the client was called.
+
+<tag/<tt/calling-user//
+<item>
+Two strings: the login name of the calling user (determined as for
+<prgn/USERV_USER/, above) and the calling uid (represented in
+decimal).
+
+<tag/<tt/calling-group//
+<item>
+Several strings: the primary and supplementary group names and gids
+(in decimal) of the calling process.  All the group names come first,
+and then the gids.  If the first supplementary group is the same as
+the primary group then it is elided.
+
+<tag/<tt/calling-user-shell//
+<item>
+The calling user's shell, as listed in the password entry for the
+calling login name (as determined for <prgn/USERV_USER/, above).
+
+<tag/<tt/service-user//
+<item>
+Two strings: the name of the service user (as specified to the client)
+and their uid (represented in decimal).
+
+<tag/<tt/service-group//
+<item>
+Several strings: the primary and supplementary group names and gids
+(in decimal) of the service user.
+
+<tag/<tt/service-user-shell//
+<item>
+The service user's shell, as listed in their password entry.
+
+<tag/<tt/u-<var/name///
+<item>
+The value of the user-defined variable <var/name/ passed by the caller
+using the <prgn/--defvar/ command-line option to the client.  If the
+variable was not defined then this parameter is an empty list of
+strings; in this case any condition which tests it will be false, and
+<tt/include-lookup/ on it will read the <tt/:none/ file, or
+<tt/:default/ if <tt/:none/ is not found.
+
+</taglist>
+
+<tag/<tt/errors-push/ <var/filename//
+<tag/<tt/srorre//
+<item>
+Stacks the error handling behaviour currently in effect.  Any changes
+to error handling will take effect only between <prgn/errors-push/ and
+<prgn/srorre/.
+
+<tag/<tt/catch-quit//
+<tag/<tt/hctac//
+<item>
+Any use of <prgn/quit/ inside <prgn/catch-quit/ will merely cause the
+parsing to continue at <prgn/hctac/ instead.  Any control constructs
+started since the <prgn/catch-quit/ will be considered finished if a
+<prgn/quit/ is found.
+<p>
+
+If an error occurs inside <prgn/catch-quit/ the execution settings
+will be reset (as if by the <prgn/reset/ directive) and parsing will
+likewise continue at <prgn/hctac/.
+<p>
+
+If a lexical or syntax error is detected in the same configuration
+file as the <prgn/catch-quit/, while looking for the <prgn/hctac/
+after an error or <prgn/quit/, that new error will not be caught.
+
+</taglist>
+
+<sect1 id="dirs-execution">Directives for changing execution settings
+<p>
+
+The following directives modify the execution settings; the server
+will remember the fact that the directive was encountered and act on
+it only after all the configuration has been parsed.  The <em/last/
+directive which modifies any particuar setting will take effect.
+
+<taglist>
+<tag/<tt/reject//
+<item>
+Reject the request.  <prgn/execute/, <prgn/execute-from-directory/ and
+<prgn/execute-from-path/ will change this setting.
+
+<tag/<tt/execute <var/pathname/ [<var/argument/ ...]//
+<item>
+Execute the program <var/pathname/, with the arguments as specified,
+followed by any arguments given to the client if
+<prgn/no-suppress-args/ is in effect.  It is an error for the
+execution to fail when it is attempted (after all the configuration
+has been parsed).  If <var/pathname/ does not contain a slash it will
+be searched for on the service user's path.
+
+<tag/<tt/execute-from-directory <var/pathname/ [<var/argument/ ...]//
+<item>
+Take all the characters after the last slash of the service name
+specified when the client was called, and execute that program in the
+directory named by <var/pathname/ as if it had been specified for
+<var/execute/.  The part of the service name used may contain only
+alphanumerics and hyphens and must start with an alphanumeric (and it
+must be non-empty), otherwise it is an error.
+<p>
+
+This directive is ignored if the relevant program does not exist in
+the directory specified; in this case the program to execute is left
+at its previous setting (or unset, if it was not set before).
+<p>
+
+It is an error for the test for the existence of the program to fail
+other than with a `no such file or directory' indication.  It is also
+an error for the execution to fail if and when it is attempted (after
+all the configuration has been parsed).
+
+<tag/<tt/execute-from-path//
+<item>
+<var/service/ is interpreted as a program on the default <prgn/PATH/
+(or as a pathname of an executable, if it contains a <tt>/</>).  This
+directive is <em/very dangerous/, and is only provided to make the
+<prgn/--override/ options effective.  It should not normally be used.
+It is an error for the execution to fail when it is attempted (after
+all the configuration has been parsed).
+
+<tag/<tt/execute-builtin <var/service-name/ <var/service-arguments//
+<item>
+Executes the builtin service <var/service-name/.  These builtin
+services display information about the server and/or the request, and
+ignore any arguments passed from the service side except possibly to
+print them as part of their output.  They write their results to their
+standard output (i.e., wherever file descriptor 1 is directed).  The
+builtin services are:
+
+<taglist compact>
+<tag/<tt/execute//
+<item>
+Displays the execution settings, defined variables,
+arguments, etc. with which the builtin service was invoked.
+
+<tag/<tt/environment//
+<item>
+Displays the environment variable settings with which the builtin
+service was invoked.
+
+<tag/<tt/parameter <var/parameter///
+<item>
+Displays the values of the service configuration language parameter
+specified.
+
+<tag/<tt/version//
+<item>
+Displays the version string and compilation details of the uservd
+server program.
+
+<tag/<tt/reset//
+<item>
+Displays the default reset configuration (evaluated when <prgn/reset/
+is found in a configuration file, or when an error is caught by
+<prgn/catch-quit/).
+
+<tag/<tt/toplevel//
+<item>
+Displays the top-level default configuration (the configuration data,
+evaluated by the server, which calls all the other configuration
+files).
+
+<tag/<tt/override//
+<item>
+Displays the top-level override configuration (the configuration data,
+evaluated by the server, which causes all the other configuration data
+to be parsed).
+</taglist>
+
+In the future other builtin services may be defined which do more than
+just print information.
+
+<tag/<tt/set-environment//
+<tag/<tt/no-set-environment//
+<item>
+Runs <tt>/etc/environment</> to set the service user's environment.
+This adds the overhead of invoking a shell, but doesn't cause any
+shell (de)mangling of the service's arguments.  This is achieved by
+invoking
+<example>
+.../program arg arg arg ...
+</example>
+as
+<example>
+/bin/sh -c '. /etc/environment; exec "$@"' - .../program arg arg arg ...
+</example>
+<prgn/no-set-environment/ cancels the effect of
+<prgn/set-environment/.
+
+<tag/<tt/no-suppress-args//
+<tag/<tt/suppress-args//
+<item>
+Include any arguments given to the client as arguments to the program
+invoked as a result of an <prgn/execute/,
+<prgn/execute-from-directory/ or <prgn/execute-from-path/ directive.
+<prgn/suppress-args/ undoes the effect of <prgn/no-suppress-args/.
+
+<tag/<tt/require-fd <var/fd-range/ read|write//
+<item>
+Insist that the filedescriptor(s) be opened for reading resp. writing.
+It is an error if any descriptor marked as required when the service
+is about to be invoked (after the configuration has been parsed) was
+not specified when the client was invoked.  Each file descriptor has a
+separate setting, and the last one of <prgn/require-fd/,
+<prgn/allow-fd/, <prgn/ignore-fd/, <prgn/null-fd/ or <prgn/reject-fd/
+which affected a particular file descriptor will take effect.
+<p>
+
+<var/fd-range/ may be a single number, two numbers separated by a
+hyphen, or one number followed by a hyphen (indicating all descriptors
+from that number onwards).  It may also be one of the words
+<tt/stdin/, <tt/stdout/ or <tt/stderr/.  Open-ended file descriptor
+rangers are allowed only with <prgn/reject-fd/ and <prgn/ignore-fd/,
+as otherwise the service program would find itself with a very large
+number of file descriptors open.
+<p>
+
+When the configuration has been parsed, and before the service is
+about to be executed, stderr (fd 2) must be required or allowed
+(<prgn/require-fd/ or <prgn/allow-fd/) for writing; this is so that
+the error message printed by the server's child process if it cannot
+<prgn/exec/ the service program is not lost.
+
+<tag/<tt/allow-fd <var/fd-range/ [read|write]//
+<item>
+Allow the descriptor(s) to be opened for reading resp. writing, or
+either if neither <tt/read/ nor <tt/write/ is specified.  If a
+particular descriptor not specified by the client then it will be open
+onto <tt>/dev/null</> (for reading, writing, or both, depending on
+whether <tt/read/, <tt/write/ or neither was specified).
+
+<tag/<tt/null-fd <var/fd-range/ [read|write]//
+<item>
+Specify that the descriptor(s) be opened onto <prgn>/dev/null</> for
+reading resp. writing, or both if neither <tt/read/ nor <tt/write/
+is specified.  Any specification of these file descriptors by the
+client will be silently ignored; the client will see its ends of the
+descriptors being closed immediately.
+
+<tag/<tt/reject-fd <var/fd-range///
+<item>
+Do not allow the descriptor(s) to be specified by the client.  It is
+an error if any descriptor(s) marked for rejection are specified when
+the service is about to be invoked (after the configuration has been
+parsed).
+
+<tag/<tt/ignore-fd <var/fd-range///
+<item>
+Silently ignore any specification by the client of those
+descriptor(s).  The pipes corresponding to these descriptors will be
+closed just before the service is invoked.
+
+<tag/<tt/disconnect-hup//
+<tag/<tt/no-disconnect-hup//
+<item>
+Causes the service's process group to get a <prgn/SIGHUP/ if the
+client disconnects before the main service process terminates.
+<prgn/no-disconnect-hup/ cancels <prgn/disconnect-hup/.
+<p>
+
+If one of the reading descriptors specified when the client is called
+gets a read error, or if the service is disconnected for some other
+reason, then the <prgn/SIGHUP/ will be delivered <em/before/ the
+writing end(s) of the service's reading pipe(s) are closed, so that
+the client can distinguish disconnection from reading EOF on a pipe.
+
+<tag/<tt/reset//
+<item>
+Resets the execution settings to the default.  This is equivalent to:
+<example>
+cd ~/
+reject
+no-set-environment
+suppress-args
+allow-fd 0 read
+allow-fd 1-2 write
+reject-fd 3-
+disconnect-hup
+</example>
+
+</taglist>
+
+If no <prgn/execute/, <prgn/execute-from-path/,
+<prgn/execute-from-directory/ or <prgn/builtin/ is interpreted before
+all the files are read then the request is rejected.
+
+
+<sect id="configerrors">Errors in the configuration file
+<p>
+
+If a syntax error or other problem occurs when processing a
+configuration file then a diagnostic will be issued, to wherever the
+error messages are currently being sent (see the <prgn/errors-/ family
+of directives, above).
+<p>
+
+The error will cause processing of the configuration files to cease at
+that point, unless the error was inside a <prgn/catch-quit/ construct.
+In this case the settings controlling the program's execution will be
+reset to the defaults as if a <prgn/reset/ directive had been issued,
+and parsing continues after <prgn/hctac/.
+
+
+<sect id="defaults">Defaults
+<p>
+
+The default configuration processing is as if the daemon were parsing
+an overall configuration file whose contents were as follows:
+
+<example>
+reset
+user-rcfile ~/.userv/rc
+errors-to-stderr
+include /etc/userv/system.default
+if grep service-user-shell /etc/shells
+   errors-push
+     catch-quit
+       include-ifexist <var/file specified by most recent user-rcfile directive/
+     hctac
+   srorre
+fi
+include /etc/userv/system.override
+quit
+</example>
+<p>
+
+If one of the <prgn/--override/ options to the client is used then it
+will instead be as if the daemon were parsing an overall configuration
+as follows:
+
+<example>
+reset
+errors-to-stderr
+include <var/file containing configuration data sent by client/
+quit
+</example>
+
+
+<chapt id="ipass">Information passed through the client/daemon combination
+<p>
+
+The information described below is the only information which passes
+between the caller and the service.
+
+<list>
+<item>
+The service name supplied by the caller is available in the
+configuration language for deciding whether and which service program
+to invoke, in the <prgn/service/ parameter, and is used by the
+<prgn/execute-from-directory/ and <prgn/execute-from-path/
+configuration directives.  It is usually used to select which service
+program to invoke.  It is also passed to the service program in the
+<prgn/USERV_SERVICE/ environment variable.
+
+<item>
+File descriptors specified by the client and allowed according to the
+configuration language will be connected.  Each file descriptor is
+opened for reading or writing.  Communication is via pipes, one end of
+each pipe being open on the appropriate file descriptor in the service
+program (when it is invoked) and the other end being held by the
+client process, which will read and write files it opens on behalf of
+its caller or file descriptors it is passed by its caller.
+<p>
+
+Data may be passed into the service through reading pipes and out of
+it through writing pipes.  These pipes can remain open only until the
+service and client have terminated, or can be made to stay open after
+the client has terminated and (if the service program forks) the main
+service process has exited; the behaviour is controlled by options
+passed to the client by its caller.
+<p>
+
+The caller can arrange that a writing pipe be connected to a pipe or
+similar object and cause attempts to write to that descriptor by the
+service to generate a <prgn/SIGPIPE/ (or <prgn/EPIPE/ if
+<prgn/SIGPIPE/ is caught or ignored) in the service.
+<p>
+
+Likewise, the service can close filedescriptors specified for reading,
+which will cause the corresponding filedescriptors passed by the
+caller to be closed, so that if these are pipes processes which write
+to them will receive <prgn/SIGPIPE/ or <prgn/EPIPE/.
+
+<item>
+If <prgn/no-suppress-args/ is set then arguments passed to the client
+by its caller will be passed on, verbatim, to the service.
+
+<item>
+Fatal signals and system call failures experienced by the client will
+result in the disconnection of the service from the client and
+possibly some of the communication file descriptors described above;
+if <prgn/disconnect-hup/ is set then the service will also be sent a
+<prgn/SIGHUP/.
+
+<item>
+The value of the <prgn/LOGNAME/ (or <prgn/USER/) environment variable
+as passed to the client will be used as the login name of the calling
+user if the uid of the calling process matches the uid corresponding
+to that login name.  Otherwise the calling uid's password entry will
+be used to determine the calling user's login name.
+<p>
+
+This login name and the calling uid are available in the configuration
+language in the <prgn/calling-user/ parameter and are passed to the
+service program in environment variables <prgn/USERV_USER/ and
+<prgn/USERV_UID/.
+<p>
+
+The shell corresponding to that login name (according to the password
+entry) is available as in the configuration language's
+<prgn/calling-user-shell/ parameter.
+<p>
+
+If no relevant password entry can be found then no service will be
+invoked.
+
+<item>
+The numeric values and textual names for calling gid and supplementary
+group list are available in the configuration language in the
+<prgn/calling-group/ parameter and are passed to the service in
+environment variables.
+<p>
+
+If no name can be found for a numeric group to which the calling
+process belongs then no service will be invoked.
+
+<item>
+The name of the current working directory in which the client was
+invoked is passed, if available and not hidden using <prgn/--hidecwd/,
+to the service program in the <prgn/USERV_CWD/ variable.  This grants no
+special access to that directory unless it is a subdirectory of a
+directory which is executable (searchable) but not readable by the
+service user.
+
+<item>
+Settings specified by the caller using the <tt/--defvar
+<var/name/=<var/value// option to the client are available in the
+configuration language as the corresponding <tt/u-<var/name//
+parameters and are passed to the service program in environment
+variables <tt/USERV_U_<var/name//.
+
+<item>
+If the calling user is root or the same as the service user then
+options may be given to the client which bypass the usual security
+features; in this case other information may pass between the caller
+and the service.
+
+</list>
+
+<chapt id="notes">Applications and notes on use
+<p>
+
+<sect id="reducepriv">Reducing the number of absolutely privileged subsystems
+<p>
+
+Currently most Unix systems have many components which need to run as
+root, even though most of their activity does not strictly require
+it.  This gives rise to a large and complex body of code which must be
+trusted with the security of the system.
+<p>
+
+Using <prgn/userv/ many of these subsystems no longer need any unusual
+privilege.
+<p>
+
+<prgn/cron/ and <prgn/at/, <prgn/lpr/ and the system's mail transfer
+agent (<prgn/sendmail/, <prgn/smail/, <prgn/exim/ or the like) all
+fall into this category.
+
+<sect id="noexcess">Do not give away excessive privilege to <prgn/userv/-using facilities
+<p>
+
+There is a danger that people reimplementing the facilities I mention
+above using <prgn/userv/ will discard much of the security benefit by
+using a naive implementation technique.  This will become clearer with
+an example:
+<p>
+
+Consider the <prgn/lpr/ program.  In current systems this needs to
+have an absolutely privileged component in order to support delayed
+printing without copying: when the user queues a file to be printed
+the filename is stored in the print queue, rather than a copy of it,
+and the printer daemon accesses the file directly when it is ready to
+print the job.  In order that the user can print files which are not
+world-readable the daemon is given root privilege so that it can open
+the file in the context of the user, rather than its own.
+<p>
+
+A simple-minded approach to converting this scheme to use <prgn/userv/
+might involve giving the printer daemon (the <prgn/lp/ user) the
+ability to read the file by allowing them to run <prgn/cat/ (or a
+special-purpose file-reading program) as any user.  The <prgn/lpr/
+program would use a <prgn/userv/ service to store the filename in the
+printer daemon's queues, and the daemon would read the file later when
+it felt like it.
+<p>
+
+However, this would allow the printer daemon to read any file on the
+system, whether or not someone had asked for it to be printed.  Since
+many files will contain passwords and other security-critical
+information this is nearly as bad as giving the daemon root access in
+the first place.  Any security holes in the print server which allow a
+user to execute commands as the <prgn/lp/ user will give the user the
+ability to read any file on the system.
+<p>
+
+Instead, it is necessary to keep a record of which files the daemon
+has been asked to print <em/outside/ the control of the print daemon.
+This record could be kept by a new root-privileged component, but this
+is not necessary: the record of which files a user has asked to be
+printed can be kept under the control of the user in question.  The
+submission program <prgn/lpr/ will make a record in an area under the
+user's control before communicating with the print server, and the
+print server would be given the ability to run a special file-reading
+program which would only allow files to be read which were listed in
+the user's file of things they'd asked to print.
+<p>
+
+Now security holes in most of the printing system do not critically
+affect the security of the entire system: they only allow the attacker
+to read and interfere with print jobs.  Bugs in the programs run by the
+print server to read users' files (and to remove entries from the list
+of files when it has done with them) will still be serious, but this
+program can be quite simple.
+<p>
+
+Similar considerations apply to many <prgn/userv/-based versions of
+facilities which currently run as root.
+<p>
+
+It is debatable whether the user-controlled state should be kept in
+the user's filespace (in dotfiles, say) or kept in a separate area set
+aside for the purpose; however, using the user's home directory (and
+probably creating a separate subdirectory of it as a dotfile to
+contain many subsystems' state) has fewer implications for the rest of
+the system and makes it entirely clear where the security boundaries
+lie.
+
+<sect id="notreally"><prgn/userv/ is not a replacement for <prgn/really/ and <prgn/sudo/
+<p>
+
+<prgn/userv/ is not intended as a general-purpose system
+administration tool with which system administrators can execute
+privileged programs when they need to.  It is unsuitable for this
+purpose precisely because it enforces a strong separation between the
+calling and the called program, which is undesirable in this context.
+<p>
+
+Its facilities for restricting activities to running certain programs
+may at first glance seem to provide similar functionality to
+<prgn/sudo/<footnote><prgn/sudo/ is a program which allows users to
+execute certain programs as root, according to configuration files
+specified by the system administrator.</footnote>.  However, the
+separation mentioned above is a problem here too, particular for
+interaction - it can be hard for a <prgn/userv/ service program to
+interact with its real caller or the user in question.
+
+<sect id="nogeneral">Don't give access to general-purpose utilities
+<p>
+
+Do not specify general purpose programs like <prgn/mv/ or <prgn/cat/
+in <prgn/execute-/ directives without careful thought about their
+arguments, and certainly not if <prgn/no-suppress-args/ is specified.
+If you do so it will give the caller much more privilige than you
+probably intend.
+<p>
+
+It is a shame that I have to say this here, but inexperienced
+administrators have made similar mistakes with programs like
+<prgn/sudo/.
+
+</book>