blob: 3c9973ef980e5ffd55bdacae16134d7e6dbb151a [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
// Commands to get/set Permissions.
import (
"fmt"
"v.io/v23/context"
"v.io/v23/security"
"v.io/v23/security/access"
"v.io/v23/services/device"
"v.io/v23/verror"
"v.io/x/lib/cmdline"
"v.io/x/ref/lib/v23cmd"
)
var cmdGet = &cmdline.Command{
Runner: v23cmd.RunnerFunc(runGet),
Name: "get",
Short: "Get Permissions for the given target.",
Long: "Get Permissions for the given target.",
ArgsName: "<device manager name>",
ArgsLong: `
<device manager name> can be a Vanadium name for a device manager,
application installation or instance.`,
}
func runGet(ctx *context.T, env *cmdline.Env, args []string) error {
if expected, got := 1, len(args); expected != got {
return env.UsageErrorf("get: incorrect number of arguments, expected %d, got %d", expected, got)
}
vanaName := args[0]
objPerms, _, err := device.ApplicationClient(vanaName).GetPermissions(ctx)
if err != nil {
return fmt.Errorf("GetPermissions on %s failed: %v", vanaName, err)
}
// Convert objPerms (Permissions) into permsEntries for pretty printing.
entries := make(permsEntries)
for tag, perms := range objPerms {
for _, p := range perms.In {
entries.Tags(string(p))[tag] = false
}
for _, b := range perms.NotIn {
entries.Tags(b)[tag] = true
}
}
fmt.Fprintln(env.Stdout, entries)
return nil
}
// TODO(caprita): Add unit test logic for 'force set'.
var forceSet bool
var cmdSet = &cmdline.Command{
Runner: v23cmd.RunnerFunc(runSet),
Name: "set",
Short: "Set Permissions for the given target.",
Long: "Set Permissions for the given target",
ArgsName: "<device manager name> (<blessing> [!]<tag>(,[!]<tag>)*",
ArgsLong: `
<device manager name> can be a Vanadium name for a device manager,
application installation or instance.
<blessing> is a blessing pattern.
If the same pattern is repeated multiple times in the command, then
the only the last occurrence will be honored.
<tag> is a subset of defined access types ("Admin", "Read", "Write" etc.).
If the access right is prefixed with a '!' then <blessing> is added to the
NotIn list for that right. Using "^" as a "tag" causes all occurrences of
<blessing> in the current AccessList to be cleared.
Examples:
set root/self ^
will remove "root/self" from the In and NotIn lists for all access rights.
set root/self Read,!Write
will add "root/self" to the In list for Read access and the NotIn list
for Write access (and remove "root/self" from both the In and NotIn
lists of all other access rights)`,
}
func init() {
cmdSet.Flags.BoolVar(&forceSet, "f", false, "Instead of making the AccessLists additive, do a complete replacement based on the specified settings.")
}
func runSet(ctx *context.T, env *cmdline.Env, args []string) error {
if got := len(args); !((got%2) == 1 && got >= 3) {
return env.UsageErrorf("set: incorrect number of arguments %d, must be 1 + 2n", got)
}
vanaName := args[0]
pairs := args[1:]
entries := make(permsEntries)
for i := 0; i < len(pairs); i += 2 {
blessing := pairs[i]
tags, err := parseAccessTags(pairs[i+1])
if err != nil {
return env.UsageErrorf("failed to parse access tags for %q: %v", blessing, err)
}
entries[blessing] = tags
}
// Set the Permissions on the specified names.
for {
objPerms, version := make(access.Permissions), ""
if !forceSet {
var err error
if objPerms, version, err = device.ApplicationClient(vanaName).GetPermissions(ctx); err != nil {
return fmt.Errorf("GetPermissions(%s) failed: %v", vanaName, err)
}
}
for blessingOrPattern, tags := range entries {
objPerms.Clear(blessingOrPattern) // Clear out any existing references
for tag, blacklist := range tags {
if blacklist {
objPerms.Blacklist(blessingOrPattern, tag)
} else {
objPerms.Add(security.BlessingPattern(blessingOrPattern), tag)
}
}
}
switch err := device.ApplicationClient(vanaName).SetPermissions(ctx, objPerms, version); {
case err != nil && verror.ErrorID(err) != verror.ErrBadVersion.ID:
return fmt.Errorf("SetPermissions(%s) failed: %v", vanaName, err)
case err == nil:
return nil
}
fmt.Fprintln(env.Stderr, "WARNING: trying again because of asynchronous change")
}
}
var cmdACL = &cmdline.Command{
Name: "acl",
Short: "Tool for setting device manager Permissions",
Long: `
The acl tool manages Permissions on the device manger, installations and instances.
`,
Children: []*cmdline.Command{cmdGet, cmdSet},
}