From 31bc8c843e1862b2d28f31eff85eca3d1dbd4754 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sat, 9 May 2020 14:04:47 -0700 Subject: cmd/fscrypt: add FSCRYPT_CONF environmental variable Allow overriding the location of fscrypt.conf by setting the FSCRYPT_CONF environmental variable. The CLI tests need this to avoid touching the real /etc/fscrypt.conf. --- cmd/fscrypt/fscrypt.go | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'cmd/fscrypt') diff --git a/cmd/fscrypt/fscrypt.go b/cmd/fscrypt/fscrypt.go index e260f7f..069cc96 100644 --- a/cmd/fscrypt/fscrypt.go +++ b/cmd/fscrypt/fscrypt.go @@ -31,6 +31,8 @@ import ( "os" "github.com/urfave/cli" + + "github.com/google/fscrypt/actions" ) // Current version of the program (set by Makefile) @@ -41,6 +43,10 @@ func main() { cli.CommandHelpTemplate = commandHelpTemplate cli.SubcommandHelpTemplate = subcommandHelpTemplate + if conffile := os.Getenv("FSCRYPT_CONF"); conffile != "" { + actions.ConfigFileLocation = conffile + } + // Create our command line application app := cli.NewApp() app.Usage = shortUsage -- cgit v1.3 From 8ff53630f1cc90ae23835e9571f9096e211dce67 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sat, 9 May 2020 14:04:47 -0700 Subject: cmd/fscrypt: add FSCRYPT_ROOT_MNT environmental variable Allow overriding the mountpoint where login protectors are stored by setting the FSCRYPT_ROOT_MNT environmental variable. The CLI tests need this to avoid touching the real "/". --- actions/protector.go | 4 ++++ cmd/fscrypt/commands.go | 5 +++-- cmd/fscrypt/fscrypt.go | 3 +++ cmd/fscrypt/protector.go | 14 ++++++++------ pam_fscrypt/run_fscrypt.go | 3 ++- 5 files changed, 20 insertions(+), 9 deletions(-) (limited to 'cmd/fscrypt') diff --git a/actions/protector.go b/actions/protector.go index 4bd7c15..dab9c27 100644 --- a/actions/protector.go +++ b/actions/protector.go @@ -30,6 +30,10 @@ import ( "github.com/google/fscrypt/util" ) +// LoginProtectorMountpoint is the mountpoint where login protectors are stored. +// This can be overridden by the user of this package. +var LoginProtectorMountpoint = "/" + // Errors relating to Protectors var ( ErrProtectorName = errors.New("login protectors do not need a name") diff --git a/cmd/fscrypt/commands.go b/cmd/fscrypt/commands.go index f84102e..ec75584 100644 --- a/cmd/fscrypt/commands.go +++ b/cmd/fscrypt/commands.go @@ -73,12 +73,13 @@ func setupAction(c *cli.Context) error { if err := createGlobalConfig(c.App.Writer, actions.ConfigFileLocation); err != nil { return newExitError(c, err) } - if err := setupFilesystem(c.App.Writer, "/"); err != nil { + if err := setupFilesystem(c.App.Writer, actions.LoginProtectorMountpoint); err != nil { if errors.Cause(err) != filesystem.ErrAlreadySetup { return newExitError(c, err) } fmt.Fprintf(c.App.Writer, - "Skipping creating /.fscrypt because it already exists.\n") + "Skipping creating %s because it already exists.\n", + filepath.Join(actions.LoginProtectorMountpoint, ".fscrypt")) } case 1: // Case (2) - filesystem setup diff --git a/cmd/fscrypt/fscrypt.go b/cmd/fscrypt/fscrypt.go index 069cc96..bbe16bb 100644 --- a/cmd/fscrypt/fscrypt.go +++ b/cmd/fscrypt/fscrypt.go @@ -46,6 +46,9 @@ func main() { if conffile := os.Getenv("FSCRYPT_CONF"); conffile != "" { actions.ConfigFileLocation = conffile } + if rootmnt := os.Getenv("FSCRYPT_ROOT_MNT"); rootmnt != "" { + actions.LoginProtectorMountpoint = rootmnt + } // Create our command line application app := cli.NewApp() diff --git a/cmd/fscrypt/protector.go b/cmd/fscrypt/protector.go index 25f1984..6d35d9e 100644 --- a/cmd/fscrypt/protector.go +++ b/cmd/fscrypt/protector.go @@ -51,8 +51,10 @@ func createProtectorFromContext(ctx *actions.Context) (*actions.Protector, error // We only want to create new login protectors on the root filesystem. // So we make a new context if necessary. - if ctx.Config.Source == metadata.SourceType_pam_passphrase && ctx.Mount.Path != "/" { - log.Printf("creating login protector on %q instead of %q", "/", ctx.Mount.Path) + if ctx.Config.Source == metadata.SourceType_pam_passphrase && + ctx.Mount.Path != actions.LoginProtectorMountpoint { + log.Printf("creating login protector on %q instead of %q", + actions.LoginProtectorMountpoint, ctx.Mount.Path) if ctx, err = modifiedContext(ctx); err != nil { return nil, err } @@ -84,7 +86,7 @@ func expandedProtectorOptions(ctx *actions.Context) ([]*actions.ProtectorOption, } // Do nothing different if we are at the root, or cannot load the root. - if ctx.Mount.Path == "/" { + if ctx.Mount.Path == actions.LoginProtectorMountpoint { return options, nil } if ctx, err = modifiedContext(ctx); err != nil { @@ -117,10 +119,10 @@ func expandedProtectorOptions(ctx *actions.Context) ([]*actions.ProtectorOption, return options, nil } -// modifiedContext returns a copy of ctx with the mountpoint replaced by that of -// the root filesystem. +// modifiedContext returns a copy of ctx with the mountpoint replaced by +// LoginProtectorMountpoint. func modifiedContext(ctx *actions.Context) (*actions.Context, error) { - mnt, err := filesystem.GetMount("/") + mnt, err := filesystem.GetMount(actions.LoginProtectorMountpoint) if err != nil { return nil, err } diff --git a/pam_fscrypt/run_fscrypt.go b/pam_fscrypt/run_fscrypt.go index 3d0acb1..ef7ff92 100644 --- a/pam_fscrypt/run_fscrypt.go +++ b/pam_fscrypt/run_fscrypt.go @@ -132,7 +132,8 @@ func setupLogging(args map[string]bool) io.Writer { // one exists. This protector descriptor (if found) will be cached in the pam // data, under descriptorLabel. func loginProtector(handle *pam.Handle) (*actions.Protector, error) { - ctx, err := actions.NewContextFromMountpoint("/", handle.PamUser) + ctx, err := actions.NewContextFromMountpoint(actions.LoginProtectorMountpoint, + handle.PamUser) if err != nil { return nil, err } -- cgit v1.3 From 5716215ceae3ab8b49a7b2ba410cb51a82c3176b Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sat, 9 May 2020 14:04:47 -0700 Subject: cmd/fscrypt: add FSCRYPT_CONSISTENT_OUTPUT environmental variable Allow setting FSCRYPT_CONSISTENT_OUTPUT=1 in the environment to cause policies and protectors to sorted by last modification time. The CLI tests need this to make the output of 'fscrypt' ordered in a consistent way with regard to the operations performed. --- cmd/fscrypt/fscrypt.go | 4 ++++ filesystem/filesystem.go | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) (limited to 'cmd/fscrypt') diff --git a/cmd/fscrypt/fscrypt.go b/cmd/fscrypt/fscrypt.go index bbe16bb..aa5b6f4 100644 --- a/cmd/fscrypt/fscrypt.go +++ b/cmd/fscrypt/fscrypt.go @@ -33,6 +33,7 @@ import ( "github.com/urfave/cli" "github.com/google/fscrypt/actions" + "github.com/google/fscrypt/filesystem" ) // Current version of the program (set by Makefile) @@ -49,6 +50,9 @@ func main() { if rootmnt := os.Getenv("FSCRYPT_ROOT_MNT"); rootmnt != "" { actions.LoginProtectorMountpoint = rootmnt } + if consistent := os.Getenv("FSCRYPT_CONSISTENT_OUTPUT"); consistent == "1" { + filesystem.SortDescriptorsByLastMtime = true + } // Create our command line application app := cli.NewApp() diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go index ecdeae1..e01f9ff 100644 --- a/filesystem/filesystem.go +++ b/filesystem/filesystem.go @@ -38,7 +38,9 @@ import ( "log" "os" "path/filepath" + "sort" "strings" + "time" "github.com/golang/protobuf/proto" "github.com/pkg/errors" @@ -63,6 +65,11 @@ var ( ErrCorruptMetadata = util.SystemError("on-disk metadata is corrupt") ) +// SortDescriptorsByLastMtime indicates whether descriptors are sorted by last +// modification time when being listed. This can be set to true to get +// consistent output for testing. +var SortDescriptorsByLastMtime = false + // Mount contains information for a specific mounted filesystem. // Path - Absolute path where the directory is mounted // FilesystemType - Type of the mounted filesystem, e.g. "ext4" @@ -534,6 +541,37 @@ func (m *Mount) ListPolicies() ([]string, error) { return policies, m.err(err) } +type namesAndTimes struct { + names []string + times []time.Time +} + +func (c namesAndTimes) Len() int { + return len(c.names) +} + +func (c namesAndTimes) Less(i, j int) bool { + return c.times[i].Before(c.times[j]) +} + +func (c namesAndTimes) Swap(i, j int) { + c.names[i], c.names[j] = c.names[j], c.names[i] + c.times[i], c.times[j] = c.times[j], c.times[i] +} + +func sortFileListByLastMtime(directoryPath string, names []string) error { + c := namesAndTimes{names: names, times: make([]time.Time, len(names))} + for i, name := range names { + fi, err := os.Lstat(filepath.Join(directoryPath, name)) + if err != nil { + return err + } + c.times[i] = fi.ModTime() + } + sort.Sort(c) + return nil +} + // listDirectory returns a list of descriptors for a metadata directory, // including files which are links to other filesystem's metadata. func (m *Mount) listDirectory(directoryPath string) ([]string, error) { @@ -549,6 +587,12 @@ func (m *Mount) listDirectory(directoryPath string) ([]string, error) { return nil, err } + if SortDescriptorsByLastMtime { + if err := sortFileListByLastMtime(directoryPath, names); err != nil { + return nil, err + } + } + descriptors := make([]string, 0, len(names)) for _, name := range names { // Be sure to include links as well -- cgit v1.3