The companion package,
userv-utils, contains a selection of
example services, some of which are useful tools in their own right. See the
README in its top-level directory for details.
In later versions of this specification standard service names and interfaces for common services such as mail delivery and WWW CGI scripts may be specified.
userv-using applications and system services which hide
userv behind wrapper scripts may need to store information in the
user's filespace to preserve the correct placement of the security perimiters.
Such applications should usually do so in a directory (created by them)
~/.userv/service, where service is the
service name or application in question.
If desired, a dot-directory inside ~/.userv may be used to avoid the user becoming confused by finding parts of a semi-privileged application's internal state in their filespace, and/or discourage them from fiddling with and thus corrupting it.
userv applications should of course not rely for their
global integrity and security on the integrity of the data on the user's side
of the security boundary.
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.
If they were to use
userv, many of these subsystems would no
longer need any unusual privilege.
lpr and the system's mail
transfer agent (
the like) all fall into this category, though
of these programs are not currently available.
There is a danger that people reimplementing the facilities I mention above
userv will discard much of the security benefit by using a
naive implementation technique. This will become clearer with an example:
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.
A simple-minded approach to converting this scheme to use
might involve giving the printer daemon (the
lp user) the ability
to read the file by allowing them to run
cat (or a special-purpose
file-reading program) as any user. The
lpr program would use a
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.
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
will give the user the ability to read any file on the system.
Instead, it is necessary to keep a record of which files the daemon has been
asked to print 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
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.
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.
Similar considerations apply to many
userv-based versions of
facilities which currently run as root.
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 possibly creating a separate subdirectory of it as a dotfile to contain subsystem state) has fewer implications for the rest of the system and makes it entirely clear where the security boundaries lie.
uservcan often replace
sudo, but not
userv is not intended as a general-purpose system administration
tool with which system administrators can execute arbitrary programs like text
editors as root (or other system users) 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.
However, its use when restricted to running particular programs in particular
ways is very similar to many common uses of
userv is generally
much better than restricted
sudo, because it protects the called
program much more strongly from bad environmental conditions set up by the
caller. Most programs that one might want to run via restricted
sudo, have not been designed to run in a partially hostile
userv allows these programs to be run in a safer
environment and should be used instead.
When the service program is reading from a file descriptor connected to the
calling side, the fd that the service program refers to a pipe set up by
userv and not to the same object as was presented by the caller.
Therefore if there is some kind of error it is possible for the service-side fd to give premature end of file. If it is important to tell whether all of the intended data has been received by the service program, the datastream must contain an explicit end-of-file indication of some kind.
For example, consider a
userv service for submitting a mail
message, where message is supplied on the service's stdin. However, if the
calling process is interrupted before it has written all of the message, the
service program will get EOF on the message data. In a naive arrangement this
would cause a half-complete message to be sent. To prevent this, it is
necessary to adopt some kind of explicit end indication; for example, the end
of the message could be signalled by a dot on a line by itself, and dots
doubled, as in SMTP. Then the service program would know when the entire
message had been received, and could avoid queueing incomplete messages.
Do not specify general purpose programs like
execute- directives without careful thought
about their arguments, and certainly not if
specified. If you do so it will give the caller much more privilige than you
It is a shame that I have to say this here, but inexperienced administrators
have made similar mistakes with programs like
User service daemon and client specification1.0.3