reverse: add symlink encryption and Readlink support
This commit is contained in:
parent
12808138ef
commit
b883dd10a6
|
@ -1,6 +1,7 @@
|
||||||
package fusefrontend_reverse
|
package fusefrontend_reverse
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -275,3 +276,23 @@ func (rfs *reverseFS) OpenDir(cipherPath string, context *fuse.Context) ([]fuse.
|
||||||
func (rfs *reverseFS) StatFs(name string) *fuse.StatfsOut {
|
func (rfs *reverseFS) StatFs(name string) *fuse.StatfsOut {
|
||||||
return rfs.loopbackfs.StatFs(name)
|
return rfs.loopbackfs.StatFs(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Readlink - FUSE call
|
||||||
|
func (rfs *reverseFS) Readlink(cipherPath string, context *fuse.Context) (string, fuse.Status) {
|
||||||
|
absPath, err := rfs.abs(rfs.decryptPath(cipherPath))
|
||||||
|
if err != nil {
|
||||||
|
return "", fuse.ToStatus(err)
|
||||||
|
}
|
||||||
|
plainTarget, err := os.Readlink(absPath)
|
||||||
|
if err != nil {
|
||||||
|
return "", fuse.ToStatus(err)
|
||||||
|
}
|
||||||
|
if rfs.args.PlaintextNames {
|
||||||
|
return plainTarget, fuse.OK
|
||||||
|
}
|
||||||
|
nonce := derivePathIV(cipherPath)
|
||||||
|
// Symlinks are encrypted like file contents and base64-encoded
|
||||||
|
cBinTarget := rfs.contentEnc.EncryptBlock([]byte(plainTarget), 0, nil, contentenc.ExternalNonce, nonce)
|
||||||
|
cTarget := base64.URLEncoding.EncodeToString(cBinTarget)
|
||||||
|
return cTarget, fuse.OK
|
||||||
|
}
|
||||||
|
|
|
@ -47,6 +47,12 @@ func (rfs *reverseFS) decryptPath(relPath string) (string, error) {
|
||||||
if _, ok := err.(base64.CorruptInputError); ok {
|
if _, ok := err.(base64.CorruptInputError); ok {
|
||||||
return "", syscall.ENOENT
|
return "", syscall.ENOENT
|
||||||
}
|
}
|
||||||
|
// Stat attempts on the link target of encrypted symlinks.
|
||||||
|
// These are always valid base64 but the length is not a
|
||||||
|
// multiple of 16.
|
||||||
|
if err == syscall.EINVAL {
|
||||||
|
return "", syscall.ENOENT
|
||||||
|
}
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
} else if nameType == nametransform.LongNameContent {
|
} else if nameType == nametransform.LongNameContent {
|
||||||
|
|
|
@ -4,7 +4,6 @@ package nametransform
|
||||||
import (
|
import (
|
||||||
"crypto/aes"
|
"crypto/aes"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"fmt"
|
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/rfjakob/eme"
|
"github.com/rfjakob/eme"
|
||||||
|
@ -38,7 +37,8 @@ func (n *NameTransform) DecryptName(cipherName string, iv []byte) (string, error
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
if len(bin)%aes.BlockSize != 0 {
|
if len(bin)%aes.BlockSize != 0 {
|
||||||
return "", fmt.Errorf("Decoded length %d is not a multiple of the AES block size", len(bin))
|
tlog.Warn.Printf("DecryptName %q: decoded length %d is not a multiple of 16", cipherName, len(bin))
|
||||||
|
return "", syscall.EINVAL
|
||||||
}
|
}
|
||||||
bin = eme.Transform(n.cryptoCore.BlockCipher, iv, bin, eme.DirectionDecrypt)
|
bin = eme.Transform(n.cryptoCore.BlockCipher, iv, bin, eme.DirectionDecrypt)
|
||||||
bin, err = unPad16(bin)
|
bin, err = unPad16(bin)
|
||||||
|
|
|
@ -28,3 +28,24 @@ func TestLongnameStat(t *testing.T) {
|
||||||
test_helpers.VerifySize(t, path, 10)
|
test_helpers.VerifySize(t, path, 10)
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSymlinks(t *testing.T) {
|
||||||
|
target := "/"
|
||||||
|
os.Symlink(target, dirA+"/symlink")
|
||||||
|
cSymlink := dirC + "/symlink"
|
||||||
|
_, err := os.Lstat(cSymlink)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Lstat: %v", err)
|
||||||
|
}
|
||||||
|
_, err = os.Stat(cSymlink)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Stat: %v", err)
|
||||||
|
}
|
||||||
|
actualTarget, err := os.Readlink(cSymlink)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if target != actualTarget {
|
||||||
|
t.Errorf("wrong symlink target: want=%q have=%q", target, actualTarget)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue