From 6e355131670ad014e45f879475ddf800f0080d41 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Wed, 23 Feb 2022 12:35:04 -0800 Subject: Make 'fscrypt setup' offer a choice of directory modes World-writable directories are not appropriate for some systems, so offer a choice of single-user-writable and world-writable modes, with single-user-writable being the default. Add a new documentation section to help users decide which one to use. --- cmd/fscrypt/commands.go | 6 +++--- cmd/fscrypt/errors.go | 4 ++++ cmd/fscrypt/flags.go | 14 ++++++++++++-- cmd/fscrypt/setup.go | 41 +++++++++++++++++++++++++++++++++++++++-- cmd/fscrypt/status.go | 11 ++++++++++- 5 files changed, 68 insertions(+), 8 deletions(-) (limited to 'cmd') diff --git a/cmd/fscrypt/commands.go b/cmd/fscrypt/commands.go index 023c0fa..30aa3a7 100644 --- a/cmd/fscrypt/commands.go +++ b/cmd/fscrypt/commands.go @@ -63,7 +63,7 @@ var Setup = cli.Command{ the README). This may require root privileges.`, mountpointArg, actions.ConfigFileLocation, shortDisplay(timeTargetFlag)), - Flags: []cli.Flag{timeTargetFlag, forceFlag}, + Flags: []cli.Flag{timeTargetFlag, forceFlag, allUsersSetupFlag}, Action: setupAction, } @@ -468,7 +468,7 @@ var Lock = cli.Command{ recoverable by an attacker who compromises system memory. To be fully safe, you must reboot with a power cycle.`, directoryArg, shortDisplay(dropCachesFlag)), - Flags: []cli.Flag{dropCachesFlag, userFlag, allUsersFlag}, + Flags: []cli.Flag{dropCachesFlag, userFlag, allUsersLockFlag}, Action: lockAction, } @@ -502,7 +502,7 @@ func lockAction(c *cli.Context) error { return newExitError(c, ErrDropCachesPerm) } - if err = policy.Deprovision(allUsersFlag.Value); err != nil { + if err = policy.Deprovision(allUsersLockFlag.Value); err != nil { switch err { case keyring.ErrKeyNotPresent: break diff --git a/cmd/fscrypt/errors.go b/cmd/fscrypt/errors.go index bcf5b59..2d76792 100644 --- a/cmd/fscrypt/errors.go +++ b/cmd/fscrypt/errors.go @@ -232,6 +232,10 @@ func getErrorSuggestions(err error) string { } } return "" + case *filesystem.ErrNoCreatePermission: + return `For how to allow users to create fscrypt metadata on a + filesystem, refer to + https://github.com/google/fscrypt#setting-up-fscrypt-on-a-filesystem` case *filesystem.ErrNotSetup: return fmt.Sprintf(`Run "sudo fscrypt setup %s" to use fscrypt on this filesystem.`, e.Mount.Path) diff --git a/cmd/fscrypt/flags.go b/cmd/fscrypt/flags.go index 044b71e..1b41839 100644 --- a/cmd/fscrypt/flags.go +++ b/cmd/fscrypt/flags.go @@ -116,7 +116,8 @@ var ( allFlags = []prettyFlag{helpFlag, versionFlag, verboseFlag, quietFlag, forceFlag, skipUnlockFlag, timeTargetFlag, sourceFlag, nameFlag, keyFileFlag, protectorFlag, - unlockWithFlag, policyFlag, allUsersFlag, noRecoveryFlag} + unlockWithFlag, policyFlag, allUsersLockFlag, allUsersSetupFlag, + noRecoveryFlag} // universalFlags contains flags that should be on every command universalFlags = []cli.Flag{verboseFlag, quietFlag, helpFlag} ) @@ -164,7 +165,7 @@ var ( privileges.`, Default: true, } - allUsersFlag = &boolFlag{ + allUsersLockFlag = &boolFlag{ Name: "all-users", Usage: `Lock the directory no matter which user(s) have unlocked it. Requires root privileges. This flag is only @@ -172,6 +173,15 @@ var ( different from the one you're locking it as. This flag is only implemented for v2 encryption policies.`, } + allUsersSetupFlag = &boolFlag{ + Name: "all-users", + Usage: `When setting up a filesystem for fscrypt, allow users + other than the calling user (typically root) to create + fscrypt policies and protectors on the filesystem. Note + that this will create a world-writable directory, which + users could use to fill up the entire filesystem. Hence, + this option may not be appropriate for some systems.`, + } noRecoveryFlag = &boolFlag{ Name: "no-recovery", Usage: `Don't generate a recovery passphrase.`, diff --git a/cmd/fscrypt/setup.go b/cmd/fscrypt/setup.go index 7b9bebb..1da0d16 100644 --- a/cmd/fscrypt/setup.go +++ b/cmd/fscrypt/setup.go @@ -26,6 +26,7 @@ import ( "os" "github.com/google/fscrypt/actions" + "github.com/google/fscrypt/filesystem" "github.com/google/fscrypt/util" ) @@ -80,11 +81,47 @@ func setupFilesystem(w io.Writer, path string) error { if err != nil { return err } + username := ctx.TargetUser.Username - if err = ctx.Mount.Setup(); err != nil { + err = ctx.Mount.CheckSetup() + if err == nil { + return &filesystem.ErrAlreadySetup{Mount: ctx.Mount} + } + if _, ok := err.(*filesystem.ErrNotSetup); !ok { return err } - fmt.Fprintf(w, "Metadata directories created at %q.\n", ctx.Mount.BaseDir()) + allUsers := allUsersSetupFlag.Value + if !allUsers { + thisFilesystem := "this filesystem" + if ctx.Mount.Path == "/" { + thisFilesystem = "the root filesystem" + } + prompt := fmt.Sprintf(`Allow users other than %s to create +fscrypt metadata on %s? (See +https://github.com/google/fscrypt#setting-up-fscrypt-on-a-filesystem)`, + username, thisFilesystem) + allUsers, err = askQuestion(wrapText(prompt, 0), false) + if err != nil { + return err + } + } + var setupMode filesystem.SetupMode + if allUsers { + setupMode = filesystem.WorldWritable + } else { + setupMode = filesystem.SingleUserWritable + } + if err = ctx.Mount.Setup(setupMode); err != nil { + return err + } + + if allUsers { + fmt.Fprintf(w, "Metadata directories created at %q, writable by everyone.\n", + ctx.Mount.BaseDir()) + } else { + fmt.Fprintf(w, "Metadata directories created at %q, writable by %s only.\n", + ctx.Mount.BaseDir(), username) + } return nil } diff --git a/cmd/fscrypt/status.go b/cmd/fscrypt/status.go index d10dfd8..54c6f1f 100644 --- a/cmd/fscrypt/status.go +++ b/cmd/fscrypt/status.go @@ -165,9 +165,18 @@ func writeFilesystemStatus(w io.Writer, ctx *actions.Context) error { return err } - fmt.Fprintf(w, "%s filesystem %q has %s and %s\n\n", ctx.Mount.FilesystemType, + fmt.Fprintf(w, "%s filesystem %q has %s and %s.\n", ctx.Mount.FilesystemType, ctx.Mount.Path, pluralize(len(options), "protector"), pluralize(len(policyDescriptors), "policy")) + if setupMode, user, err := ctx.Mount.GetSetupMode(); err == nil { + switch setupMode { + case filesystem.WorldWritable: + fmt.Fprintf(w, "All users can create fscrypt metadata on this filesystem.\n") + case filesystem.SingleUserWritable: + fmt.Fprintf(w, "Only %s can create fscrypt metadata on this filesystem.\n", user.Username) + } + } + fmt.Fprintf(w, "\n") if len(options) > 0 { writeOptions(w, options) -- cgit v1.2.3