reverse: make gocryptfs.conf mapping plaintextnames-aware
Only in plaintextnames-mode AND with the config file at the default location it will be mapped into the mountpoint. Also adds a test for that.
This commit is contained in:
parent
dde4a66454
commit
f054353bd3
@ -20,6 +20,9 @@ type argContainer struct {
|
|||||||
// Configuration file name override
|
// Configuration file name override
|
||||||
config string
|
config string
|
||||||
notifypid, scryptn int
|
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
|
var flagSet *flag.FlagSet
|
||||||
|
@ -14,4 +14,8 @@ type Args struct {
|
|||||||
// Should we chown a file after it has been created?
|
// 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.
|
// This only makes sense if (1) allow_other is set and (2) we run as root.
|
||||||
PreserveOwner bool
|
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
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ import (
|
|||||||
"github.com/rfjakob/gocryptfs/internal/cryptocore"
|
"github.com/rfjakob/gocryptfs/internal/cryptocore"
|
||||||
"github.com/rfjakob/gocryptfs/internal/fusefrontend"
|
"github.com/rfjakob/gocryptfs/internal/fusefrontend"
|
||||||
"github.com/rfjakob/gocryptfs/internal/nametransform"
|
"github.com/rfjakob/gocryptfs/internal/nametransform"
|
||||||
|
"github.com/rfjakob/gocryptfs/internal/tlog"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
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
|
// 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
|
return filepath.Base(relPath) == nametransform.DirIVFilename
|
||||||
}
|
}
|
||||||
|
|
||||||
// isNameFile determines if the path points to a gocryptfs.longname.*.name
|
// isNameFile determines if the path points to a gocryptfs.longname.*.name
|
||||||
// file
|
// 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))
|
fileType := nametransform.NameType(filepath.Base(relPath))
|
||||||
return fileType == nametransform.LongNameFilename
|
return fileType == nametransform.LongNameFilename
|
||||||
}
|
}
|
||||||
@ -161,19 +168,15 @@ func (rfs *reverseFS) GetAttr(relPath string, context *fuse.Context) (*fuse.Attr
|
|||||||
if relPath == configfile.ConfDefaultName {
|
if relPath == configfile.ConfDefaultName {
|
||||||
return rfs.inoAwareStat(configfile.ConfReverseName)
|
return rfs.inoAwareStat(configfile.ConfReverseName)
|
||||||
}
|
}
|
||||||
if rfs.isFiltered(relPath) {
|
|
||||||
return nil, fuse.EPERM
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle virtual files
|
// Handle virtual files
|
||||||
var f nodefs.File
|
var f nodefs.File
|
||||||
var status fuse.Status
|
var status fuse.Status
|
||||||
virtual := false
|
virtual := false
|
||||||
if isDirIV(relPath) {
|
if rfs.isDirIV(relPath) {
|
||||||
virtual = true
|
virtual = true
|
||||||
f, status = rfs.newDirIVFile(relPath)
|
f, status = rfs.newDirIVFile(relPath)
|
||||||
}
|
}
|
||||||
if isNameFile(relPath) {
|
if rfs.isNameFile(relPath) {
|
||||||
virtual = true
|
virtual = true
|
||||||
f, status = rfs.newNameFile(relPath)
|
f, status = rfs.newNameFile(relPath)
|
||||||
}
|
}
|
||||||
@ -204,7 +207,7 @@ func (rfs *reverseFS) GetAttr(relPath string, context *fuse.Context) (*fuse.Attr
|
|||||||
|
|
||||||
// Access - FUSE call
|
// Access - FUSE call
|
||||||
func (rfs *reverseFS) Access(relPath string, mode uint32, context *fuse.Context) fuse.Status {
|
func (rfs *reverseFS) Access(relPath string, mode uint32, context *fuse.Context) fuse.Status {
|
||||||
if isDirIV(relPath) {
|
if rfs.isDirIV(relPath) {
|
||||||
return fuse.OK
|
return fuse.OK
|
||||||
}
|
}
|
||||||
if rfs.isFiltered(relPath) {
|
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
|
// gocryptfs.conf maps to .gocryptfs.reverse.conf in the plaintext directory
|
||||||
return rfs.loopbackfs.Open(configfile.ConfReverseName, flags, context)
|
return rfs.loopbackfs.Open(configfile.ConfReverseName, flags, context)
|
||||||
}
|
}
|
||||||
if isDirIV(relPath) {
|
if rfs.isDirIV(relPath) {
|
||||||
return rfs.newDirIVFile(relPath)
|
return rfs.newDirIVFile(relPath)
|
||||||
}
|
}
|
||||||
if isNameFile(relPath) {
|
if rfs.isNameFile(relPath) {
|
||||||
return rfs.newNameFile(relPath)
|
return rfs.newNameFile(relPath)
|
||||||
}
|
}
|
||||||
if rfs.isFiltered(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)
|
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
|
// OpenDir - FUSE readdir call
|
||||||
func (rfs *reverseFS) OpenDir(cipherPath string, context *fuse.Context) ([]fuse.DirEntry, fuse.Status) {
|
func (rfs *reverseFS) OpenDir(cipherPath string, context *fuse.Context) ([]fuse.DirEntry, fuse.Status) {
|
||||||
relPath, err := rfs.decryptPath(cipherPath)
|
relPath, err := rfs.decryptPath(cipherPath)
|
||||||
@ -246,6 +274,9 @@ func (rfs *reverseFS) OpenDir(cipherPath string, context *fuse.Context) ([]fuse.
|
|||||||
if entries == nil {
|
if entries == nil {
|
||||||
return nil, status
|
return nil, status
|
||||||
}
|
}
|
||||||
|
if rfs.args.PlaintextNames {
|
||||||
|
return rfs.openDirPlaintextnames(cipherPath, entries)
|
||||||
|
}
|
||||||
// Allocate maximum possible number of virtual files.
|
// Allocate maximum possible number of virtual files.
|
||||||
// If all files have long names we need a virtual ".name" file for each,
|
// If all files have long names we need a virtual ".name" file for each,
|
||||||
// plus one for gocryptfs.diriv.
|
// plus one for gocryptfs.diriv.
|
||||||
|
1
main.go
1
main.go
@ -155,6 +155,7 @@ func main() {
|
|||||||
os.Exit(ErrExitInit)
|
os.Exit(ErrExitInit)
|
||||||
}
|
}
|
||||||
tlog.Info.Printf("Using config file at custom location %s", args.config)
|
tlog.Info.Printf("Using config file at custom location %s", args.config)
|
||||||
|
args._configCustom = true
|
||||||
} else if args.reverse {
|
} else if args.reverse {
|
||||||
args.config = filepath.Join(args.cipherdir, configfile.ConfReverseName)
|
args.config = filepath.Join(args.cipherdir, configfile.ConfReverseName)
|
||||||
} else {
|
} else {
|
||||||
|
1
mount.go
1
mount.go
@ -125,6 +125,7 @@ func initFuseFrontend(key []byte, args *argContainer, confFile *configfile.ConfF
|
|||||||
PlaintextNames: args.plaintextnames,
|
PlaintextNames: args.plaintextnames,
|
||||||
LongNames: args.longnames,
|
LongNames: args.longnames,
|
||||||
CryptoBackend: cryptoBackend,
|
CryptoBackend: cryptoBackend,
|
||||||
|
ConfigCustom: args._configCustom,
|
||||||
}
|
}
|
||||||
// confFile is nil when "-zerokey" or "-masterkey" was used
|
// confFile is nil when "-zerokey" or "-masterkey" was used
|
||||||
if confFile != nil {
|
if confFile != nil {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package reverse_test
|
package reverse_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
//"time"
|
//"time"
|
||||||
@ -49,3 +50,17 @@ func TestSymlinks(t *testing.T) {
|
|||||||
t.Errorf("wrong symlink target: want=%q have=%q", target, actualTarget)
|
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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -10,26 +10,38 @@ import (
|
|||||||
|
|
||||||
var dirA, dirB, dirC string
|
var dirA, dirB, dirC string
|
||||||
var x240 string
|
var x240 string
|
||||||
|
var plaintextnames bool
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
x240 = string(bytes.Repeat([]byte("x"), 240))
|
x240 = string(bytes.Repeat([]byte("x"), 240))
|
||||||
dirA = test_helpers.TmpDir + "/a"
|
var r int
|
||||||
dirB = test_helpers.TmpDir + "/b"
|
for _, plaintextnames = range []bool{false, true} {
|
||||||
dirC = test_helpers.TmpDir + "/c"
|
argsA := []string{"-reverse"}
|
||||||
if err := os.Mkdir(dirA, 0700); err != nil {
|
if plaintextnames {
|
||||||
panic(err)
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
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, "-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)
|
os.Exit(r)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user