diff options
Diffstat (limited to 'internal/ctlsock')
| -rw-r--r-- | internal/ctlsock/ctlsock_serve.go | 183 | ||||
| -rw-r--r-- | internal/ctlsock/sanitize.go | 32 | ||||
| -rw-r--r-- | internal/ctlsock/sanitize_test.go | 30 | 
3 files changed, 0 insertions, 245 deletions
| diff --git a/internal/ctlsock/ctlsock_serve.go b/internal/ctlsock/ctlsock_serve.go deleted file mode 100644 index 8b19e8a..0000000 --- a/internal/ctlsock/ctlsock_serve.go +++ /dev/null @@ -1,183 +0,0 @@ -// Package ctlsock implements the control socket interface that can be -// activated by passing "-ctlsock" on the command line. -package ctlsock - -import ( -	"encoding/json" -	"errors" -	"fmt" -	"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 -	// WarnText contains warnings that may have been encountered while -	// processing the message. -	WarnText string -} - -type ctlSockHandler struct { -	fs     Interface -	socket *net.UnixListener -} - -// Serve serves incoming connections on "sock". This call blocks so you -// probably want to run it in a new goroutine. -func Serve(sock net.Listener, fs Interface) { -	handler := ctlSockHandler{ -		fs:     fs, -		socket: sock.(*net.UnixListener), -	} -	handler.acceptLoop() -} - -func (ch *ctlSockHandler) acceptLoop() { -	for { -		conn, err := ch.socket.Accept() -		if err != nil { -			// This can trigger on program exit with "use of closed network connection". -			// Special-casing this is hard due to https://github.com/golang/go/issues/4373 -			// so just don't use tlog.Warn to not cause panics in the tests. -			tlog.Info.Printf("ctlsock: Accept error: %v", err) -			break -		} -		go ch.handleConnection(conn.(*net.UnixConn)) -	} -} - -// ReadBufSize is the size of the request read buffer. -// The longest possible path is 4096 bytes on Linux and 1024 on Mac OS X so -// 5000 bytes should be enough to hold the whole JSON request. This -// assumes that the path does not contain too many characters that had to be -// be escaped in JSON (for example, a null byte blows up to "\u0000"). -// We abort the connection if the request is bigger than this. -const ReadBufSize = 5000 - -// handleConnection reads and parses JSON requests from "conn" -func (ch *ctlSockHandler) handleConnection(conn *net.UnixConn) { -	buf := make([]byte, ReadBufSize) -	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 -		} -		if n == ReadBufSize { -			tlog.Warn.Printf("ctlsock: request too big (max = %d bytes)", ReadBufSize-1) -			conn.Close() -			return -		} -		data := buf[:n] -		var in RequestStruct -		err = json.Unmarshal(data, &in) -		if err != nil { -			tlog.Warn.Printf("ctlsock: JSON Unmarshal error: %#v", err) -			err = errors.New("JSON Unmarshal error: " + err.Error()) -			sendResponse(conn, err, "", "") -			continue -		} -		ch.handleRequest(&in, conn) -	} -} - -// handleRequest handles an already-unmarshaled JSON request -func (ch *ctlSockHandler) handleRequest(in *RequestStruct, conn *net.UnixConn) { -	var err error -	var inPath, outPath, clean, warnText string -	// You cannot perform both decryption and encryption in one request -	if in.DecryptPath != "" && in.EncryptPath != "" { -		err = errors.New("Ambiguous") -		sendResponse(conn, err, "", "") -		return -	} -	// Neither encryption nor encryption has been requested, makes no sense -	if in.DecryptPath == "" && in.EncryptPath == "" { -		err = errors.New("Empty input") -		sendResponse(conn, err, "", "") -		return -	} -	// Canonicalize input path -	if in.EncryptPath != "" { -		inPath = in.EncryptPath -	} else { -		inPath = in.DecryptPath -	} -	clean = SanitizePath(inPath) -	// Warn if a non-canonical path was passed -	if inPath != clean { -		warnText = fmt.Sprintf("Non-canonical input path '%s' has been interpreted as '%s'.", inPath, clean) -	} -	// Error out if the canonical path is now empty -	if clean == "" { -		err = errors.New("Empty input after canonicalization") -		sendResponse(conn, err, "", warnText) -		return -	} -	// Actual encrypt or decrypt operation -	if in.EncryptPath != "" { -		outPath, err = ch.fs.EncryptPath(clean) -	} else { -		outPath, err = ch.fs.DecryptPath(clean) -	} -	sendResponse(conn, err, outPath, warnText) -} - -// sendResponse sends a JSON response message -func sendResponse(conn *net.UnixConn, err error, result string, warnText string) { -	msg := ResponseStruct{ -		Result:   result, -		WarnText: warnText, -	} -	if err != nil { -		msg.ErrText = err.Error() -		msg.ErrNo = -1 -		// Try to extract the actual error number -		if pe, ok := err.(*os.PathError); ok { -			if se, ok := pe.Err.(syscall.Errno); ok { -				msg.ErrNo = int32(se) -			} -		} else if err == syscall.ENOENT { -			msg.ErrNo = int32(syscall.ENOENT) -		} -	} -	jsonMsg, err := json.Marshal(msg) -	if err != nil { -		tlog.Warn.Printf("ctlsock: Marshal failed: %v", err) -		return -	} -	// For convenience for the user, add a newline at the end. -	jsonMsg = append(jsonMsg, '\n') -	_, err = conn.Write(jsonMsg) -	if err != nil { -		tlog.Warn.Printf("ctlsock: Write failed: %v", err) -	} -} diff --git a/internal/ctlsock/sanitize.go b/internal/ctlsock/sanitize.go deleted file mode 100644 index 7cf77a5..0000000 --- a/internal/ctlsock/sanitize.go +++ /dev/null @@ -1,32 +0,0 @@ -package ctlsock - -import ( -	"path/filepath" -	"strings" -) - -// SanitizePath adapts filepath.Clean for FUSE paths. -// 1) Leading slash(es) are dropped -// 2) It returns "" instead of "." -// 3) If the cleaned path points above CWD (start with ".."), an empty string -//    is returned -// See the TestSanitizePath testcases for examples. -func SanitizePath(path string) string { -	// (1) -	for len(path) > 0 && path[0] == '/' { -		path = path[1:] -	} -	if len(path) == 0 { -		return "" -	} -	clean := filepath.Clean(path) -	// (2) -	if clean == "." { -		return "" -	} -	// (3) -	if clean == ".." || strings.HasPrefix(clean, "../") { -		return "" -	} -	return clean -} diff --git a/internal/ctlsock/sanitize_test.go b/internal/ctlsock/sanitize_test.go deleted file mode 100644 index d79fa7c..0000000 --- a/internal/ctlsock/sanitize_test.go +++ /dev/null @@ -1,30 +0,0 @@ -package ctlsock - -import ( -	"testing" -) - -func TestSanitizePath(t *testing.T) { -	testCases := [][]string{ -		{"", ""}, -		{".", ""}, -		{"/", ""}, -		{"foo", "foo"}, -		{"/foo", "foo"}, -		{"foo/", "foo"}, -		{"/foo/", "foo"}, -		{"/foo/./foo", "foo/foo"}, -		{"./", ""}, -		{"..", ""}, -		{"foo/../..", ""}, -		{"foo/../../aaaaaa", ""}, -		{"/foo/../../aaaaaa", ""}, -		{"/////", ""}, -	} -	for _, tc := range testCases { -		res := SanitizePath(tc[0]) -		if res != tc[1] { -			t.Errorf("%q: got %q, want %q", tc[0], res, tc[1]) -		} -	} -} | 
