aboutsummaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
authorJakob Unterwurzacher2016-11-10 00:27:08 +0100
committerJakob Unterwurzacher2016-11-10 00:27:08 +0100
commit75ebb28a625bc16d145f5acd9e0cc1d305716afe (patch)
tree6e4c654c67b93933a2575857883777b3f05fc5d3 /internal
parentdf28fc5a11f5e52897f45cc299ab62a2a2cbaf4c (diff)
ctlsock: add initial limited implementation
At the moment, in forward mode you can only encrypt paths and in reverse mode you can only decrypt paths.
Diffstat (limited to 'internal')
-rw-r--r--internal/ctlsock/ctlsock_serve.go137
-rw-r--r--internal/fusefrontend/ctlsock_interface.go19
-rw-r--r--internal/fusefrontend/write_lock.go2
-rw-r--r--internal/fusefrontend_reverse/ctlsock_interface.go19
-rw-r--r--internal/fusefrontend_reverse/rfs.go2
5 files changed, 177 insertions, 2 deletions
diff --git a/internal/ctlsock/ctlsock_serve.go b/internal/ctlsock/ctlsock_serve.go
new file mode 100644
index 0000000..571260d
--- /dev/null
+++ b/internal/ctlsock/ctlsock_serve.go
@@ -0,0 +1,137 @@
+// Package ctlsock implementes the control socket interface that can be
+// activated by passing "-ctlsock" on the command line.
+package ctlsock
+
+import (
+ "encoding/json"
+ "errors"
+ "io"
+ "net"
+ "os"
+ "syscall"
+
+ "github.com/rfjakob/gocryptfs/internal/tlog"
+)
+
+// Interface should be implemented by fusefrontend[_reverse]
+type Interface interface {
+ EncryptPath(string) (string, error)
+ DecryptPath(string) (string, error)
+}
+
+// RequestStruct is sent by a client
+type RequestStruct struct {
+ EncryptPath string
+ DecryptPath string
+}
+
+// ResponseStruct is sent by us as response to a request
+type ResponseStruct struct {
+ // Result is the resulting decrypted or encrypted path. Empty on error.
+ Result string
+ // ErrNo is the error number as defined in errno.h.
+ // 0 means success and -1 means that the error number is not known
+ // (look at ErrText in this case).
+ ErrNo int32
+ // ErrText is a detailed error message.
+ ErrText string
+}
+
+type ctlSockHandler struct {
+ fs Interface
+ socket *net.UnixListener
+}
+
+// CreateAndServe creates an unix socket at "path" and serves incoming
+// connections in a new goroutine.
+func CreateAndServe(path string, fs Interface) error {
+ sock, err := net.Listen("unix", path)
+ if err != nil {
+ return err
+ }
+ handler := ctlSockHandler{
+ fs: fs,
+ socket: sock.(*net.UnixListener),
+ }
+ go handler.acceptLoop()
+ return nil
+}
+
+func (ch *ctlSockHandler) acceptLoop() {
+ for {
+ conn, err := ch.socket.Accept()
+ if err != nil {
+ tlog.Warn.Printf("ctlsock: Accept error: %v", err)
+ break
+ }
+ go ch.handleConnection(conn.(*net.UnixConn))
+ }
+}
+
+func (ch *ctlSockHandler) handleConnection(conn *net.UnixConn) {
+ // 2*PATH_MAX is definitely big enough for requests to decrypt or
+ // encrypt paths.
+ buf := make([]byte, 2*syscall.PathMax)
+ for {
+ n, err := conn.Read(buf)
+ if err == io.EOF {
+ conn.Close()
+ return
+ } else if err != nil {
+ tlog.Warn.Printf("ctlsock: Read error: %#v", err)
+ conn.Close()
+ return
+ }
+ buf = buf[:n]
+ var in RequestStruct
+ err = json.Unmarshal(buf, &in)
+ if err != nil {
+ tlog.Warn.Printf("ctlsock: Unmarshal error: %#v", err)
+ errorMsg := ResponseStruct{
+ ErrNo: int32(syscall.EINVAL),
+ ErrText: err.Error(),
+ }
+ sendResponse(&errorMsg, conn)
+ }
+ ch.handleRequest(&in, conn)
+ // Restore original size.
+ buf = buf[:cap(buf)]
+ }
+}
+
+func (ch *ctlSockHandler) handleRequest(in *RequestStruct, conn *net.UnixConn) {
+ var err error
+ var out ResponseStruct
+ if in.DecryptPath != "" && in.EncryptPath != "" {
+ err = errors.New("Ambigous")
+ } else if in.DecryptPath == "" && in.EncryptPath == "" {
+ err = errors.New("No operation")
+ } else if in.DecryptPath != "" {
+ out.Result, err = ch.fs.DecryptPath(in.DecryptPath)
+ } else if in.EncryptPath != "" {
+ out.Result, err = ch.fs.EncryptPath(in.EncryptPath)
+ }
+ if err != nil {
+ out.ErrText = err.Error()
+ out.ErrNo = -1
+ // Try to extract the actual error number
+ if pe, ok := err.(*os.PathError); ok {
+ if se, ok := pe.Err.(syscall.Errno); ok {
+ out.ErrNo = int32(se)
+ }
+ }
+ }
+ sendResponse(&out, conn)
+}
+
+func sendResponse(msg *ResponseStruct, conn *net.UnixConn) {
+ jsonMsg, err := json.Marshal(msg)
+ if err != nil {
+ tlog.Warn.Printf("ctlsock: Marshal failed: %v", err)
+ return
+ }
+ _, err = conn.Write(jsonMsg)
+ if err != nil {
+ tlog.Warn.Printf("ctlsock: Write failed: %v", err)
+ }
+}
diff --git a/internal/fusefrontend/ctlsock_interface.go b/internal/fusefrontend/ctlsock_interface.go
new file mode 100644
index 0000000..c22dce6
--- /dev/null
+++ b/internal/fusefrontend/ctlsock_interface.go
@@ -0,0 +1,19 @@
+package fusefrontend
+
+import (
+ "errors"
+
+ "github.com/rfjakob/gocryptfs/internal/ctlsock"
+)
+
+var _ ctlsock.Interface = &FS{} // Verify that interface is implemented.
+
+// EncryptPath implements ctlsock.Backend
+func (fs *FS) EncryptPath(plainPath string) (string, error) {
+ return fs.encryptPath(plainPath)
+}
+
+// DecryptPath implements ctlsock.Backend
+func (fs *FS) DecryptPath(plainPath string) (string, error) {
+ return "", errors.New("Not implemented")
+}
diff --git a/internal/fusefrontend/write_lock.go b/internal/fusefrontend/write_lock.go
index 7394994..3addfd6 100644
--- a/internal/fusefrontend/write_lock.go
+++ b/internal/fusefrontend/write_lock.go
@@ -21,7 +21,7 @@ var wlock wlockMap
// 2) lock ... unlock ...
// 3) unregister
type wlockMap struct {
- // Counts lock() calls. As every operation that modifies a file should
+ // opCount counts lock() calls. As every operation that modifies a file should
// call it, this effectively serves as a write-operation counter.
// The variable is accessed without holding any locks so atomic operations
// must be used. It must be the first element of the struct to guarantee
diff --git a/internal/fusefrontend_reverse/ctlsock_interface.go b/internal/fusefrontend_reverse/ctlsock_interface.go
new file mode 100644
index 0000000..448663f
--- /dev/null
+++ b/internal/fusefrontend_reverse/ctlsock_interface.go
@@ -0,0 +1,19 @@
+package fusefrontend_reverse
+
+import (
+ "errors"
+
+ "github.com/rfjakob/gocryptfs/internal/ctlsock"
+)
+
+var _ ctlsock.Interface = &reverseFS{} // Verify that interface is implemented.
+
+// EncryptPath implements ctlsock.Backend
+func (rfs *reverseFS) EncryptPath(plainPath string) (string, error) {
+ return "", errors.New("Not implemented")
+}
+
+// DecryptPath implements ctlsock.Backend
+func (rfs *reverseFS) DecryptPath(plainPath string) (string, error) {
+ return rfs.decryptPath(plainPath)
+}
diff --git a/internal/fusefrontend_reverse/rfs.go b/internal/fusefrontend_reverse/rfs.go
index 87a2602..84348f7 100644
--- a/internal/fusefrontend_reverse/rfs.go
+++ b/internal/fusefrontend_reverse/rfs.go
@@ -49,7 +49,7 @@ var _ pathfs.FileSystem = &reverseFS{}
// NewFS returns an encrypted FUSE overlay filesystem.
// In this case (reverse mode) the backing directory is plain-text and
// reverseFS provides an encrypted view.
-func NewFS(args fusefrontend.Args) pathfs.FileSystem {
+func NewFS(args fusefrontend.Args) *reverseFS {
if args.CryptoBackend != cryptocore.BackendAESSIV {
panic("reverse mode must use AES-SIV, everything else is insecure")
}