The goal is to automatically synchronize files between several hosts without
compromising the integrity of the separate machines. A nice tool for 2-way sync
is unison. To
sync files between different machines The Right Way (TM) is to tunnel the
unison protocol over ssh. This is well supported by unison.
To run sync automatically (e.g. via cron), you need to
create an SSH keypair
without passphrase, so unison can log into the other machine without human
interaction. This is where the problems start, since anyone who got access to
the private key (e.g. by compromising or stealing the machine the private key
was on) can log into the other host.
Now ssh has a nice way to restrict what you can do with a specific key, so you
can e.g. use the following in the remote hosts
command="/usr/bin/unison -server" ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA8K2cd0yemw...
That way someone who has the private key can't execute arbitrary commands, but
just unison in server mode. However it's still possible to tell the unison
server to overwrite arbitrary files (which the user has write access to). This
is a major problem, since also files like
~/.bashrc can be
overwritten, so the next time the user logs in, arbitrary commands will be
A possible solution
One solution is to simply create a new user on the remote host with a disabled
password, and let unison run as that user (via adding the appropriate line to
$HOME/.ssh/authorized_keys, and telling the local unison to use
That's possible, but the
.bashrc trick still works, it's just less
likely that the code there is ever executed (root would have to use
su to become that user).
For me this solution didn't work out since I wanted to sync my maildir, and it
was hard to ensure that file permissions were set in a way that both allowed me
to read my mail and allowed unison (running under user unison-sync) to sync the
The Right Solution (TM)
All the problems vanish as soon as you run unison under the user you'd normally
use, but in a chroot. Now a full-blown chroot takes up a lot of space, and
there's once again the danger that someone might enter the chroot and run some
kind of shell (though the risk is even lower).
It's best to use a chroot which only contains the bare minimum of files
necessary to run
You get numerous advantages:
- No problems with file permissions
- No shell inside the chroot that would read startup files from
- Hardly any space wasted. The whole chroot is about 4Mb in size
- Since the chroot is pretty much empty, many common exploits (well, shell codes) won't work
How to do it
greek0@orest:/home/chroots/unichroot$ cat ~/.ssh/authorized_keys
command="/usr/bin/dchroot -q -c unison -- /usr/bin/unison -server" ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA8K2cd0.....
greek0@orest:/home/chroots/unichroot$ grep unison /etc/dchroot.conf
greek0@orest:/home/chroots/unichroot$ find . -maxdepth 3 | xargs ls -ld
drwxr-xr-x 2 root root 4096 2006-08-04 16:39 ./bin
-rwxr-xr-x 1 root root 576100 2006-08-04 15:06 ./bin/sash
lrwxrwxrwx 1 root root 4 2006-08-04 16:39 ./bin/zsh -> sash
drwxr-xr-x 3 root root 4096 2006-08-04 15:10 ./home
drwx------ 4 greek0 greek0 4096 2006-08-04 15:18 ./home/greek0
drwx------ 31 greek0 greek0 4096 2006-08-04 13:47 ./home/greek0/Maildir
drwx------ 2 greek0 greek0 4096 2006-08-04 15:47 ./home/greek0/.unison
drwxr-xr-x 2 root root 4096 2006-08-04 15:07 ./lib
-rwxr-xr-x 1 root root 88164 2006-08-04 14:58 ./lib/ld-linux.so.2
-rwxr-xr-x 1 root root 1151644 2006-08-04 14:56 ./lib/libc.so.6
-rw-r--r-- 1 root root 9592 2006-08-04 14:56 ./lib/libdl.so.2
-rw-r--r-- 1 root root 141040 2006-08-04 14:55 ./lib/libm.so.6
-rw-r--r-- 1 root root 9656 2006-08-04 14:55 ./lib/libutil.so.1
drwxr-xr-x 3 root root 4096 2006-08-04 14:53 ./usr
drwxr-xr-x 2 root root 4096 2006-08-04 14:55 ./usr/bin
lrwxrwxrwx 1 root root 14 2006-08-04 15:12 ./usr/bin/unison -> unison-2.13.16
-rwxr-xr-x 1 root root 955784 2006-08-04 14:54 ./usr/bin/unison-2.13.16
zsh symlink is there because I have
my shell in
/etc/passwd, and dchroot also wants to use it in the
chroot (for launching unison).
/home/greek0/Maildir is bind-mounted from outside the chroot,
bind-mounting is done at boot-time via
The chroot was created manually, simply by copying the files from the host. You
/usr/bin/unison plus all the libraries it depends
on. You can find those via
readelf -d /usr/bin/unison | grep NEEDED.
Additionally you need the dynamic linker
readelf -l /usr/bin/unison | grep INTERP -A 1).
One thing to pay attention to is that most of the files copied from
/lib are symlinks. Be sure to either use
arguments, or use
cp -a and copy the link targets too.