From 022a6968ae0ede1259141e32b8e32553dad7d824 Mon Sep 17 00:00:00 2001 From: Jakob Unterwurzacher Date: Tue, 6 Oct 2015 00:29:08 +0200 Subject: [PATCH] Implement proper daemonization The shell wrapper sends gocryptfs into the background and waits for SIGUSR1 --- all.bash | 2 -- cryptfs/cryptfs.go | 3 ++- gocryptfs | 19 +++++++++--------- gocryptfs_main/main.go | 37 +++++++++++++++++++++------------- gocryptfs_main/sendsig.go | 42 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 77 insertions(+), 26 deletions(-) create mode 100644 gocryptfs_main/sendsig.go diff --git a/all.bash b/all.bash index 08bc7cf..ab55293 100755 --- a/all.bash +++ b/all.bash @@ -3,6 +3,4 @@ set -eu cd gocryptfs_main -echo -n "Compiling... " go build -echo "done." diff --git a/cryptfs/cryptfs.go b/cryptfs/cryptfs.go index c58481c..214ea10 100644 --- a/cryptfs/cryptfs.go +++ b/cryptfs/cryptfs.go @@ -9,10 +9,11 @@ import ( ) const ( + DEFAULT_PLAINBS = 4096 KEY_LEN = 16 NONCE_LEN = 12 AUTH_TAG_LEN = 16 - DEFAULT_PLAINBS = 4096 + FILEID_LEN = 16 ) type CryptFS struct { diff --git a/gocryptfs b/gocryptfs index ce15b97..73d7b42 100755 --- a/gocryptfs +++ b/gocryptfs @@ -1,9 +1,13 @@ #!/bin/bash -# Simple wrapper that runs the gocryptfs process in the background +# Shell wrapper that runs the gocryptfs process in the background +# and exits on SIGUSR1 set -eu +trap "exit 0" SIGUSR1 +shopt -u huponexit + dir=$(dirname "$0") main="$dir/gocryptfs_main/gocryptfs_main" @@ -12,11 +16,8 @@ if [ ! -x $main ]; then exit 1 fi -# This needs user input and cannot run in the background -if [[ $* == *--init* ]]; then - "$main" $* -else - "$main" $* & - sleep 0.1 - disown -fi +# A backgrounded process gets /dev/null as stdin per default. +# Explicitly set stdin to the current stdin so we can ask the user for input. +"$main" $* < /proc/self/fd/0 & wait +# The "& wait" is neccessary because bash only processes signals when +# executing internal commands diff --git a/gocryptfs_main/main.go b/gocryptfs_main/main.go index ae3974e..3674eb2 100644 --- a/gocryptfs_main/main.go +++ b/gocryptfs_main/main.go @@ -128,11 +128,20 @@ func main() { fmt.Println(err) os.Exit(ERREXIT_LOADCONF) } - fmt.Printf("Success\n") + fmt.Printf("done.\n") + } + + srv := pathfsFrontend(key, cipherdir, mountpoint, fusedebug) + fmt.Printf("Mounted.\n") + + if zerokey == false { printMasterKey(key) } - pathfsFrontend(key, cipherdir, mountpoint, fusedebug) + // Send notification to our parent + sendSig() + // Jump into server loop + srv.Serve() } // printMasterKey - remind the user that he should store the master key in @@ -143,12 +152,13 @@ func printMasterKey(key []byte) { h = h[0:8] + "-" + h[8:16] + "-" + h[16:24] + "-" + h[24:32] fmt.Printf(` -WARNING: - If the gocryptfs config file becomes corrupted or you ever - forget your password, there is only one hope for recovery: - The master key. Print it to a piece of paper and store it in a drawer. +ATTENTION: - Master key: %s + Your master key is: %s + +If the gocryptfs.conf file becomes corrupted or you ever forget your password, +there is only one hope for recovery: The master key. Print it to a piece of +paper and store it in a drawer. `, h) } @@ -171,7 +181,7 @@ func readPassword() string { fd := int(os.Stdin.Fd()) p, err := terminal.ReadPassword(fd) if err != nil { - fmt.Printf("Error: Could not read password: %s\n") + fmt.Printf("Error: Could not read password: %v\n", err) os.Exit(ERREXIT_PASSWORD) } return string(p) @@ -189,7 +199,7 @@ func dirEmpty(dir string) bool { return false } -func pathfsFrontend(key []byte, cipherdir string, mountpoint string, debug bool) { +func pathfsFrontend(key []byte, cipherdir string, mountpoint string, debug bool) *fuse.Server { finalFs := pathfs_frontend.NewFS(key, cipherdir, USE_OPENSSL) pathFsOpts := &pathfs.PathNodeFsOptions{ClientInodes: true} @@ -210,13 +220,12 @@ func pathfsFrontend(key []byte, cipherdir string, mountpoint string, debug bool) // Second column, "Type", will be shown as "fuse." + Name mOpts.Name = "gocryptfs" - state, err := fuse.NewServer(conn.RawFS(), mountpoint, &mOpts) + srv, err := fuse.NewServer(conn.RawFS(), mountpoint, &mOpts) if err != nil { - fmt.Printf("Mount fail: %v\n", err) + fmt.Printf("Mount failed: %v", err) os.Exit(1) } - state.SetDebug(debug) + srv.SetDebug(debug) - fmt.Println("Mounted.") - state.Serve() + return srv } diff --git a/gocryptfs_main/sendsig.go b/gocryptfs_main/sendsig.go new file mode 100644 index 0000000..98bd448 --- /dev/null +++ b/gocryptfs_main/sendsig.go @@ -0,0 +1,42 @@ +package main + +import ( + "syscall" + "bytes" + "fmt" + "os" + "io/ioutil" +) + +// cmdline looks like this: /bin/bash \0 /path/to/gocryptfs \0 --zerokey \0 ... +const ( + WRAPPER_PREFIX = "/bin/bash\000" + WRAPPER_CONTAINS = "gocryptfs\000" +) + +// Send USR1 to the "gocryptfs" wrapper shell script. This notifies it that the +// mounting has completed sucessfully. +// +// Checks /proc/$PPID/cmdline to make sure we do not kill an unrelated process. +func sendSig() { + ppid := os.Getppid() + fn := fmt.Sprintf("/proc/%d/cmdline", ppid) + cmdline, err := ioutil.ReadFile(fn) + if err != nil { + fmt.Printf("sendSig: ReadFile: %v\n", err) + return + } + if bytes.HasPrefix(cmdline, []byte(WRAPPER_PREFIX)) && bytes.Contains(cmdline, []byte(WRAPPER_CONTAINS)) { + p, err := os.FindProcess(ppid) + if err != nil { + fmt.Printf("sendSig: FindProcess: %v\n", err) + return + } + err = p.Signal(syscall.SIGUSR1) + if err != nil { + fmt.Printf("sendSig: Signal: %v\n", err) + } + } else { + fmt.Printf("Not running under the gocryptfs wrapper - will not daemonize\n") + } +}