diff options
| -rw-r--r-- | cli_args.go | 3 | ||||
| -rw-r--r-- | internal/fusefrontend/args.go | 4 | ||||
| -rw-r--r-- | internal/fusefrontend_reverse/rfs.go | 53 | ||||
| -rw-r--r-- | main.go | 1 | ||||
| -rw-r--r-- | mount.go | 1 | ||||
| -rw-r--r-- | tests/reverse/correctness_test.go | 15 | ||||
| -rw-r--r-- | tests/reverse/main_test.go | 46 | 
7 files changed, 95 insertions, 28 deletions
| diff --git a/cli_args.go b/cli_args.go index dd570d3..d80e937 100644 --- a/cli_args.go +++ b/cli_args.go @@ -20,6 +20,9 @@ type argContainer struct {  	// Configuration file name override  	config             string  	notifypid, scryptn int +	// _configCustom is true when the user sets a custom config file name. +	// This is not a CLI option. +	_configCustom bool  }  var flagSet *flag.FlagSet diff --git a/internal/fusefrontend/args.go b/internal/fusefrontend/args.go index 64ca899..204647d 100644 --- a/internal/fusefrontend/args.go +++ b/internal/fusefrontend/args.go @@ -14,4 +14,8 @@ type Args struct {  	// Should we chown a file after it has been created?  	// This only makes sense if (1) allow_other is set and (2) we run as root.  	PreserveOwner bool +	// ConfigCustom is true when the user select a non-default config file +	// location. If it is false, reverse mode maps ".gocryptfs.reverse.conf" +	// to "gocryptfs.conf" in the plaintext dir. +	ConfigCustom bool  } diff --git a/internal/fusefrontend_reverse/rfs.go b/internal/fusefrontend_reverse/rfs.go index 1c143bf..36f49be 100644 --- a/internal/fusefrontend_reverse/rfs.go +++ b/internal/fusefrontend_reverse/rfs.go @@ -17,6 +17,7 @@ import (  	"github.com/rfjakob/gocryptfs/internal/cryptocore"  	"github.com/rfjakob/gocryptfs/internal/fusefrontend"  	"github.com/rfjakob/gocryptfs/internal/nametransform" +	"github.com/rfjakob/gocryptfs/internal/tlog"  )  const ( @@ -110,13 +111,19 @@ func (rfs *reverseFS) dirIVAttr(relPath string, context *fuse.Context) (*fuse.At  }  // isDirIV determines if the path points to a gocryptfs.diriv file -func isDirIV(relPath string) bool { +func (rfs *reverseFS) isDirIV(relPath string) bool { +	if rfs.args.PlaintextNames { +		return false +	}  	return filepath.Base(relPath) == nametransform.DirIVFilename  }  // isNameFile determines if the path points to a gocryptfs.longname.*.name  // file -func isNameFile(relPath string) bool { +func (rfs *reverseFS) isNameFile(relPath string) bool { +	if rfs.args.PlaintextNames { +		return false +	}  	fileType := nametransform.NameType(filepath.Base(relPath))  	return fileType == nametransform.LongNameFilename  } @@ -161,19 +168,15 @@ func (rfs *reverseFS) GetAttr(relPath string, context *fuse.Context) (*fuse.Attr  	if relPath == configfile.ConfDefaultName {  		return rfs.inoAwareStat(configfile.ConfReverseName)  	} -	if rfs.isFiltered(relPath) { -		return nil, fuse.EPERM -	} -  	// Handle virtual files  	var f nodefs.File  	var status fuse.Status  	virtual := false -	if isDirIV(relPath) { +	if rfs.isDirIV(relPath) {  		virtual = true  		f, status = rfs.newDirIVFile(relPath)  	} -	if isNameFile(relPath) { +	if rfs.isNameFile(relPath) {  		virtual = true  		f, status = rfs.newNameFile(relPath)  	} @@ -204,7 +207,7 @@ func (rfs *reverseFS) GetAttr(relPath string, context *fuse.Context) (*fuse.Attr  // Access - FUSE call  func (rfs *reverseFS) Access(relPath string, mode uint32, context *fuse.Context) fuse.Status { -	if isDirIV(relPath) { +	if rfs.isDirIV(relPath) {  		return fuse.OK  	}  	if rfs.isFiltered(relPath) { @@ -223,10 +226,10 @@ func (rfs *reverseFS) Open(relPath string, flags uint32, context *fuse.Context)  		// gocryptfs.conf maps to .gocryptfs.reverse.conf in the plaintext directory  		return rfs.loopbackfs.Open(configfile.ConfReverseName, flags, context)  	} -	if isDirIV(relPath) { +	if rfs.isDirIV(relPath) {  		return rfs.newDirIVFile(relPath)  	} -	if isNameFile(relPath) { +	if rfs.isNameFile(relPath) {  		return rfs.newNameFile(relPath)  	}  	if rfs.isFiltered(relPath) { @@ -235,6 +238,31 @@ func (rfs *reverseFS) Open(relPath string, flags uint32, context *fuse.Context)  	return rfs.NewFile(relPath, flags)  } +func (rfs *reverseFS) openDirPlaintextnames(relPath string, entries []fuse.DirEntry) ([]fuse.DirEntry, fuse.Status) { +	if relPath != "" || rfs.args.ConfigCustom { +		return entries, fuse.OK +	} +	// We are in the root dir and the default config file name +	// ".gocryptfs.reverse.conf" is used. We map it to "gocryptfs.conf". +	dupe := -1 +	status := fuse.OK +	for i := range entries { +		if entries[i].Name == configfile.ConfReverseName { +			entries[i].Name = configfile.ConfDefaultName +		} else if entries[i].Name == configfile.ConfDefaultName { +			dupe = i +		} +	} +	if dupe >= 0 { +		// Warn the user loudly: The gocryptfs.conf_NAME_COLLISION file will +		// throw ENOENT errors that are hard to miss. +		tlog.Warn.Printf("The file %s is mapped to %s and shadows another file. Please rename %s in %s .", +			configfile.ConfReverseName, configfile.ConfDefaultName, configfile.ConfDefaultName, rfs.args.Cipherdir) +		entries[dupe].Name = "gocryptfs.conf_NAME_COLLISION_" + fmt.Sprintf("%d", cryptocore.RandUint64()) +	} +	return entries, status +} +  // OpenDir - FUSE readdir call  func (rfs *reverseFS) OpenDir(cipherPath string, context *fuse.Context) ([]fuse.DirEntry, fuse.Status) {  	relPath, err := rfs.decryptPath(cipherPath) @@ -246,6 +274,9 @@ func (rfs *reverseFS) OpenDir(cipherPath string, context *fuse.Context) ([]fuse.  	if entries == nil {  		return nil, status  	} +	if rfs.args.PlaintextNames { +		return rfs.openDirPlaintextnames(cipherPath, entries) +	}  	// Allocate maximum possible number of virtual files.  	// If all files have long names we need a virtual ".name" file for each,  	// plus one for gocryptfs.diriv. @@ -155,6 +155,7 @@ func main() {  			os.Exit(ErrExitInit)  		}  		tlog.Info.Printf("Using config file at custom location %s", args.config) +		args._configCustom = true  	} else if args.reverse {  		args.config = filepath.Join(args.cipherdir, configfile.ConfReverseName)  	} else { @@ -125,6 +125,7 @@ func initFuseFrontend(key []byte, args *argContainer, confFile *configfile.ConfF  		PlaintextNames: args.plaintextnames,  		LongNames:      args.longnames,  		CryptoBackend:  cryptoBackend, +		ConfigCustom:   args._configCustom,  	}  	// confFile is nil when "-zerokey" or "-masterkey" was used  	if confFile != nil { diff --git a/tests/reverse/correctness_test.go b/tests/reverse/correctness_test.go index 40bd320..c75a1fd 100644 --- a/tests/reverse/correctness_test.go +++ b/tests/reverse/correctness_test.go @@ -1,6 +1,7 @@  package reverse_test  import ( +	"io/ioutil"  	"os"  	"testing"  	//"time" @@ -49,3 +50,17 @@ func TestSymlinks(t *testing.T) {  		t.Errorf("wrong symlink target: want=%q have=%q", target, actualTarget)  	}  } + +// .gocryptfs.reverse.conf in the plaintext dir should be visible as +// gocryptfs.conf +func TestConfigMapping(t *testing.T) { +	c := dirB + "/gocryptfs.conf" +	test_helpers.VerifyExistence(c) +	data, err := ioutil.ReadFile(c) +	if err != nil { +		t.Fatal(err) +	} +	if len(data) == 0 { +		t.Errorf("empty file") +	} +} diff --git a/tests/reverse/main_test.go b/tests/reverse/main_test.go index a42bb82..a2b7eb6 100644 --- a/tests/reverse/main_test.go +++ b/tests/reverse/main_test.go @@ -10,26 +10,38 @@ import (  var dirA, dirB, dirC string  var x240 string +var plaintextnames bool  func TestMain(m *testing.M) {  	x240 = string(bytes.Repeat([]byte("x"), 240)) -	dirA = test_helpers.TmpDir + "/a" -	dirB = test_helpers.TmpDir + "/b" -	dirC = test_helpers.TmpDir + "/c" -	if err := os.Mkdir(dirA, 0700); err != nil { -		panic(err) -	} -	if err := os.Mkdir(dirB, 0700); err != nil { -		panic(err) -	} -	if err := os.Mkdir(dirC, 0700); err != nil { -		panic(err) +	var r int +	for _, plaintextnames = range []bool{false, true} { +		argsA := []string{"-reverse"} +		if plaintextnames { +			argsA = append(argsA, "-plaintextnames") +		} +		dirA = test_helpers.InitFS(nil, argsA...) +		dirB = test_helpers.TmpDir + "/b" +		dirC = test_helpers.TmpDir + "/c" +		if err := os.Mkdir(dirB, 0700); err != nil { +			panic(err) +		} +		if err := os.Mkdir(dirC, 0700); err != nil { +			panic(err) +		} +		test_helpers.MountOrExit(dirA, dirB, "-reverse", "-extpass", "echo test") +		test_helpers.MountOrExit(dirB, dirC, "-extpass", "echo test") +		r = m.Run() +		test_helpers.UnmountPanic(dirC) +		test_helpers.UnmountPanic(dirB) + +		os.RemoveAll(dirA) +		os.RemoveAll(dirB) +		os.RemoveAll(dirC) + +		if r != 0 { +			os.Exit(r) +		}  	} -	test_helpers.MountOrExit(dirA, dirB, "-zerokey", "-reverse") -	test_helpers.MountOrExit(dirB, dirC, "-zerokey", "-aessiv") -	r := m.Run() -	test_helpers.UnmountPanic(dirC) -	test_helpers.UnmountPanic(dirB) -	os.RemoveAll(test_helpers.TmpDir)  	os.Exit(r)  } | 
