GNU Rush |
|
Restricted User Shell |
Sergey Poznyakoff |
In this chapter we will explain how to write GNU Rush configuration rules for several popular remote copy and version control system utilities. For this purpose, we assume the following setup:
scp
and rsync
to upload
files to the /incoming directory and to copy files to and from
their ~/public_html directory.
The actual location of the /incoming directory is /home/ftp,
but that must be transparent to users, i.e. they use
scp file host:/incoming
(not
host:/home/ftp/incoming
) to upload files.
sftp
to manage their
~/public_html directory. In this case, to prevent users from
accessing other directories, sftp-server
is executed in a
chrooted environment.
VCS | Repository Root |
---|---|
cvs | /cvsroot |
svn | /svnroot |
git | /gitroot |
The scp
utility is executed on the server side
with option -t, when copying files to server, and with
-f when copying from it. Thus, the basic templates for
scp
rules are:
# Copying to server: rule scp-to match $command ~ "^scp -t" ... # Copying from server: rule scp-from match $command ~ "^scp -f" ...
You may also wish to allow for -v (‘verbose’) command line option. In this case, the ‘scp-to’ rule will become:
rule scp-to match $command ~ "^scp (-v )?-t" ...
Now, we want users to be able to upload files to
/home/ftp/incoming directory. Moreover, the /home/ftp
directory prefix must be invisible to them. We should also make sure
that the user cannot get outside the incoming directory by using
../ components in his upload path. So, our first rule for
scp
uploads will be:
rule scp-to-incoming match $command ~ "^scp (-v )?-t /incoming/" && \ ${-1} !~ "\\.\\./" set command "/bin/scp" set [-1] =~ "s|^|/home/ftp/|"
The match
statement ensures that no relative components are
used. The two set
statements ensure that the right
scp
binary is used and that /home/ftp prefix is
prepended to the upload path.
Other than uploading to /incoming, users must be able to use
scp
to manage public_html directories located in
their homes. They should use relative paths for that, i.e., the
command:
$ scp file.html server:
will copy file file.html to ~/public_html/file.html on the server. The corresponding rule is:
rule scp-home match $command ~ "^scp (-v )?-[tf] [^/].*" && \ ${-1} !~ "\\.\\./" set [0] = "/bin/scp" set [-1] =~ "s|^|public_html/|" chdir "~"
Finally, we provide two trap rules for diagnostic purposes:
rule scp-to-trap match $command ~ "^scp (-v )?-t" exit "Error: Uploads to this directory prohibited" rule scp-from match $command ~ "^scp (-v )?-f" exit Error: Downloads from this directory prohibited
On the server side, rsync
is executed with the
--server command line option. In addition, when copying
files from the server, the --sender option is used. This
makes it possible to discern between incoming and outgoing requests.
In our setup, rsync
is used the same way as scp
, so
the two rules will be:
rule rsync-incoming match $command ~ "^rsync --server" && \ $command !~ --sender && \ ${-1} ~ "/incoming/" && ${-1} !~ "\\.\\./" set [0] =~ "s|^|/usr/bin/|" set [-1] =~ "s|^|/home/ftp/|" rule rsync-home match $command ~ "^rsync" && \ ${-1} !~ "^[^/]" && \ ${-1} !~ "\\.\\./" set [0] = "s|^|/usr/bin/|" set [-1] =~ "s|^|public_html/|" chdir "~"
The trap rules for rsync
are trivial:
rule rsync-to-trap match $command ~ "^rsync.*--sender" exit "Error: Downloads from this directory prohibited" rule rsync-from-trap match $command ~ "^rsync" exit "Error: Uploads to this directory prohibited"
Executing sftp
on the client machine invokes
sftp-server
, without arguments, on the server.
We want to allow our users to use sftp
to manage their
public_html directories. The sftp-server
will be
executed with the user’s home directory as root, in a chrooted
environment. For this to work, each user’s home must contain a copy
of sftp-server
(which we’ll place in ~/bin
subdirectory) and all files it needs for normal execution:
/etc/group and /etc/passwd with one entry
(for the user and his group), and, unless the binary is linked
statically, all the shared libraries it is linked with, in the
subdirectory ~/lib.
Given these prerequisites, the following rule will ensure proper
sftp
interaction:
rule sftp-incoming match $command ~ "^.*/sftp-server" set [0] = "/bin/sftp-server" chroot "~" chdir "public_html"
Notice the last action. Due to it, users don’t have to type cd
public_html
at the beginning of their sftp sessions.
Using cvs
over ssh
invokes cvs server
on
the server machine. In the simplest case, the following rule will do
to give users access to CVS repositories:
rule cvs match $command ~ "^cvs server" set command ~ "s|^cvs|/usr/bin/cvs -f"
However, cvs
as of version 1.12.13 does not allow to limit root
directories that users are allowed to access. It does have
--allow-root option, but unfortunately this option is ignored when
invoked as cvs server
. To restrict possible roots, we have
to run cvs
in a chrooted environment. Let’s suppose we
created an environment for cvs
in directory /var/cvs,
with the cvs
binary located in /var/cvs/bin and
repository root directory being /var/cvs/cvsroot. Then, we can
use the following rule:
rule cvs match $command ~ "^cvs server" set [0] = "/bin/cvs" chroot "/var/cvs"
Remote access to SVN repositories is done via
svnserve
binary. It is executed on server with -t
option. The -r option can be used to restrict access to a
subset of root directories. So, we can use the following rule:
rule svn match $command ~ "^svnserve -t" set command =~ "s|-r *[^ ]*||" set command =~ \ "s|^svnserve |/usr/bin/svnserve -r /svnroot|"
The first set command
action removes any -r options
the user might have specified and enforces a single root directory. A
more restrictive action can be used to improve security:
set command =~ "s|.*|/usr/bin/svnserve -r /svnroot|"
Remote access to Git repositories over ssh causes execution of
git-receive-pack
and git-upload-pack
on the server.
The simplest rule for Git is:
rule git set $command ~ "^git-(receive|upload)-pack" set [0] =~ "s|^|/usr/bin/|"
The set
action is necessary to ensure the proper location
of Git binaries to use. This example supposes they are placed in
/usr/bin, you will have to tailor it if they are located
elsewhere on your system.
To limit Git accesses to repositories under /gitroot directory, modify the ‘$1’, as shown in the example below:
rule git match $command ~ "^git-(receive|upload)-pack" set [1] =~ "^/gitroot[^ ]+\.git$" set [0] =~ "s|^|/usr/bin/|"
To provide more helpful error messages, you may follow this rule by a trap rule (see trap rules):
# Trap the rest of Git requests:
rule git-trap
match $command ~ "^git-.+"
exit "fatal: access to this repository is denied."
In this section we will show how to set up a mail notification for
Rush rules. Let’s suppose we wish to receive emails for each upload
by scp-to
rule (see scp). To do so, we add the following
fall through rule to the beginning of rush.rc:
rule default post-socket "inet://localhost" fall-trough
This will enable notifications for each rule located below this one.
Missing port in post-socket
statement means rush
will
be using the default ‘tcpmux’ port.
To receive and process these requests, you will need an
inetd
capable to handle TCPMUX. We recommend the
one from GNU Inetutils package
(GNU Inetutils). In
/etc/inetd.conf file, we add:
# Enable TCPMUX handling. tcpmux stream tcp nowait root internal # Handle ‘scp-to’ service. tcpmux/+scp-to stream tcp nowait root \ /usr/sbin/tcpd /bin/rushmail
The program /bin/rushmail
does the actual notification.
Following is its simplest implementation:
#! /bin/sh read user command /usr/sbin/sendmail -oi -t <<EOT From: GNU Rush Notification <devnull@localhost> To: <root@localhost> Subject: GNU Rush notification Be informed that $user executed $command. EOT
This document was generated on January 2, 2022 using makeinfo.
Verbatim copying and distribution of this entire article is permitted in any medium, provided this notice is preserved.