Implement force_owner option to display ownership as a specific user.
This commit is contained in:
parent
fc2a5f5ab0
commit
cf1ded5236
@ -78,6 +78,17 @@ that uses built-in Go crypto.
|
|||||||
|
|
||||||
Setting this option forces the filesystem to read-only and noexec.
|
Setting this option forces the filesystem to read-only and noexec.
|
||||||
|
|
||||||
|
#### -force_owner string
|
||||||
|
If given a string of the form "uid:gid" (where both "uid" and "gid" are
|
||||||
|
substituted with positive integers), presents all files as owned by the given
|
||||||
|
uid and gid, regardless of their actual ownership. Implies "allow_other".
|
||||||
|
|
||||||
|
This is rarely desired behavior: One should *usually* run gocryptfs as the
|
||||||
|
account which owns the backing-store files, which should *usually* be one and
|
||||||
|
the same with the account intended to access the decrypted content. An example
|
||||||
|
of a case where this may be useful is a situation where content is stored on a
|
||||||
|
filesystem that doesn't properly support UNIX ownership and permissions.
|
||||||
|
|
||||||
#### -fsname string
|
#### -fsname string
|
||||||
Override the filesystem name (first column in df -T). Can also be
|
Override the filesystem name (first column in df -T). Can also be
|
||||||
passed as "-o fsname=" and is equivalent to libfuse's option of the
|
passed as "-o fsname=" and is equivalent to libfuse's option of the
|
||||||
|
@ -144,6 +144,9 @@ Changelog
|
|||||||
---------
|
---------
|
||||||
|
|
||||||
v1.4 (not yet released)
|
v1.4 (not yet released)
|
||||||
|
* Add `force_owner` option to allow files to be presented as owned by a
|
||||||
|
different user or group from the user running gocryptfs. Please see caveats
|
||||||
|
and guidance in the man page before using this functionality.
|
||||||
* Increase open file limit to 4096 ([#82](https://github.com/rfjakob/gocryptfs/issues/82)).
|
* Increase open file limit to 4096 ([#82](https://github.com/rfjakob/gocryptfs/issues/82)).
|
||||||
* Implement path decryption via ctlsock ([#84](https://github.com/rfjakob/gocryptfs/issues/84)).
|
* Implement path decryption via ctlsock ([#84](https://github.com/rfjakob/gocryptfs/issues/84)).
|
||||||
Previously, decryption was only implemented for reverse mode. Now both
|
Previously, decryption was only implemented for reverse mode. Now both
|
||||||
|
@ -13,6 +13,7 @@ import (
|
|||||||
"github.com/rfjakob/gocryptfs/internal/prefer_openssl"
|
"github.com/rfjakob/gocryptfs/internal/prefer_openssl"
|
||||||
"github.com/rfjakob/gocryptfs/internal/stupidgcm"
|
"github.com/rfjakob/gocryptfs/internal/stupidgcm"
|
||||||
"github.com/rfjakob/gocryptfs/internal/tlog"
|
"github.com/rfjakob/gocryptfs/internal/tlog"
|
||||||
|
"github.com/hanwen/go-fuse/fuse"
|
||||||
)
|
)
|
||||||
|
|
||||||
// argContainer stores the parsed CLI options and arguments
|
// argContainer stores the parsed CLI options and arguments
|
||||||
@ -22,7 +23,7 @@ type argContainer struct {
|
|||||||
longnames, allow_other, ro, reverse, aessiv, nonempty, raw64,
|
longnames, allow_other, ro, reverse, aessiv, nonempty, raw64,
|
||||||
noprealloc, speed, hkdf, serialize_reads, forcedecode, hh, info bool
|
noprealloc, speed, hkdf, serialize_reads, forcedecode, hh, info bool
|
||||||
masterkey, mountpoint, cipherdir, cpuprofile, extpass,
|
masterkey, mountpoint, cipherdir, cpuprofile, extpass,
|
||||||
memprofile, ko, passfile, ctlsock, fsname string
|
memprofile, ko, passfile, ctlsock, fsname, force_owner string
|
||||||
// Configuration file name override
|
// Configuration file name override
|
||||||
config string
|
config string
|
||||||
notifypid, scryptn int
|
notifypid, scryptn int
|
||||||
@ -31,6 +32,8 @@ type argContainer struct {
|
|||||||
_configCustom bool
|
_configCustom bool
|
||||||
// _ctlsockFd stores the control socket file descriptor (ctlsock stores the path)
|
// _ctlsockFd stores the control socket file descriptor (ctlsock stores the path)
|
||||||
_ctlsockFd net.Listener
|
_ctlsockFd net.Listener
|
||||||
|
// _forceOwner is, if non-nil, a parsed, validated Owner (as opposed to the string above)
|
||||||
|
_forceOwner *fuse.Owner
|
||||||
}
|
}
|
||||||
|
|
||||||
var flagSet *flag.FlagSet
|
var flagSet *flag.FlagSet
|
||||||
@ -136,6 +139,7 @@ func parseCliOpts() (args argContainer) {
|
|||||||
flagSet.StringVar(&args.ko, "ko", "", "Pass additional options directly to the kernel, comma-separated list")
|
flagSet.StringVar(&args.ko, "ko", "", "Pass additional options directly to the kernel, comma-separated list")
|
||||||
flagSet.StringVar(&args.ctlsock, "ctlsock", "", "Create control socket at specified path")
|
flagSet.StringVar(&args.ctlsock, "ctlsock", "", "Create control socket at specified path")
|
||||||
flagSet.StringVar(&args.fsname, "fsname", "", "Override the filesystem name")
|
flagSet.StringVar(&args.fsname, "fsname", "", "Override the filesystem name")
|
||||||
|
flagSet.StringVar(&args.force_owner, "force_owner", "", "uid:gid pair to coerce ownership")
|
||||||
flagSet.IntVar(&args.notifypid, "notifypid", 0, "Send USR1 to the specified process after "+
|
flagSet.IntVar(&args.notifypid, "notifypid", 0, "Send USR1 to the specified process after "+
|
||||||
"successful mount - used internally for daemonization")
|
"successful mount - used internally for daemonization")
|
||||||
flagSet.IntVar(&args.scryptn, "scryptn", configfile.ScryptDefaultLogN, "scrypt cost parameter logN. Possible values: 10-28. "+
|
flagSet.IntVar(&args.scryptn, "scryptn", configfile.ScryptDefaultLogN, "scrypt cost parameter logN. Possible values: 10-28. "+
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package fusefrontend
|
package fusefrontend
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/hanwen/go-fuse/fuse"
|
||||||
"github.com/rfjakob/gocryptfs/internal/cryptocore"
|
"github.com/rfjakob/gocryptfs/internal/cryptocore"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -16,6 +17,12 @@ 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
|
||||||
|
// Should we force ownership to be presented with a given user and group?
|
||||||
|
// This only makes sense if allow_other is set. In *most* cases, it also
|
||||||
|
// only makes sense with PreserveOwner set, but can also make sense without
|
||||||
|
// PreserveOwner if the underlying filesystem acting as backing store
|
||||||
|
// enforces ownership itself.
|
||||||
|
ForceOwner *fuse.Owner
|
||||||
// ConfigCustom is true when the user select a non-default config file
|
// ConfigCustom is true when the user select a non-default config file
|
||||||
// location. If it is false, reverse mode maps ".gocryptfs.reverse.conf"
|
// location. If it is false, reverse mode maps ".gocryptfs.reverse.conf"
|
||||||
// to "gocryptfs.conf" in the plaintext dir.
|
// to "gocryptfs.conf" in the plaintext dir.
|
||||||
|
@ -77,6 +77,9 @@ func (fs *FS) GetAttr(name string, context *fuse.Context) (*fuse.Attr, fuse.Stat
|
|||||||
target, _ := fs.Readlink(name, context)
|
target, _ := fs.Readlink(name, context)
|
||||||
a.Size = uint64(len(target))
|
a.Size = uint64(len(target))
|
||||||
}
|
}
|
||||||
|
if fs.args.ForceOwner != nil {
|
||||||
|
a.Owner = *fs.args.ForceOwner
|
||||||
|
}
|
||||||
return a, status
|
return a, status
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,6 +115,9 @@ func (rfs *ReverseFS) GetAttr(relPath string, context *fuse.Context) (*fuse.Attr
|
|||||||
}
|
}
|
||||||
var a fuse.Attr
|
var a fuse.Attr
|
||||||
a.FromStat(&st)
|
a.FromStat(&st)
|
||||||
|
if rfs.args.ForceOwner != nil {
|
||||||
|
a.Owner = *rfs.args.ForceOwner
|
||||||
|
}
|
||||||
return &a, fuse.OK
|
return &a, fuse.OK
|
||||||
}
|
}
|
||||||
// Handle virtual files (gocryptfs.diriv, *.name)
|
// Handle virtual files (gocryptfs.diriv, *.name)
|
||||||
@ -136,6 +139,9 @@ func (rfs *ReverseFS) GetAttr(relPath string, context *fuse.Context) (*fuse.Attr
|
|||||||
}
|
}
|
||||||
var a fuse.Attr
|
var a fuse.Attr
|
||||||
status = f.GetAttr(&a)
|
status = f.GetAttr(&a)
|
||||||
|
if rfs.args.ForceOwner != nil {
|
||||||
|
a.Owner = *rfs.args.ForceOwner
|
||||||
|
}
|
||||||
return &a, status
|
return &a, status
|
||||||
}
|
}
|
||||||
// Decrypt path to "plaintext relative path"
|
// Decrypt path to "plaintext relative path"
|
||||||
@ -177,6 +183,9 @@ func (rfs *ReverseFS) GetAttr(relPath string, context *fuse.Context) (*fuse.Attr
|
|||||||
|
|
||||||
a.Size = uint64(len(linkTarget))
|
a.Size = uint64(len(linkTarget))
|
||||||
}
|
}
|
||||||
|
if rfs.args.ForceOwner != nil {
|
||||||
|
a.Owner = *rfs.args.ForceOwner
|
||||||
|
}
|
||||||
return &a, fuse.OK
|
return &a, fuse.OK
|
||||||
}
|
}
|
||||||
|
|
||||||
|
22
main.go
22
main.go
@ -8,6 +8,7 @@ import (
|
|||||||
"runtime"
|
"runtime"
|
||||||
"runtime/pprof"
|
"runtime/pprof"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/rfjakob/gocryptfs/internal/configfile"
|
"github.com/rfjakob/gocryptfs/internal/configfile"
|
||||||
@ -17,6 +18,7 @@ import (
|
|||||||
"github.com/rfjakob/gocryptfs/internal/speed"
|
"github.com/rfjakob/gocryptfs/internal/speed"
|
||||||
"github.com/rfjakob/gocryptfs/internal/stupidgcm"
|
"github.com/rfjakob/gocryptfs/internal/stupidgcm"
|
||||||
"github.com/rfjakob/gocryptfs/internal/tlog"
|
"github.com/rfjakob/gocryptfs/internal/tlog"
|
||||||
|
"github.com/hanwen/go-fuse/fuse"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GitVersion is the gocryptfs version according to git, set by build.bash
|
// GitVersion is the gocryptfs version according to git, set by build.bash
|
||||||
@ -190,6 +192,26 @@ func main() {
|
|||||||
pprof.StartCPUProfile(f)
|
pprof.StartCPUProfile(f)
|
||||||
defer pprof.StopCPUProfile()
|
defer pprof.StopCPUProfile()
|
||||||
}
|
}
|
||||||
|
// "-force_owner"
|
||||||
|
if args.force_owner != "" {
|
||||||
|
var uidNum, gidNum int64
|
||||||
|
ownerPieces := strings.SplitN(args.force_owner, ":", 2)
|
||||||
|
if len(ownerPieces) != 2 {
|
||||||
|
tlog.Fatal.Printf("force_owner must be in form UID:GID")
|
||||||
|
os.Exit(exitcodes.Usage)
|
||||||
|
}
|
||||||
|
uidNum, err = strconv.ParseInt(ownerPieces[0], 0, 32)
|
||||||
|
if err != nil || uidNum < 0 {
|
||||||
|
tlog.Fatal.Printf("force_owner: Unable to parse UID %v as positive integer", ownerPieces[0])
|
||||||
|
os.Exit(exitcodes.Usage)
|
||||||
|
}
|
||||||
|
gidNum, err = strconv.ParseInt(ownerPieces[1], 0, 32)
|
||||||
|
if err != nil || gidNum < 0 {
|
||||||
|
tlog.Fatal.Printf("force_owner: Unable to parse GID %v as positive integer", ownerPieces[1])
|
||||||
|
os.Exit(exitcodes.Usage)
|
||||||
|
}
|
||||||
|
args._forceOwner = &fuse.Owner{Uid: uint32(uidNum), Gid: uint32(gidNum)}
|
||||||
|
}
|
||||||
// "-memprofile"
|
// "-memprofile"
|
||||||
if args.memprofile != "" {
|
if args.memprofile != "" {
|
||||||
tlog.Info.Printf("Writing mem profile to %s", args.memprofile)
|
tlog.Info.Printf("Writing mem profile to %s", args.memprofile)
|
||||||
|
6
mount.go
6
mount.go
@ -217,6 +217,11 @@ func initFuseFrontend(key []byte, args *argContainer, confFile *configfile.ConfF
|
|||||||
if args.aessiv {
|
if args.aessiv {
|
||||||
cryptoBackend = cryptocore.BackendAESSIV
|
cryptoBackend = cryptocore.BackendAESSIV
|
||||||
}
|
}
|
||||||
|
// forceOwner implies allow_other, as documented.
|
||||||
|
// Set this early, so args.allow_other can be relied on below this point.
|
||||||
|
if args._forceOwner != nil {
|
||||||
|
args.allow_other = true
|
||||||
|
}
|
||||||
frontendArgs := fusefrontend.Args{
|
frontendArgs := fusefrontend.Args{
|
||||||
Cipherdir: args.cipherdir,
|
Cipherdir: args.cipherdir,
|
||||||
Masterkey: key,
|
Masterkey: key,
|
||||||
@ -229,6 +234,7 @@ func initFuseFrontend(key []byte, args *argContainer, confFile *configfile.ConfF
|
|||||||
HKDF: args.hkdf,
|
HKDF: args.hkdf,
|
||||||
SerializeReads: args.serialize_reads,
|
SerializeReads: args.serialize_reads,
|
||||||
ForceDecode: args.forcedecode,
|
ForceDecode: args.forcedecode,
|
||||||
|
ForceOwner: args._forceOwner,
|
||||||
}
|
}
|
||||||
// confFile is nil when "-zerokey" or "-masterkey" was used
|
// confFile is nil when "-zerokey" or "-masterkey" was used
|
||||||
if confFile != nil {
|
if confFile != nil {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user