Saturday, February 9, 2008

A simple way to manage encrypted filesystems on shell servers

If you haven't checked out the FUSE tool encfs, look it up - it doesn't need any information on itself, it's incredibly simple to use.

http://fuse.sourceforge.net/
http://www.arg0.net/encfs


I've made a simple script to automatically mount and unmount an encfs filesystem on a system (This is designed with connecting to a remote shell server in mind).
Right now, it mounts the encfs on login if you tell it to, and if once you logout there are no more interactive sessions logged in (NOTE: My check for this is potentially NASTY! Please provide feedback on a better solution if you have any ideas! I think what I have will only work on Linux systems that store TTY info in /dev/pts/, and even then it's kind of tailored to my environment - you've been warned!

What this does when you SSH in to the server:
1) Ask if you want to mount your encrypted filesystem
2) If you just hit enter, or say "n" (Actually, if you say anything other than "y" or "Y") it will not mount the FS.
2a) If you say "y" or "Y" it will go ahead and mount the filesystem, attempting to create it if it does not yet exist.
3) It will write the status of the mount operation to ~/.encfsmounted

When you logout:
1) If ~/.encfsmounted has the mount point in it, -and- you're on your last interactive (TTY allocated) session, it will try to unmount it.
1a) If either of the above is false, it won't be anything.


Potential Problems:
1) Race conditions - what if you ssh in more than once and don't answer the prompt in order? Weirdness could occur.
2) Bizarre TTY allocations could trick the script in to thinking more or less sessions are active (Think about using screen for example - no good!)
3) Probably other things, this was written in about an hour and half across two days.


I've started putting the code in a mercurial repository, so you may browse and check it out here:
http://seadine.org/hg/encfs_automount/


Here's a current snapshot of the code as it exists now, it mostly works - but it seems that FUSE or the EncFS project itself may have some bugs - you'll sometimes see that it hangs on the umount_encfs function (This could very well be a flaw in my script! Feedback is welcome!)


1 #!/bin/bash
2 #
3 # This defines two bash functions to mount and unmount a FUSE EncFS.
4 # You must have setup encfs with $HOME/.encfs/ as the encrypted store,
5 # and $HOME/encfs/ as the mount point prior to this being useful.
6 # Add mount_encfs to a login script, like .bash_login, and umount_encfs
7 # to your .bash_logout script.
8 # The umount_encfs function does some very loose checking to see if it
9 # should unmount the encfs or not. Be sure to manually call umount_encfs
10 # if you can't risk this check failing.
11 # This shall be released AS-IS, author crash@neg9.org
12
13 ENC_STORE="${HOME}/.encfs"
14 ENC_MOUNT="${HOME}/encfs"
15 ENC_STATUS="${HOME}/.encfsmounted"
16
17 function mount_encfs ()
18 {
19 if [ ! -e $ENC_STATUS ]; then
20 echo "nothing mounted" > $ENC_STATUS;
21 fi
22
23 # Check to see if the encfs is already mounted, bail if so
24 ENCFSMOUNTED=$(cat $ENC_STATUS)
25 if [ "${ENCFSMOUNTED}" = "${ENC_MOUNT}" ]; then
26 return;
27 fi;
28
29 # Otherwise, on we go
30 MOUNT="n";
31
32 read -p "Mount encrypted filesystem? [y/N] " MOUNT;
33 if [ "$MOUNT" = "y" -o "$MOUNT" = "Y" ]; then
34 echo "Mounting encrypted filesystem [${ENC_STORE}] on [${ENC_MOUNT}] now..."
35 /usr/bin/encfs $ENC_STORE $ENC_MOUNT;
36 if [ $? -eq 0 ]; then
37 echo "$ENC_MOUNT" > $ENC_STATUS
38 echo "Mounted encrypted filesystem successfully on [${ENC_MOUNT}]";
39 else
40 echo "nothing mounted" > $ENC_STATUS;
41 fi;
42 fi
43
44 return
45 }
46
47 function umount_encfs ()
48 {
49 NINTERACTIVE=$(ls -l /dev/pts/ | grep "^.......... . ${USER}" | wc -l);
50 ENCFSMOUNTED=$(cat $ENC_STATUS)
51 if [ $NINTERACTIVE -le 1 -a "${ENCFSMOUNTED}" = "${ENC_MOUNT}" ]; then
52 /usr/bin/fusermount -u $ENC_MOUNT > /dev/null 2>&1;
53 if [ $? -eq 0 ]; then
54 echo "Unmounted encrypted filesystem [${ENC_STORE}]"
55 echo "nothing mounted" > $ENC_STATUS;
56 else
57 echo "Failed to unmount encrypted filesystem [${ENC_STORE}]";
58 fi;
59 fi
60
61 return
62 }
63
64 function umount_encfs_force ()
65 {
66 /usr/bin/fusermount -u $ENC_MOUNT > /dev/null 2>&1;
67 if [ $? -eq 0 ]; then
68 echo "Unmounted encrypted filesystem [${ENC_STORE}]"
69 echo "nothing mounted" > $ENC_STATUS;
70 else
71 echo "Failed to unmount encrypted filesystem [${ENC_STORE}]";
72 fi;
73
74 return
75 }


I presented this as a short lightning talk at GSLUG on February 9th, 2008.