mirror of
https://github.com/ceph/ceph-csi.git
synced 2024-11-10 16:30:19 +00:00
185 lines
6.4 KiB
Go
185 lines
6.4 KiB
Go
|
/*
|
||
|
* context.go - top-level interface to fscrypt packages
|
||
|
*
|
||
|
* Copyright 2017 Google Inc.
|
||
|
* Author: Joe Richey (joerichey@google.com)
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||
|
* the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||
|
* License for the specific language governing permissions and limitations under
|
||
|
* the License.
|
||
|
*/
|
||
|
|
||
|
// Package actions is the high-level interface to the fscrypt packages. The
|
||
|
// functions here roughly correspond with commands for the tool in cmd/fscrypt.
|
||
|
// All of the actions include a significant amount of logging, so that good
|
||
|
// output can be provided for cmd/fscrypt's verbose mode.
|
||
|
// The top-level actions currently include:
|
||
|
// - Creating a new config file
|
||
|
// - Creating a context on which to perform actions
|
||
|
// - Creating, unlocking, and modifying Protectors
|
||
|
// - Creating, unlocking, and modifying Policies
|
||
|
package actions
|
||
|
|
||
|
import (
|
||
|
"log"
|
||
|
"os/user"
|
||
|
|
||
|
"github.com/pkg/errors"
|
||
|
|
||
|
"github.com/google/fscrypt/filesystem"
|
||
|
"github.com/google/fscrypt/keyring"
|
||
|
"github.com/google/fscrypt/metadata"
|
||
|
"github.com/google/fscrypt/util"
|
||
|
)
|
||
|
|
||
|
// ErrLocked indicates that the key hasn't been unwrapped yet.
|
||
|
var ErrLocked = errors.New("key needs to be unlocked first")
|
||
|
|
||
|
// Context contains the necessary global state to perform most of fscrypt's
|
||
|
// 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 is the filesystem relative to which all Protectors and Policies
|
||
|
// are added, edited, removed, and applied, and to which policies using
|
||
|
// the filesystem keyring are provisioned.
|
||
|
Mount *filesystem.Mount
|
||
|
// TargetUser is the user for whom protectors are created, and to whose
|
||
|
// keyring policies using the user keyring are provisioned. It's also
|
||
|
// the user for whom the keys are claimed in the filesystem keyring when
|
||
|
// v2 policies are provisioned.
|
||
|
TargetUser *user.User
|
||
|
// TrustedUser is the user for whom policies and protectors are allowed
|
||
|
// to be read. Specifically, if TrustedUser is set, then only
|
||
|
// policies and protectors owned by TrustedUser or by root will be
|
||
|
// allowed to be read. If it's nil, then all policies and protectors
|
||
|
// the process has filesystem-level read access to will be allowed.
|
||
|
TrustedUser *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. The target user
|
||
|
// defaults to the current effective user if none is specified.
|
||
|
func NewContextFromPath(path string, targetUser *user.User) (*Context, error) {
|
||
|
ctx, err := newContextFromUser(targetUser)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
if ctx.Mount, err = filesystem.FindMount(path); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
log.Printf("%s is on %s filesystem %q (%s)", path,
|
||
|
ctx.Mount.FilesystemType, ctx.Mount.Path, ctx.Mount.Device)
|
||
|
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. The target user
|
||
|
// defaults to the current effective user if none is specified.
|
||
|
func NewContextFromMountpoint(mountpoint string, targetUser *user.User) (*Context, error) {
|
||
|
ctx, err := newContextFromUser(targetUser)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
if ctx.Mount, err = filesystem.GetMount(mountpoint); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
log.Printf("found %s filesystem %q (%s)", ctx.Mount.FilesystemType,
|
||
|
ctx.Mount.Path, ctx.Mount.Device)
|
||
|
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 user is
|
||
|
// nil, the effective user is used.
|
||
|
func newContextFromUser(targetUser *user.User) (*Context, error) {
|
||
|
var err error
|
||
|
if targetUser == nil {
|
||
|
if targetUser, err = util.EffectiveUser(); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ctx := &Context{TargetUser: targetUser}
|
||
|
if ctx.Config, err = getConfig(); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
// By default, when running as a non-root user we only read policies and
|
||
|
// protectors owned by the user or root. When running as root, we allow
|
||
|
// reading all policies and protectors.
|
||
|
if !ctx.Config.GetAllowCrossUserMetadata() && !util.IsUserRoot() {
|
||
|
ctx.TrustedUser, err = util.EffectiveUser()
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
}
|
||
|
|
||
|
log.Printf("creating context for user %q", targetUser.Username)
|
||
|
return ctx, nil
|
||
|
}
|
||
|
|
||
|
// checkContext verifies that the context contains a valid config and a mount
|
||
|
// which is being used with fscrypt.
|
||
|
func (ctx *Context) checkContext() error {
|
||
|
if err := ctx.Config.CheckValidity(); err != nil {
|
||
|
return &ErrBadConfig{ctx.Config, err}
|
||
|
}
|
||
|
return ctx.Mount.CheckSetup(ctx.TrustedUser)
|
||
|
}
|
||
|
|
||
|
func (ctx *Context) getKeyringOptions() *keyring.Options {
|
||
|
return &keyring.Options{
|
||
|
Mount: ctx.Mount,
|
||
|
User: ctx.TargetUser,
|
||
|
UseFsKeyringForV1Policies: ctx.Config.GetUseFsKeyringForV1Policies(),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// getProtectorOption returns the ProtectorOption for the protector on the
|
||
|
// context's mountpoint with the specified descriptor.
|
||
|
func (ctx *Context) getProtectorOption(protectorDescriptor string) *ProtectorOption {
|
||
|
mnt, data, err := ctx.Mount.GetProtector(protectorDescriptor, ctx.TrustedUser)
|
||
|
if err != nil {
|
||
|
return &ProtectorOption{ProtectorInfo{}, nil, err}
|
||
|
}
|
||
|
|
||
|
info := ProtectorInfo{data}
|
||
|
// No linked path if on the same mountpoint
|
||
|
if mnt == ctx.Mount {
|
||
|
return &ProtectorOption{info, nil, nil}
|
||
|
}
|
||
|
return &ProtectorOption{info, mnt, nil}
|
||
|
}
|
||
|
|
||
|
// ProtectorOptions creates a slice of all the options for all of the Protectors
|
||
|
// on the Context's mountpoint.
|
||
|
func (ctx *Context) ProtectorOptions() ([]*ProtectorOption, error) {
|
||
|
if err := ctx.checkContext(); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
descriptors, err := ctx.Mount.ListProtectors(ctx.TrustedUser)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
options := make([]*ProtectorOption, len(descriptors))
|
||
|
for i, descriptor := range descriptors {
|
||
|
options[i] = ctx.getProtectorOption(descriptor)
|
||
|
}
|
||
|
return options, nil
|
||
|
}
|