diriv: also support old CBC symlink
This commit is contained in:
parent
01141f8b5e
commit
1fb349e97b
30
main.go
30
main.go
|
@ -245,6 +245,7 @@ func main() {
|
||||||
}
|
}
|
||||||
// Get master key
|
// Get master key
|
||||||
var masterkey []byte
|
var masterkey []byte
|
||||||
|
var confFile *cryptfs.ConfFile
|
||||||
if args.masterkey != "" {
|
if args.masterkey != "" {
|
||||||
// "-masterkey"
|
// "-masterkey"
|
||||||
cryptfs.Info.Printf("Using explicit master key.\n")
|
cryptfs.Info.Printf("Using explicit master key.\n")
|
||||||
|
@ -257,15 +258,12 @@ func main() {
|
||||||
masterkey = make([]byte, cryptfs.KEY_LEN)
|
masterkey = make([]byte, cryptfs.KEY_LEN)
|
||||||
} else {
|
} else {
|
||||||
// Load master key from config file
|
// Load master key from config file
|
||||||
var confFile *cryptfs.ConfFile
|
|
||||||
masterkey, confFile = loadConfig(&args)
|
masterkey, confFile = loadConfig(&args)
|
||||||
printMasterKey(masterkey)
|
printMasterKey(masterkey)
|
||||||
// Settings from the config file override command line args
|
|
||||||
args.plaintextnames = confFile.IsFeatureFlagSet(cryptfs.FlagPlaintextNames)
|
|
||||||
args.diriv = confFile.IsFeatureFlagSet(cryptfs.FlagDirIV)
|
|
||||||
}
|
}
|
||||||
// Initialize FUSE server
|
// Initialize FUSE server
|
||||||
srv := pathfsFrontend(masterkey, args)
|
cryptfs.Debug.Printf("args: %v\n", args)
|
||||||
|
srv := pathfsFrontend(masterkey, args, confFile)
|
||||||
cryptfs.Info.Println("Filesystem ready.")
|
cryptfs.Info.Println("Filesystem ready.")
|
||||||
// We are ready - send USR1 signal to our parent
|
// We are ready - send USR1 signal to our parent
|
||||||
if args.notifypid > 0 {
|
if args.notifypid > 0 {
|
||||||
|
@ -279,11 +277,27 @@ func main() {
|
||||||
// main exits with code 0
|
// main exits with code 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// pathfsFrontend - initialize FUSE server based on go-fuse's PathFS.
|
// pathfsFrontend - initialize gocryptfs/pathfs_frontend
|
||||||
// Calls os.Exit on errors
|
// Calls os.Exit on errors
|
||||||
func pathfsFrontend(key []byte, args argContainer) *fuse.Server {
|
func pathfsFrontend(key []byte, args argContainer, confFile *cryptfs.ConfFile) *fuse.Server {
|
||||||
|
|
||||||
finalFs := pathfs_frontend.NewFS(key, args.cipherdir, args.openssl, args.plaintextnames, args.diriv)
|
// Reconciliate CLI and config file arguments into a Args struct that is passed to the
|
||||||
|
// filesystem implementation
|
||||||
|
frontendArgs := pathfs_frontend.Args{
|
||||||
|
Cipherdir: args.cipherdir,
|
||||||
|
Masterkey: key,
|
||||||
|
OpenSSL: args.openssl,
|
||||||
|
PlaintextNames: args.plaintextnames,
|
||||||
|
DirIV: args.diriv,
|
||||||
|
}
|
||||||
|
// confFile is nil when "-zerokey" or "-masterkey" was used
|
||||||
|
if confFile != nil {
|
||||||
|
// Settings from the config file override command line args
|
||||||
|
frontendArgs.PlaintextNames = confFile.IsFeatureFlagSet(cryptfs.FlagPlaintextNames)
|
||||||
|
frontendArgs.DirIV = confFile.IsFeatureFlagSet(cryptfs.FlagDirIV)
|
||||||
|
}
|
||||||
|
|
||||||
|
finalFs := pathfs_frontend.NewFS(frontendArgs)
|
||||||
pathFsOpts := &pathfs.PathNodeFsOptions{ClientInodes: true}
|
pathFsOpts := &pathfs.PathNodeFsOptions{ClientInodes: true}
|
||||||
pathFs := pathfs.NewPathNodeFs(finalFs, pathFsOpts)
|
pathFs := pathfs.NewPathNodeFs(finalFs, pathFsOpts)
|
||||||
fuseOpts := &nodefs.Options{
|
fuseOpts := &nodefs.Options{
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
package pathfs_frontend
|
||||||
|
|
||||||
|
// Container for arguments that are passed from main() to pathfs_frontend
|
||||||
|
type Args struct {
|
||||||
|
Masterkey []byte
|
||||||
|
Cipherdir string
|
||||||
|
OpenSSL bool
|
||||||
|
PlaintextNames bool
|
||||||
|
DirIV bool
|
||||||
|
}
|
|
@ -18,9 +18,7 @@ import (
|
||||||
type FS struct {
|
type FS struct {
|
||||||
*cryptfs.CryptFS
|
*cryptfs.CryptFS
|
||||||
pathfs.FileSystem // loopbackFileSystem, see go-fuse/fuse/pathfs/loopback.go
|
pathfs.FileSystem // loopbackFileSystem, see go-fuse/fuse/pathfs/loopback.go
|
||||||
backingDir string // Backing directory, cipherdir
|
args Args // Stores configuration arguments
|
||||||
// Are per-directory filename IVs enabled?
|
|
||||||
dirIV bool
|
|
||||||
// dirIVLock: Lock()ed if any "gocryptfs.diriv" file is modified
|
// dirIVLock: Lock()ed if any "gocryptfs.diriv" file is modified
|
||||||
// Readers must RLock() it to prevent them from seeing intermediate
|
// Readers must RLock() it to prevent them from seeing intermediate
|
||||||
// states
|
// states
|
||||||
|
@ -28,23 +26,24 @@ type FS struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encrypted FUSE overlay filesystem
|
// Encrypted FUSE overlay filesystem
|
||||||
func NewFS(key []byte, backing string, useOpenssl bool, plaintextNames bool, dirIV bool) *FS {
|
func NewFS(args Args) *FS {
|
||||||
return &FS{
|
return &FS{
|
||||||
CryptFS: cryptfs.NewCryptFS(key, useOpenssl, plaintextNames),
|
CryptFS: cryptfs.NewCryptFS(args.Masterkey, args.OpenSSL, args.PlaintextNames),
|
||||||
FileSystem: pathfs.NewLoopbackFileSystem(backing),
|
FileSystem: pathfs.NewLoopbackFileSystem(args.Cipherdir),
|
||||||
dirIV: dirIV,
|
args: args,
|
||||||
backingDir: backing,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBackingPath - get the absolute encrypted path of the backing file
|
// GetBackingPath - get the absolute encrypted path of the backing file
|
||||||
// from the relative plaintext path "relPath"
|
// from the relative plaintext path "relPath"
|
||||||
func (fs *FS) getBackingPath(relPath string) (string, error) {
|
func (fs *FS) getBackingPath(relPath string) (string, error) {
|
||||||
encrypted, err := fs.encryptPath(relPath)
|
cPath, err := fs.encryptPath(relPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return filepath.Join(fs.backingDir, encrypted), nil
|
cAbsPath := filepath.Join(fs.args.Cipherdir, cPath)
|
||||||
|
cryptfs.Debug.Printf("getBackingPath: %s + %s -> %s\n", fs.args.Cipherdir, relPath, cAbsPath)
|
||||||
|
return cAbsPath, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *FS) GetAttr(name string, context *fuse.Context) (*fuse.Attr, fuse.Status) {
|
func (fs *FS) GetAttr(name string, context *fuse.Context) (*fuse.Attr, fuse.Status) {
|
||||||
|
@ -85,12 +84,12 @@ func (fs *FS) OpenDir(dirName string, context *fuse.Context) ([]fuse.DirEntry, f
|
||||||
// silently ignore "gocryptfs.conf" in the top level dir
|
// silently ignore "gocryptfs.conf" in the top level dir
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if fs.dirIV && cName == cryptfs.DIRIV_FILENAME {
|
if fs.args.DirIV && cName == cryptfs.DIRIV_FILENAME {
|
||||||
// silently ignore "gocryptfs.diriv" everywhere if dirIV is enabled
|
// silently ignore "gocryptfs.diriv" everywhere if dirIV is enabled
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
var name string
|
var name string
|
||||||
if !fs.dirIV {
|
if !fs.args.DirIV {
|
||||||
name, err = fs.decryptPath(cName)
|
name, err = fs.decryptPath(cName)
|
||||||
} else {
|
} else {
|
||||||
// When dirIV is enabled we need the full path to be able to decrypt it
|
// When dirIV is enabled we need the full path to be able to decrypt it
|
||||||
|
@ -123,15 +122,16 @@ func (fs *FS) mangleOpenFlags(flags uint32) (newFlags int, writeOnly bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *FS) Open(path string, flags uint32, context *fuse.Context) (fuseFile nodefs.File, status fuse.Status) {
|
func (fs *FS) Open(path string, flags uint32, context *fuse.Context) (fuseFile nodefs.File, status fuse.Status) {
|
||||||
cryptfs.Debug.Printf("Open(%s)\n", path)
|
|
||||||
if fs.CryptFS.IsFiltered(path) {
|
if fs.CryptFS.IsFiltered(path) {
|
||||||
return nil, fuse.EPERM
|
return nil, fuse.EPERM
|
||||||
}
|
}
|
||||||
iflags, writeOnly := fs.mangleOpenFlags(flags)
|
iflags, writeOnly := fs.mangleOpenFlags(flags)
|
||||||
cPath, err := fs.getBackingPath(path)
|
cPath, err := fs.getBackingPath(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
cryptfs.Debug.Printf("Open: getBackingPath: %v\n", err)
|
||||||
return nil, fuse.ToStatus(err)
|
return nil, fuse.ToStatus(err)
|
||||||
}
|
}
|
||||||
|
cryptfs.Debug.Printf("Open: %s\n", cPath)
|
||||||
f, err := os.OpenFile(cPath, iflags, 0666)
|
f, err := os.OpenFile(cPath, iflags, 0666)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fuse.ToStatus(err)
|
return nil, fuse.ToStatus(err)
|
||||||
|
@ -214,6 +214,16 @@ func (fs *FS) Readlink(path string, context *fuse.Context) (out string, status f
|
||||||
if status != fuse.OK {
|
if status != fuse.OK {
|
||||||
return "", status
|
return "", status
|
||||||
}
|
}
|
||||||
|
// Old filesystem: symlinks are encrypted like paths (CBC)
|
||||||
|
if !fs.args.DirIV {
|
||||||
|
target, err := fs.decryptPath(cTarget)
|
||||||
|
if err != nil {
|
||||||
|
cryptfs.Warn.Printf("Readlink: CBC decryption failed: %v", err)
|
||||||
|
return "", fuse.EIO
|
||||||
|
}
|
||||||
|
return target, fuse.OK
|
||||||
|
}
|
||||||
|
// Since gocryptfs v0.5 symlinks are encrypted like file contents (GCM)
|
||||||
cBinTarget, err := base64.URLEncoding.DecodeString(cTarget)
|
cBinTarget, err := base64.URLEncoding.DecodeString(cTarget)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cryptfs.Warn.Printf("Readlink: %v\n", err)
|
cryptfs.Warn.Printf("Readlink: %v\n", err)
|
||||||
|
@ -335,7 +345,17 @@ func (fs *FS) Symlink(target string, linkName string, context *fuse.Context) (co
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fuse.ToStatus(err)
|
return fuse.ToStatus(err)
|
||||||
}
|
}
|
||||||
|
// Old filesystem: symlinks are encrypted like paths (CBC)
|
||||||
|
if !fs.args.DirIV {
|
||||||
|
cTarget, err := fs.encryptPath(target)
|
||||||
|
if err != nil {
|
||||||
|
cryptfs.Warn.Printf("Symlink: BUG: we should not get an error here: %v\n", err)
|
||||||
|
return fuse.ToStatus(err)
|
||||||
|
}
|
||||||
|
err = os.Symlink(cTarget, cPath)
|
||||||
|
return fuse.ToStatus(err)
|
||||||
|
}
|
||||||
|
// Since gocryptfs v0.5 symlinks are encrypted like file contents (GCM)
|
||||||
cBinTarget := fs.CryptFS.EncryptBlock([]byte(target), 0, nil)
|
cBinTarget := fs.CryptFS.EncryptBlock([]byte(target), 0, nil)
|
||||||
cTarget := base64.URLEncoding.EncodeToString(cBinTarget)
|
cTarget := base64.URLEncoding.EncodeToString(cBinTarget)
|
||||||
|
|
||||||
|
|
|
@ -7,19 +7,19 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func (fs *FS) encryptPath(plainPath string) (string, error) {
|
func (fs *FS) encryptPath(plainPath string) (string, error) {
|
||||||
if !fs.dirIV {
|
if !fs.args.DirIV {
|
||||||
return fs.CryptFS.TranslatePathZeroIV(plainPath, cryptfs.OpEncrypt)
|
return fs.CryptFS.TranslatePathZeroIV(plainPath, cryptfs.OpEncrypt)
|
||||||
}
|
}
|
||||||
fs.dirIVLock.RLock()
|
fs.dirIVLock.RLock()
|
||||||
defer fs.dirIVLock.RUnlock()
|
defer fs.dirIVLock.RUnlock()
|
||||||
return fs.CryptFS.EncryptPathDirIV(plainPath, fs.backingDir)
|
return fs.CryptFS.EncryptPathDirIV(plainPath, fs.args.Cipherdir)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *FS) decryptPath(cipherPath string) (string, error) {
|
func (fs *FS) decryptPath(cipherPath string) (string, error) {
|
||||||
if !fs.dirIV {
|
if !fs.args.DirIV {
|
||||||
return fs.CryptFS.TranslatePathZeroIV(cipherPath, cryptfs.OpDecrypt)
|
return fs.CryptFS.TranslatePathZeroIV(cipherPath, cryptfs.OpDecrypt)
|
||||||
}
|
}
|
||||||
fs.dirIVLock.RLock()
|
fs.dirIVLock.RLock()
|
||||||
defer fs.dirIVLock.RUnlock()
|
defer fs.dirIVLock.RUnlock()
|
||||||
return fs.CryptFS.DecryptPathDirIV(cipherPath, fs.backingDir)
|
return fs.CryptFS.DecryptPathDirIV(cipherPath, fs.args.Cipherdir)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue