aboutsummaryrefslogtreecommitdiff
path: root/actions
diff options
context:
space:
mode:
Diffstat (limited to 'actions')
-rw-r--r--actions/context.go70
-rw-r--r--actions/context_test.go4
-rw-r--r--actions/policy.go8
-rw-r--r--actions/protector.go16
4 files changed, 63 insertions, 35 deletions
diff --git a/actions/context.go b/actions/context.go
index 7e4b64b..8ad1357 100644
--- a/actions/context.go
+++ b/actions/context.go
@@ -30,6 +30,7 @@ package actions
import (
"log"
+ "os/user"
"golang.org/x/sys/unix"
@@ -37,6 +38,7 @@ import (
"github.com/google/fscrypt/filesystem"
"github.com/google/fscrypt/metadata"
+ "github.com/google/fscrypt/util"
)
// Errors relating to Config files or Config structures.
@@ -49,47 +51,73 @@ var (
)
// Context contains the necessary global state to perform most of fscrypt's
-// actions. It contains a config struct, which is loaded from the global config
-// file, but can be edited manually. A context is specific to a filesystem, and
-// all actions to add, edit, remove, and apply Protectors and Policies are done
-// relative to that filesystem.
+// actions.
type Context struct {
+ // Config is the struct loaded from the global config file. It can be
+ // modified after being loaded to customise parameters.
Config *metadata.Config
- Mount *filesystem.Mount
+ // Mount is the filesystem relitive to which all Protectors and Policies
+ // are added, edited, removed, and applied.
+ Mount *filesystem.Mount
+ // TargetUser is the user for which protectors are created and to whose
+ // keyring policies are provisioned.
+ TargetUser *user.User
}
// NewContextFromPath makes a context for the filesystem containing the
// specified path and whose Config is loaded from the global config file. On
-// success, the Context contains a valid Config and Mount.
-func NewContextFromPath(path string) (ctx *Context, err error) {
- ctx = new(Context)
- if ctx.Mount, err = filesystem.FindMount(path); err != nil {
- return
+// success, the Context contains a valid Config and Mount. The target defaults
+// the the current effective user if none is specified.
+func NewContextFromPath(path string, target *user.User) (*Context, error) {
+ ctx, err := newContextFromUser(target)
+ if err != nil {
+ return nil, err
}
- if ctx.Config, err = getConfig(); err != nil {
- return
+ if ctx.Mount, err = filesystem.FindMount(path); err != nil {
+ return nil, err
}
log.Printf("%s is on %s filesystem %q (%s)", path,
ctx.Mount.Filesystem, ctx.Mount.Path, ctx.Mount.Device)
- return
+ return ctx, nil
}
// NewContextFromMountpoint makes a context for the filesystem at the specified
// mountpoint and whose Config is loaded from the global config file. On
-// success, the Context contains a valid Config and Mount.
-func NewContextFromMountpoint(mountpoint string) (ctx *Context, err error) {
- ctx = new(Context)
- if ctx.Mount, err = filesystem.GetMount(mountpoint); err != nil {
- return
+// success, the Context contains a valid Config and Mount. The target defaults
+// the the current effective user if none is specified.
+func NewContextFromMountpoint(mountpoint string, target *user.User) (*Context, error) {
+ ctx, err := newContextFromUser(target)
+ if err != nil {
+ return nil, err
}
- if ctx.Config, err = getConfig(); err != nil {
- return
+ if ctx.Mount, err = filesystem.GetMount(mountpoint); err != nil {
+ return nil, err
}
log.Printf("found %s filesystem %q (%s)", ctx.Mount.Filesystem,
ctx.Mount.Path, ctx.Mount.Device)
- return
+ return ctx, nil
+}
+
+// newContextFromUser makes a context with the corresponding target user, and
+// whose Config is loaded from the global config file. If the target is nil, the
+// effecitive user is used.
+func newContextFromUser(target *user.User) (*Context, error) {
+ var err error
+ if target == nil {
+ if target, err = util.EffectiveUser(); err != nil {
+ return nil, err
+ }
+ }
+
+ ctx := &Context{TargetUser: target}
+ if ctx.Config, err = getConfig(); err != nil {
+ return nil, err
+ }
+
+ log.Printf("creating context for %q", target.Username)
+ return ctx, nil
}
// checkContext verifies that the context contains an valid config and a mount
diff --git a/actions/context_test.go b/actions/context_test.go
index 4b38a33..593518f 100644
--- a/actions/context_test.go
+++ b/actions/context_test.go
@@ -47,7 +47,7 @@ func setupContext() (ctx *Context, err error) {
ConfigFileLocation = filepath.Join(mountpoint, "test.conf")
// Should not be able to setup without a config file
- if badCtx, badCtxErr := NewContextFromMountpoint(mountpoint); badCtxErr == nil {
+ if badCtx, badCtxErr := NewContextFromMountpoint(mountpoint, nil); badCtxErr == nil {
badCtx.Mount.RemoveAllMetadata()
return nil, fmt.Errorf("created context at %q without config file", badCtx.Mount.Path)
}
@@ -61,7 +61,7 @@ func setupContext() (ctx *Context, err error) {
}
}()
- ctx, err = NewContextFromMountpoint(mountpoint)
+ ctx, err = NewContextFromMountpoint(mountpoint, nil)
if err != nil {
return nil, err
}
diff --git a/actions/policy.go b/actions/policy.go
index 461f8cc..510afa1 100644
--- a/actions/policy.go
+++ b/actions/policy.go
@@ -57,7 +57,7 @@ func PurgeAllPolicies(ctx *Context) error {
for _, policyDescriptor := range policies {
service := ctx.getService()
- err = security.RemoveKey(service + policyDescriptor)
+ err = security.RemoveKey(service+policyDescriptor, ctx.TargetUser)
switch errors.Cause(err) {
case nil, security.ErrKeyringSearch:
@@ -372,7 +372,7 @@ func (policy *Policy) Apply(path string) error {
// IsProvisioned returns a boolean indicating if the policy has its key in the
// keyring, meaning files and directories using this policy are accessible.
func (policy *Policy) IsProvisioned() bool {
- _, err := security.FindKey(policy.Description())
+ _, err := security.FindKey(policy.Description(), policy.Context.TargetUser)
return err == nil
}
@@ -382,13 +382,13 @@ func (policy *Policy) Provision() error {
if policy.key == nil {
return ErrLocked
}
- return crypto.InsertPolicyKey(policy.key, policy.Description())
+ return crypto.InsertPolicyKey(policy.key, policy.Description(), policy.Context.TargetUser)
}
// Deprovision removes the Policy key from the kernel keyring. This prevents
// reading and writing to the directory once the caches are cleared.
func (policy *Policy) Deprovision() error {
- return security.RemoveKey(policy.Description())
+ return security.RemoveKey(policy.Description(), policy.Context.TargetUser)
}
// commitData writes the Policy's current data to the filesystem.
diff --git a/actions/protector.go b/actions/protector.go
index 5245951..ffc3c43 100644
--- a/actions/protector.go
+++ b/actions/protector.go
@@ -22,12 +22,12 @@ package actions
import (
"fmt"
"log"
- "os"
"github.com/pkg/errors"
"github.com/google/fscrypt/crypto"
"github.com/google/fscrypt/metadata"
+ "github.com/google/fscrypt/util"
)
// Errors relating to Protectors
@@ -54,17 +54,17 @@ func checkForProtectorWithName(ctx *Context, name string) error {
return nil
}
-// checkForProtectorWithUid returns an error if there is already a login
-// protector on the filesystem with a specific UID (or if we cannot read the
+// checkIfUserHasLoginProtector returns an error if there is already a login
+// protector on the filesystem for a specific user (or if we cannot read the
// necessary data).
-func checkForProtectorWithUID(ctx *Context, uid int64) error {
+func checkIfUserHasLoginProtector(ctx *Context, uid int64) error {
options, err := ctx.ProtectorOptions()
if err != nil {
return err
}
for _, option := range options {
if option.Source() == metadata.SourceType_pam_passphrase && option.UID() == uid {
- return errors.Wrapf(ErrDuplicateUID, "uid %d", uid)
+ return errors.Wrapf(ErrDuplicateUID, "user %q", ctx.TargetUser.Username)
}
}
return nil
@@ -121,9 +121,9 @@ func CreateProtector(ctx *Context, name string, keyFn KeyFunc) (*Protector, erro
case metadata.SourceType_pam_passphrase:
// As the pam passphrases are user specific, we also store the
// UID for this kind of source.
- protector.data.Uid = int64(os.Getuid())
+ protector.data.Uid = int64(util.AtoiOrPanic(ctx.TargetUser.Uid))
// Make sure we aren't duplicating protectors
- if err := checkForProtectorWithUID(ctx, protector.data.Uid); err != nil {
+ if err := checkIfUserHasLoginProtector(ctx, protector.data.Uid); err != nil {
return nil, err
}
fallthrough
@@ -180,7 +180,7 @@ func GetProtectorFromOption(ctx *Context, option *ProtectorOption) (*Protector,
// Replace the context if this is a linked protector
if option.LinkedMount != nil {
- ctx = &Context{ctx.Config, option.LinkedMount}
+ ctx = &Context{ctx.Config, option.LinkedMount, ctx.TargetUser}
}
return &Protector{Context: ctx, data: option.data}, nil
}