From defd27f75df3a6eef84ac33adf89b1ce255e738c Mon Sep 17 00:00:00 2001 From: "Joe Richey joerichey@google.com" Date: Wed, 31 May 2017 17:54:35 -0700 Subject: actions: Simplify the callback mechanism This commit makes the callbacks for getting keys easier to understand. Functions which need keys now take a KeyFunc callback. This callback contains a ProtectorInfo parameter (basically a read-only version of metadata.ProtectorData) and a boolean which indicates if the call is being retried. The documentation is also updated to say which functions will retry the KeyFunc. For selecting a protector, there is now an OptionFunc callback which takes a slice of ProtectorOptions. A ProtectorOption is a ProtectorInfo along with additional information about a linked filesystem (if applicable). This commit also adds in methods for getting the protector options for a specific filesystem or policy. It also adds a function for getting the policy descriptor for a specific path. Change-Id: I41e0d94ffd44e7166b0c5cf1b5d18437960bdf90 --- actions/protector.go | 116 ++++++++++++++++++++++++++------------------------- 1 file changed, 60 insertions(+), 56 deletions(-) (limited to 'actions/protector.go') diff --git a/actions/protector.go b/actions/protector.go index c57d016..4680cba 100644 --- a/actions/protector.go +++ b/actions/protector.go @@ -35,34 +35,16 @@ var ( ErrDuplicateUID = errors.New("there is already a login protector for this user") ) -// ListProtectorData creates a slice of all the data for Protectors on the -// Context's mountpoint. -func (ctx *Context) ListProtectorData() ([]ProtectorData, error) { - descriptors, err := ctx.Mount.ListProtectors() - if err != nil { - return nil, err - } - - data := make([]ProtectorData, len(descriptors)) - for i, descriptor := range descriptors { - data[i], err = ctx.Mount.GetRegularProtector(descriptor) - if err != nil { - return nil, err - } - } - return data, err -} - // checkForProtectorWithName returns an error if there is already a protector // on the filesystem with a specific name (or if we cannot read the necessary // data). -func (ctx *Context) checkForProtectorWithName(name string) error { - protectors, err := ctx.ListProtectorData() +func checkForProtectorWithName(ctx *Context, name string) error { + options, err := ctx.ListProtectorOptions() if err != nil { return err } - for _, protector := range protectors { - if protector.GetName() == name { + for _, option := range options { + if option.Name() == name { return ErrDuplicateName } } @@ -72,14 +54,13 @@ func (ctx *Context) checkForProtectorWithName(name string) error { // checkForProtectorWithUid returns an error if there is already a login // protector on the filesystem with a specific UID (or if we cannot read the // necessary data). -func (ctx *Context) checkForProtectorWithUID(uid int64) error { - protectors, err := ctx.ListProtectorData() +func checkForProtectorWithUID(ctx *Context, uid int64) error { + options, err := ctx.ListProtectorOptions() if err != nil { return err } - for _, protector := range protectors { - if protector.GetSource() == metadata.SourceType_pam_passphrase && - protector.GetUid() == uid { + for _, option := range options { + if option.Source() == metadata.SourceType_pam_passphrase && option.UID() == uid { return ErrDuplicateUID } } @@ -91,20 +72,19 @@ func (ctx *Context) checkForProtectorWithUID(uid int64) error { // to unlock policies and create new polices. As with the key struct, a // Protector should be wiped after use. type Protector struct { - *Context - data *metadata.ProtectorData - key *crypto.Key + Context *Context + data *metadata.ProtectorData + key *crypto.Key } -// NewProtector creates a protector with a given name (only for custom and raw -// protector types) and uses the provided KeyCallback to get the Key. The -// appropriate data is then stored on the filesystem. On error, nothing is -// changed on the filesystem. -func (ctx *Context) NewProtector(name string, callback KeyCallback) (*Protector, error) { - if !ctx.Config.IsValid() { - return nil, ErrBadConfig +// CreateProtector creates a protector with a given name (only for custom and +// raw protector types). The keyFn provided to create the Protector key will +// only be called once. If an error is returned, no data has been changed on the +// filesystem. +func CreateProtector(ctx *Context, name string, keyFn KeyFunc) (*Protector, error) { + if err := ctx.checkContext(); err != nil { + return nil, err } - // Sanity checks for names if ctx.Config.Source == metadata.SourceType_pam_passphrase { // login protectors don't need a name (we use the username instead) @@ -117,7 +97,7 @@ func (ctx *Context) NewProtector(name string, callback KeyCallback) (*Protector, return nil, ErrMissingProtectorName } // we don't want to duplicate naming - if err := ctx.checkForProtectorWithName(name); err != nil { + if err := checkForProtectorWithName(ctx, name); err != nil { return nil, err } } @@ -138,7 +118,7 @@ func (ctx *Context) NewProtector(name string, callback KeyCallback) (*Protector, // UID for this kind of source. protector.data.Uid = int64(os.Getuid()) // Make sure we aren't duplicating protectors - if err := ctx.checkForProtectorWithUID(protector.data.Uid); err != nil { + if err := checkForProtectorWithUID(ctx, protector.data.Uid); err != nil { return nil, err } fallthrough @@ -157,7 +137,7 @@ func (ctx *Context) NewProtector(name string, callback KeyCallback) (*Protector, } protector.data.ProtectorDescriptor = crypto.ComputeDescriptor(protector.key) - if err := protector.Rewrap(callback); err != nil { + if err := protector.Rewrap(keyFn); err != nil { protector.Wipe() return nil, err } @@ -165,13 +145,13 @@ func (ctx *Context) NewProtector(name string, callback KeyCallback) (*Protector, return protector, nil } -// GetProtector retrieves a protector with a specific descriptor. As a key is -// necessary to unlock this Protector, a KeyCallback must also be provided. -func (ctx *Context) GetProtector(descriptor string, callback KeyCallback) (*Protector, error) { - if !ctx.Config.IsValid() { - return nil, ErrBadConfig +// GetProtector retrieves a Protector with a specific descriptor. The keyFn +// provided to unwrap the Protector key will be retied as necessary to get the +// correct key. +func GetProtector(ctx *Context, descriptor string, keyFn KeyFunc) (*Protector, error) { + if err := ctx.checkContext(); err != nil { + return nil, err } - var err error protector := &Protector{Context: ctx} @@ -179,16 +159,39 @@ func (ctx *Context) GetProtector(descriptor string, callback KeyCallback) (*Prot return nil, err } - protector.key, err = unwrapProtectorKey(protector.data, callback) + protector.key, err = unwrapProtectorKey(ProtectorInfo{protector.data}, keyFn) + return protector, err +} + +// GetProtectorFromOption retrieves a protector based on a protector option. +// If the option had a load error, this function returns that error. The +// keyFn provided to unwrap the Protector key will be retied as necessary to +// get the correct key. +func GetProtectorFromOption(ctx *Context, option *ProtectorOption, keyFn KeyFunc) (*Protector, error) { + if err := ctx.checkContext(); err != nil { + return nil, err + } + if option.LoadError != nil { + return nil, option.LoadError + } + + // Replace the context if this is a linked protector + if option.LinkedMount != nil { + ctx = &Context{ctx.Config, option.LinkedMount} + } + var err error + protector := &Protector{Context: ctx, data: option.data} + + protector.key, err = unwrapProtectorKey(option.ProtectorInfo, keyFn) return protector, err } // Rewrap updates the data that is wrapping the Protector Key. This is useful if -// a user's password has changed, for example. As a key is necessary to rewrap -// this Protector, a KeyCallback must be provided. If an error is returned, no -// data has been changed. -func (protector *Protector) Rewrap(callback KeyCallback) error { - wrappingKey, err := getWrappingKey(protector.data, callback) +// a user's password has changed, for example. The keyFn provided to rewrap +// the Protector key will only be called once. If an error is returned, no data +// has been changed on the filesystem. +func (protector *Protector) Rewrap(keyFn KeyFunc) error { + wrappingKey, err := getWrappingKey(ProtectorInfo{protector.data}, keyFn, false) if err != nil { return err } @@ -206,10 +209,11 @@ func (protector *Protector) Rewrap(callback KeyCallback) error { return err } - return protector.Mount.AddProtector(protector.data) + return protector.Context.Mount.AddProtector(protector.data) } -// Wipe wipes a Protector's internal Key +// Wipe wipes a Protector's internal Key. It should always be called after using +// a Protector. This is often done with a defer statement. func (protector *Protector) Wipe() error { return protector.key.Wipe() } @@ -217,5 +221,5 @@ func (protector *Protector) Wipe() error { // Destroy removes a protector from the filesystem. The internal key should // still be wiped with Wipe(). func (protector *Protector) Destroy() error { - return protector.Mount.RemoveProtector(protector.data.ProtectorDescriptor) + return protector.Context.Mount.RemoveProtector(protector.data.ProtectorDescriptor) } -- cgit v1.2.3