From 0f40afc8321746ebd0ba0131b3296dd160f84ccc Mon Sep 17 00:00:00 2001 From: Jakob Unterwurzacher Date: Sun, 5 Feb 2017 18:07:14 +0100 Subject: [PATCH] ctlsock: handle non-canonical empty paths We have to check if the input path is empty AFTER canonicalizing it, too! --- internal/ctlsock/ctlsock_serve.go | 74 ++++++++++++++++++++----------- 1 file changed, 48 insertions(+), 26 deletions(-) diff --git a/internal/ctlsock/ctlsock_serve.go b/internal/ctlsock/ctlsock_serve.go index d1c0090..d09f981 100644 --- a/internal/ctlsock/ctlsock_serve.go +++ b/internal/ctlsock/ctlsock_serve.go @@ -78,6 +78,7 @@ func (ch *ctlSockHandler) acceptLoop() { // 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 { @@ -100,11 +101,8 @@ func (ch *ctlSockHandler) handleConnection(conn *net.UnixConn) { err = json.Unmarshal(buf, &in) if err != nil { tlog.Warn.Printf("ctlsock: JSON Unmarshal error: %#v", err) - errorMsg := ResponseStruct{ - ErrNo: int32(syscall.EINVAL), - ErrText: "JSON Unmarshal error: " + err.Error(), - } - sendResponse(&errorMsg, conn) + err = errors.New("JSON Unmarshal error: " + err.Error()) + sendResponse(conn, err, "", "") continue } ch.handleRequest(&in, conn) @@ -113,40 +111,64 @@ func (ch *ctlSockHandler) handleConnection(conn *net.UnixConn) { } } +// handleRequest handles an already-unmarshaled JSON request func (ch *ctlSockHandler) handleRequest(in *RequestStruct, conn *net.UnixConn) { var err error - var out ResponseStruct - var inPath, clean string + var inPath, outPath, clean, warnText string + // You cannot perform both decryption and encryption in one request if in.DecryptPath != "" && in.EncryptPath != "" { err = errors.New("Ambigous") - } else if in.DecryptPath == "" && in.EncryptPath == "" { - err = errors.New("No operation") - } else if in.DecryptPath != "" { - inPath = in.DecryptPath - clean = SanitizePath(inPath) - out.Result, err = ch.fs.DecryptPath(clean) - } else if in.EncryptPath != "" { + 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 - clean = SanitizePath(inPath) - out.Result, err = ch.fs.EncryptPath(clean) + } 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 { - out.ErrText = err.Error() - out.ErrNo = -1 + 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 { - out.ErrNo = int32(se) + msg.ErrNo = int32(se) } } } - if inPath != clean { - out.WarnText = fmt.Sprintf("Non-canonical input path '%s' has been interpreted as '%s'.", inPath, clean) - } - 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)