diff options
Diffstat (limited to 'internal')
| -rw-r--r-- | internal/fusefrontend/node_helpers.go | 10 | ||||
| -rw-r--r-- | internal/fusefrontend/root_node.go | 6 | ||||
| -rw-r--r-- | internal/nametransform/diriv.go | 50 | ||||
| -rw-r--r-- | internal/nametransform/names.go | 13 | 
4 files changed, 75 insertions, 4 deletions
| diff --git a/internal/fusefrontend/node_helpers.go b/internal/fusefrontend/node_helpers.go index b2f1d4a..f2d1e5e 100644 --- a/internal/fusefrontend/node_helpers.go +++ b/internal/fusefrontend/node_helpers.go @@ -121,7 +121,15 @@ func (n *Node) prepareAtSyscall(child string) (dirfd int, cName string, errno sy  		var iv []byte  		dirfd, iv = rn.dirCache.Lookup(n)  		if dirfd > 0 { -			cName, err := rn.nameTransform.EncryptAndHashName(child, iv) +			var cName string +			var err error +			if rn.nameTransform.HaveBadnamePatterns() { +				//BadName allowed, try to determine filenames +				cName, err = rn.nameTransform.EncryptAndHashBadName(child, iv, dirfd) +			} else { +				cName, err = rn.nameTransform.EncryptAndHashName(child, iv) +			} +  			if err != nil {  				return -1, "", fs.ToErrno(err)  			} diff --git a/internal/fusefrontend/root_node.go b/internal/fusefrontend/root_node.go index a830cc4..35b7be0 100644 --- a/internal/fusefrontend/root_node.go +++ b/internal/fusefrontend/root_node.go @@ -245,7 +245,11 @@ func (rn *RootNode) openBackingDir(relPath string) (dirfd int, cName string, err  			syscall.Close(dirfd)  			return -1, "", err  		} -		cName, err = rn.nameTransform.EncryptAndHashName(name, iv) +		if rn.nameTransform.HaveBadnamePatterns() { +			cName, err = rn.nameTransform.EncryptAndHashBadName(name, iv, dirfd) +		} else { +			cName, err = rn.nameTransform.EncryptAndHashName(name, iv) +		}  		if err != nil {  			syscall.Close(dirfd)  			return -1, "", err diff --git a/internal/nametransform/diriv.go b/internal/nametransform/diriv.go index 1d27aa5..d62b3fb 100644 --- a/internal/nametransform/diriv.go +++ b/internal/nametransform/diriv.go @@ -6,11 +6,13 @@ import (  	"io"  	"os"  	"path/filepath" +	"strings"  	"syscall"  	"github.com/rfjakob/gocryptfs/internal/cryptocore"  	"github.com/rfjakob/gocryptfs/internal/syscallcompat"  	"github.com/rfjakob/gocryptfs/internal/tlog" +	"golang.org/x/sys/unix"  )  const ( @@ -112,6 +114,54 @@ func (be *NameTransform) EncryptAndHashName(name string, iv []byte) (string, err  	return cName, nil  } +// EncryptAndHashBadName tries to find the "name" substring, which (encrypted and hashed) +// leads to an unique existing file +// Returns ENOENT if cipher file does not exist or is not unique +func (be *NameTransform) EncryptAndHashBadName(name string, iv []byte, dirfd int) (cName string, err error) { +	var st unix.Stat_t +	var filesFound int +	lastFoundName, err := be.EncryptAndHashName(name, iv) +	if !strings.HasSuffix(name, BadNameFlag) || err != nil { +		//Default mode: same behaviour on error or no BadNameFlag on "name" +		return lastFoundName, err +	} +	//Default mode: Check if File extists without modifications +	err = syscallcompat.Fstatat(dirfd, lastFoundName, &st, unix.AT_SYMLINK_NOFOLLOW) +	if err == nil { +		//file found, return result +		return lastFoundName, nil +	} +	//BadName Mode: check if the name was tranformed without change (badname suffix and undecryptable cipher name) +	err = syscallcompat.Fstatat(dirfd, name[:len(name)-len(BadNameFlag)], &st, unix.AT_SYMLINK_NOFOLLOW) +	if err == nil { +		filesFound++ +		lastFoundName = name[:len(name)-len(BadNameFlag)] +	} +	// search for the longest badname pattern match +	for charpos := len(name) - len(BadNameFlag); charpos > 0; charpos-- { +		//only use original cipher name and append assumed suffix (without badname flag) +		cNamePart, err := be.EncryptName(name[:charpos], iv) +		if err != nil { +			//expand suffix on error +			continue +		} +		if be.longNames && len(cName) > NameMax { +			cNamePart = be.HashLongName(cName) +		} +		cNameBadReverse := cNamePart + name[charpos:len(name)-len(BadNameFlag)] +		err = syscallcompat.Fstatat(dirfd, cNameBadReverse, &st, unix.AT_SYMLINK_NOFOLLOW) +		if err == nil { +			filesFound++ +			lastFoundName = cNameBadReverse +		} +	} +	if filesFound == 1 { +		return lastFoundName, nil +	} +	// more than 1 possible file found, ignore +	return "", syscall.ENOENT +} +  // Dir is like filepath.Dir but returns "" instead of ".".  func Dir(path string) string {  	d := filepath.Dir(path) diff --git a/internal/nametransform/names.go b/internal/nametransform/names.go index ca28230..f730184 100644 --- a/internal/nametransform/names.go +++ b/internal/nametransform/names.go @@ -15,6 +15,8 @@ import (  const (  	// Like ext4, we allow at most 255 bytes for a file name.  	NameMax = 255 +	//BadNameFlag is appended to filenames in plain mode if a ciphername is inavlid but is shown +	BadNameFlag = " GOCRYPTFS_BAD_NAME"  )  // NameTransformer is an interface used to transform filenames. @@ -22,11 +24,13 @@ type NameTransformer interface {  	DecryptName(cipherName string, iv []byte) (string, error)  	EncryptName(plainName string, iv []byte) (string, error)  	EncryptAndHashName(name string, iv []byte) (string, error) +	EncryptAndHashBadName(name string, iv []byte, dirfd int) (string, error)  	// HashLongName - take the hash of a long string "name" and return  	// "gocryptfs.longname.[sha256]"  	//  	// This function does not do any I/O.  	HashLongName(name string) string +	HaveBadnamePatterns() bool  	WriteLongNameAt(dirfd int, hashName string, plainName string) error  	B64EncodeToString(src []byte) string  	B64DecodeString(s string) ([]byte, error) @@ -70,10 +74,10 @@ func (n *NameTransform) DecryptName(cipherName string, iv []byte) (string, error  				for charpos := len(cipherName) - 1; charpos >= nameMin; charpos-- {  					res, err = n.decryptName(cipherName[:charpos], iv)  					if err == nil { -						return res + cipherName[charpos:] + " GOCRYPTFS_BAD_NAME", nil +						return res + cipherName[charpos:] + BadNameFlag, nil  					}  				} -				return cipherName + " GOCRYPTFS_BAD_NAME", nil +				return cipherName + BadNameFlag, nil  			}  		}  	} @@ -135,3 +139,8 @@ func (n *NameTransform) B64EncodeToString(src []byte) string {  func (n *NameTransform) B64DecodeString(s string) ([]byte, error) {  	return n.B64.DecodeString(s)  } + +// HaveBadnamePatterns returns true if BadName patterns were provided +func (n *NameTransform) HaveBadnamePatterns() bool { +	return len(n.BadnamePatterns) > 0 +} | 
