Merge "websocket: Do not serialize accepts."
diff --git a/cmd/principal/doc.go b/cmd/principal/doc.go
index 93a5977..9ffcd6d 100644
--- a/cmd/principal/doc.go
+++ b/cmd/principal/doc.go
@@ -223,7 +223,7 @@
The principal dump flags are:
-s=false
- If true, show a only the default blessing names
+ If true, show only the default blessing names
Principal Dumpblessings
@@ -389,6 +389,7 @@
The principal get commands are:
default Return blessings marked as default
forpeer Return blessings marked for the provided peer
+ publickey Prints the public key of the principal.
recognizedroots Return recognized blessings, and their associated public key.
peermap Shows the map from peer pattern to which blessing name to
present.
@@ -396,22 +397,29 @@
Principal Get Default
Returns blessings that are marked as default in the BlessingStore specified by
-the environment that this tool is running in.
+the environment that this tool is running in. Providing --names will print the
+default blessings' chain names. Providing --rootkey <chain_name> will print the
+root key of the certificate chain with chain_name. Providing --caveats
+<chain_name> will print the caveats on the certificate chain with chain_name.
Usage:
principal get default [flags]
The principal get default flags are:
- -name=false
+ -caveats=
+ Shows the caveats on the provided certificate chain name.
+ -names=false
If true, shows the value of the blessing name to be presented to the peer
- -rootkey=false
- If true, shows the value of the root key of the certificate chain to be
- presented to the peer
+ -rootkey=
+ Shows the value of the root key of the provided certificate chain name.
Principal Get Forpeer
Returns blessings that are marked for the provided peer in the BlessingStore
-specified by the environment that this tool is running in.
+specified by the environment that this tool is running in. Providing --names
+will print the blessings' chain names. Providing --rootkey <chain_name> will
+print the root key of the certificate chain with chain_name. Providing --caveats
+<chain_name> will print the caveats on the certificate chain with chain_name.
Usage:
principal get forpeer [flags] [<peer_1> ... <peer_k>]
@@ -423,11 +431,20 @@
the "..." pattern).
The principal get forpeer flags are:
- -name=false
+ -caveats=
+ Shows the caveats on the provided certificate chain name.
+ -names=false
If true, shows the value of the blessing name to be presented to the peer
- -rootkey=false
- If true, shows the value of the root key of the certificate chain to be
- presented to the peer
+ -rootkey=
+ Shows the value of the root key of the provided certificate chain name.
+
+Principal Get Publickey
+
+Prints out the public key of the principal specified by the environment that
+this tool is running in.
+
+Usage:
+ principal get publickey
Principal Get Recognizedroots
diff --git a/cmd/principal/main.go b/cmd/principal/main.go
index e6f2a6b..5aa4ae8 100644
--- a/cmd/principal/main.go
+++ b/cmd/principal/main.go
@@ -18,6 +18,7 @@
"io/ioutil"
"os"
"os/user"
+ "strings"
"time"
"v.io/v23"
@@ -68,12 +69,14 @@
flagRecvBlessingsSetDefault bool
flagRecvBlessingsForPeer string
- // Flags for the commands the get blessings
- flagBlessingsName bool
- flagBlessingsRootKey bool
+ // Flags for the commands that get blessings
+ flagBlessingsNames bool
+ flagBlessingsRootKey string
+ flagBlessingsCaveats string
errNoCaveats = fmt.Errorf("no caveats provided: it is generally dangerous to bless another principal without any caveats as that gives them almost unrestricted access to the blesser's credentials. If you really want to do this, set --require-caveats=false")
- cmdDump = &cmdline.Command{
+
+ cmdDump = &cmdline.Command{
Name: "dump",
Short: "Dump out information about the principal",
Long: `
@@ -286,6 +289,22 @@
},
}
+ cmdGetPublicKey = &cmdline.Command{
+ Name: "publickey",
+ Short: "Prints the public key of the principal.",
+ Long: `
+Prints out the public key of the principal specified by the environment
+that this tool is running in.
+`,
+ Run: func(cmd *cmdline.Command, args []string) error {
+ ctx, shutdown := v23.Init()
+ defer shutdown()
+ p := v23.GetPrincipal(ctx)
+ fmt.Println(p.PublicKey())
+ return nil
+ },
+ }
+
cmdGetTrustedRoots = &cmdline.Command{
Name: "recognizedroots",
Short: "Return recognized blessings, and their associated public key.",
@@ -327,6 +346,11 @@
Returns blessings that are marked for the provided peer in the
BlessingStore specified by the environment that this tool is
running in.
+Providing --names will print the blessings' chain names.
+Providing --rootkey <chain_name> will print the root key of the certificate chain
+with chain_name.
+Providing --caveats <chain_name> will print the caveats on the certificate chain
+with chain_name.
`,
ArgsName: "[<peer_1> ... <peer_k>]",
ArgsLong: `
@@ -349,6 +373,11 @@
Long: `
Returns blessings that are marked as default in the BlessingStore specified by
the environment that this tool is running in.
+Providing --names will print the default blessings' chain names.
+Providing --rootkey <chain_name> will print the root key of the certificate chain
+with chain_name.
+Providing --caveats <chain_name> will print the caveats on the certificate chain
+with chain_name.
`,
Run: func(cmd *cmdline.Command, args []string) error {
ctx, shutdown := v23.Init()
@@ -846,7 +875,7 @@
cmdBlessSelf.Flags.Var(&flagBlessSelfCaveats, "caveat", flagBlessSelfCaveats.usage())
cmdBlessSelf.Flags.DurationVar(&flagBlessSelfFor, "for", 0, "Duration of blessing validity (zero implies no expiration)")
- cmdDump.Flags.BoolVar(&flagDumpShort, "s", false, "If true, show a only the default blessing names")
+ cmdDump.Flags.BoolVar(&flagDumpShort, "s", false, "If true, show only the default blessing names")
cmdFork.Flags.BoolVar(&flagCreateOverwrite, "overwrite", false, "If true, any existing principal data in the directory will be overwritten")
cmdFork.Flags.Var(&flagForkCaveats, "caveat", flagForkCaveats.usage())
@@ -878,11 +907,13 @@
cmdRecvBlessings.Flags.StringVar(&flagRecvBlessingsForPeer, "for-peer", string(security.AllPrincipals), "If non-empty, the blessings received will be marked for peers matching this pattern in the store")
cmdRecvBlessings.Flags.StringVar(&flagRemoteArgFile, "remote-arg-file", "", "If non-empty, the remote key, remote token, and principal will be written to the specified file in a JSON object. This can be provided to 'principal bless --remote-arg-file FILE EXTENSION'")
- cmdGetForPeer.Flags.BoolVar(&flagBlessingsName, "name", false, "If true, shows the value of the blessing name to be presented to the peer")
- cmdGetForPeer.Flags.BoolVar(&flagBlessingsRootKey, "rootkey", false, "If true, shows the value of the root key of the certificate chain to be presented to the peer")
+ cmdGetForPeer.Flags.BoolVar(&flagBlessingsNames, "names", false, "If true, shows the value of the blessing name to be presented to the peer")
+ cmdGetForPeer.Flags.StringVar(&flagBlessingsRootKey, "rootkey", "", "Shows the value of the root key of the provided certificate chain name.")
+ cmdGetForPeer.Flags.StringVar(&flagBlessingsCaveats, "caveats", "", "Shows the caveats on the provided certificate chain name.")
- cmdGetDefault.Flags.BoolVar(&flagBlessingsName, "name", false, "If true, shows the value of the blessing name to be presented to the peer")
- cmdGetDefault.Flags.BoolVar(&flagBlessingsRootKey, "rootkey", false, "If true, shows the value of the root key of the certificate chain to be presented to the peer")
+ cmdGetDefault.Flags.BoolVar(&flagBlessingsNames, "names", false, "If true, shows the value of the blessing name to be presented to the peer")
+ cmdGetDefault.Flags.StringVar(&flagBlessingsRootKey, "rootkey", "", "Shows the value of the root key of the provided certificate chain name.")
+ cmdGetDefault.Flags.StringVar(&flagBlessingsCaveats, "caveats", "", "Shows the caveats on the provided certificate chain name.")
cmdSet := &cmdline.Command{
Name: "set",
@@ -904,7 +935,7 @@
All blessings are printed to stdout using base64-VOM-encoding.
`,
- Children: []*cmdline.Command{cmdGetDefault, cmdGetForPeer, cmdGetTrustedRoots, cmdGetPeerMap},
+ Children: []*cmdline.Command{cmdGetDefault, cmdGetForPeer, cmdGetPublicKey, cmdGetTrustedRoots, cmdGetPeerMap},
}
root := &cmdline.Command{
@@ -942,20 +973,82 @@
if blessings.IsZero() {
return fmt.Errorf("no blessings found")
}
- if flagBlessingsName {
- fmt.Println(blessings)
+ if flagBlessingsNames {
+ fmt.Println(strings.Replace(fmt.Sprint(blessings), ",", "\n", -1))
return nil
- } else if flagBlessingsRootKey {
- wire, err := blessings2wire(blessings)
+ } else if len(flagBlessingsRootKey) > 0 {
+ chain, err := getChainByName(blessings, flagBlessingsRootKey)
if err != nil {
return err
}
- fmt.Println(rootkey(wire.CertificateChains[0]))
+ fmt.Println(rootkey(chain))
+ return nil
+ } else if len(flagBlessingsCaveats) > 0 {
+ chain, err := getChainByName(blessings, flagBlessingsCaveats)
+ if err != nil {
+ return err
+ }
+ cavs, err := prettyPrintCaveats(chain)
+ if err != nil {
+ return err
+ }
+ for _, c := range cavs {
+ fmt.Println(c)
+ }
return nil
}
return dumpBlessings(blessings)
}
+func prettyPrintCaveats(chain []security.Certificate) ([]string, error) {
+ var cavs []security.Caveat
+ for _, cert := range chain {
+ cavs = append(cavs, cert.Caveats...)
+ }
+ var s []string
+ for _, cav := range cavs {
+ if cav.Id == security.PublicKeyThirdPartyCaveatX.Id {
+ c := cav.ThirdPartyDetails()
+ s = append(s, fmt.Sprintf("ThirdPartyCaveat: Requires discharge from %v (ID=%q)", c.Location(), c.ID()))
+ continue
+ }
+ var param interface{}
+ if err := vom.Decode(cav.ParamVom, ¶m); err != nil {
+ return nil, err
+ }
+ switch cav.Id {
+ case security.ConstCaveat.Id:
+ // In the case a ConstCaveat is specified, we only want to print it
+ // if it never validates.
+ if !param.(bool) {
+ s = append(s, fmt.Sprintf("Never validates"))
+ }
+ case security.ExpiryCaveatX.Id:
+ s = append(s, fmt.Sprintf("Expires at %v", param))
+ case security.MethodCaveatX.Id:
+ s = append(s, fmt.Sprintf("Restricted to methods %v", param))
+ case security.PeerBlessingsCaveat.Id:
+ s = append(s, fmt.Sprintf("Restricted to peers with blessings %v", param))
+ default:
+ s = append(s, cav.String())
+ }
+ }
+ return s, nil
+}
+
+func getChainByName(b security.Blessings, name string) ([]security.Certificate, error) {
+ wire, err := blessings2wire(b)
+ if err != nil {
+ return nil, err
+ }
+ for _, chain := range wire.CertificateChains {
+ if chainName(chain) == name {
+ return chain, nil
+ }
+ }
+ return nil, fmt.Errorf("no chains of name %v in %v", name, b)
+}
+
func read(fname string) (string, error) {
if len(fname) == 0 {
return "", nil
@@ -1010,6 +1103,14 @@
return fmt.Sprintf("%v", key)
}
+func chainName(chain []security.Certificate) string {
+ exts := make([]string, len(chain))
+ for i, cert := range chain {
+ exts[i] = cert.Extension
+ }
+ return strings.Join(exts, security.ChainSeparator)
+}
+
func base64VomEncode(i interface{}) (string, error) {
buf := &bytes.Buffer{}
closer := base64.NewEncoder(base64.URLEncoding, buf)
diff --git a/cmd/principal/principal_v23_test.go b/cmd/principal/principal_v23_test.go
index 1f3cef1..04f9fa3 100644
--- a/cmd/principal/principal_v23_test.go
+++ b/cmd/principal/principal_v23_test.go
@@ -72,14 +72,14 @@
aliceDir = filepath.Join(outputDir, "alice")
aliceFriend = filepath.Join(outputDir, "alice.bless")
bobDir = filepath.Join(outputDir, "bob")
- bobForPeer = filepath.Join(outputDir, "bob.store.forpeer")
+ bobForPeer = filepath.Join(outputDir, "bob.get.forpeer")
)
// Create two principals: alice and bob.
bin.Start("create", aliceDir, "alice").WaitOrDie(os.Stdout, os.Stderr)
bin.Start("create", bobDir, "bob").WaitOrDie(os.Stdout, os.Stderr)
- // Bless Alice with Bob's principal.
+ // Bless Bob with Alice's principal.
blessEnv := credEnv(aliceDir)
redirect(t, bin.WithEnv(blessEnv).Start("bless", "--for=1m", bobDir, "friend"), aliceFriend)
@@ -99,7 +99,30 @@
(0) ExpiryCaveat
`
if want != got {
- t.Fatalf("unexpected output, got\n%s, wanted\n%s", got, want)
+ t.Errorf("unexpected output, got\n%s, wanted\n%s", got, want)
+ }
+
+ // Test the names flag.
+ got = bin.WithEnv(blessEnv).Start("--v23.credentials="+bobDir, "get", "forpeer", "--names", "alice/server").Output()
+ want = `bob
+alice/friend
+`
+ if got != want {
+ t.Errorf("unexpected output, got %s, want %s", got, want)
+ }
+
+ // Test the rootkey flag. In particular alice/friend's rootkey should be equal to alice's publickey.
+ got = bin.WithEnv(blessEnv).Start("--v23.credentials="+bobDir, "get", "forpeer", "--rootkey", "alice/friend", "alice/server").Output()
+ want = bin.WithEnv(blessEnv).Start("get", "publickey").Output()
+ if got != want {
+ t.Errorf("unexpected output, got %s, want %s", got, want)
+ }
+
+ // Test the caveats flag.
+ got = bin.WithEnv(blessEnv).Start("--v23.credentials="+bobDir, "get", "forpeer", "--caveats", "alice/friend", "alice/server").Output()
+ want = "Expires at"
+ if !strings.HasPrefix(got, want) {
+ t.Errorf("unexpected output, got %s, want %s", got, want)
}
}
@@ -157,7 +180,7 @@
bin.Start("create", aliceDir, "alice").WaitOrDie(os.Stdout, os.Stderr)
blessEnv := credEnv(aliceDir)
- got := removePublicKeys(bin.WithEnv(blessEnv).Start("get", "peermap").Output())
+ got := bin.WithEnv(blessEnv).Start("get", "peermap").Output()
want := `Default Blessings alice
Peer pattern Blessings
... alice
diff --git a/cmd/vrun/vrun.go b/cmd/vrun/vrun.go
index d6524e5..5f3d8f1 100644
--- a/cmd/vrun/vrun.go
+++ b/cmd/vrun/vrun.go
@@ -20,7 +20,7 @@
"v.io/x/lib/cmdline"
"v.io/x/lib/vlog"
"v.io/x/ref/envvar"
- "v.io/x/ref/services/agent"
+ "v.io/x/ref/services/agent/agentlib"
"v.io/x/ref/services/agent/keymgr"
"v.io/x/ref/services/role"
@@ -121,7 +121,7 @@
func doExec(cmd []string, conn *os.File) error {
envvar.ClearCredentials()
- os.Setenv(agent.FdVarName, "3")
+ os.Setenv(agentlib.FdVarName, "3")
if conn.Fd() != 3 {
if err := syscall.Dup2(int(conn.Fd()), 3); err != nil {
vlog.Errorf("Couldn't dup fd")
@@ -159,7 +159,7 @@
return nil, nil, err
}
syscall.CloseOnExec(fd)
- principal, err := agent.NewAgentPrincipal(ctx, fd, v23.GetClient(ctx))
+ principal, err := agentlib.NewAgentPrincipal(ctx, fd, v23.GetClient(ctx))
if err != nil {
vlog.Errorf("Couldn't connect to principal")
return nil, nil, err
diff --git a/profiles/internal/rt/security.go b/profiles/internal/rt/security.go
index 8f350c2..1b99d5c 100644
--- a/profiles/internal/rt/security.go
+++ b/profiles/internal/rt/security.go
@@ -18,7 +18,7 @@
"v.io/x/ref/lib/exec"
"v.io/x/ref/lib/mgmt"
vsecurity "v.io/x/ref/lib/security"
- "v.io/x/ref/services/agent"
+ "v.io/x/ref/services/agent/agentlib"
)
func initSecurity(ctx *context.T, credentials string, client rpc.Client) (security.Principal, error) {
@@ -80,7 +80,7 @@
// We were started by a parent (presumably, device manager).
fd, _ = handle.Config.Get(mgmt.SecurityAgentFDConfigKey)
} else {
- fd = os.Getenv(agent.FdVarName)
+ fd = os.Getenv(agentlib.FdVarName)
}
if fd == "" {
return -1, nil
@@ -117,5 +117,5 @@
if err != nil {
return nil, err
}
- return agent.NewAgentPrincipal(ctx, newfd, client)
+ return agentlib.NewAgentPrincipal(ctx, newfd, client)
}
diff --git a/services/agent/agentd/main.go b/services/agent/agentd/main.go
index 60bccd3..f5d69e0 100644
--- a/services/agent/agentd/main.go
+++ b/services/agent/agentd/main.go
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// Daemon agentd holds a private key in memory and makes it available to a
+// subprocess via the agent protocol.
package main
import (
@@ -23,8 +25,8 @@
"v.io/x/ref/envvar"
vsecurity "v.io/x/ref/lib/security"
vsignals "v.io/x/ref/lib/signals"
- "v.io/x/ref/services/agent"
- "v.io/x/ref/services/agent/server"
+ "v.io/x/ref/services/agent/agentlib"
+ "v.io/x/ref/services/agent/internal/server"
_ "v.io/x/ref/profiles"
)
@@ -108,7 +110,7 @@
vlog.Panic("failed to set principal for ctx: %v", err)
}
- if err = os.Setenv(agent.FdVarName, "3"); err != nil {
+ if err = os.Setenv(agentlib.FdVarName, "3"); err != nil {
vlog.Fatalf("setenv: %v", err)
}
diff --git a/services/agent/agent_test.go b/services/agent/agentlib/agent_test.go
similarity index 96%
rename from services/agent/agent_test.go
rename to services/agent/agentlib/agent_test.go
index 2c3c17d..a8a70e5 100644
--- a/services/agent/agent_test.go
+++ b/services/agent/agentlib/agent_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package agent_test
+package agentlib_test
import (
"fmt"
@@ -17,8 +17,8 @@
"v.io/v23"
"v.io/v23/context"
"v.io/v23/security"
- "v.io/x/ref/services/agent"
- "v.io/x/ref/services/agent/server"
+ "v.io/x/ref/services/agent/agentlib"
+ "v.io/x/ref/services/agent/internal/server"
"v.io/x/ref/test"
"v.io/x/ref/test/modules"
"v.io/x/ref/test/testutil"
@@ -44,9 +44,9 @@
return nil, err
}
if cached {
- return agent.NewAgentPrincipal(ctx, fd, v23.GetClient(ctx))
+ return agentlib.NewAgentPrincipal(ctx, fd, v23.GetClient(ctx))
} else {
- return agent.NewUncachedPrincipal(ctx, fd, v23.GetClient(ctx))
+ return agentlib.NewUncachedPrincipal(ctx, fd, v23.GetClient(ctx))
}
}
diff --git a/services/agent/agent_v23_test.go b/services/agent/agentlib/agent_v23_test.go
similarity index 99%
rename from services/agent/agent_v23_test.go
rename to services/agent/agentlib/agent_v23_test.go
index 33f60eb..daa9185 100644
--- a/services/agent/agent_v23_test.go
+++ b/services/agent/agentlib/agent_v23_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package agent_test
+package agentlib_test
import (
"bytes"
diff --git a/services/agent/client.go b/services/agent/agentlib/client.go
similarity index 97%
rename from services/agent/client.go
rename to services/agent/agentlib/client.go
index 64cd670..f6aaeba 100644
--- a/services/agent/client.go
+++ b/services/agent/agentlib/client.go
@@ -2,9 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Package agent provides a client for communicating with an "Agent"
-// process holding the private key for an identity.
-package agent
+// Package agentlib implements a client for communicating with an agentd process
+// holding the private key for an identity.
+package agentlib
import (
"fmt"
diff --git a/services/agent/peer_test.go b/services/agent/agentlib/peer_test.go
similarity index 95%
rename from services/agent/peer_test.go
rename to services/agent/agentlib/peer_test.go
index 3c5ff13..ea5959d 100644
--- a/services/agent/peer_test.go
+++ b/services/agent/agentlib/peer_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package agent
+package agentlib
import (
"v.io/v23/context"
diff --git a/services/agent/v23_test.go b/services/agent/agentlib/v23_test.go
similarity index 97%
rename from services/agent/v23_test.go
rename to services/agent/agentlib/v23_test.go
index a6b4044..3e4061b 100644
--- a/services/agent/v23_test.go
+++ b/services/agent/agentlib/v23_test.go
@@ -4,7 +4,7 @@
// This file was auto-generated via go generate.
// DO NOT UPDATE MANUALLY
-package agent_test
+package agentlib_test
import "fmt"
import "testing"
diff --git a/services/agent/server/server.go b/services/agent/internal/server/server.go
similarity index 97%
rename from services/agent/server/server.go
rename to services/agent/internal/server/server.go
index 6710b1a..46b5e0b 100644
--- a/services/agent/server/server.go
+++ b/services/agent/internal/server/server.go
@@ -26,12 +26,13 @@
"v.io/v23/verror"
"v.io/x/lib/vlog"
vsecurity "v.io/x/ref/lib/security"
+ "v.io/x/ref/services/agent"
"v.io/x/ref/services/agent/internal/unixfd"
)
const PrincipalHandleByteSize = sha512.Size
-const pkgPath = "v.io/x/ref/services/agent/server"
+const pkgPath = "v.io/x/ref/services/agent/internal/server"
// Errors
var (
@@ -261,9 +262,8 @@
}
spec := rpc.ListenSpec{Addrs: rpc.ListenAddrs(a)}
if _, err = s.Listen(spec); err == nil {
- agent := &agentd{w.newID(), w, principal, ctx}
- serverAgent := AgentServer(agent)
- err = s.Serve("", serverAgent, nil)
+ server := agent.AgentServer(&agentd{w.newID(), w, principal, ctx})
+ err = s.Serve("", server, nil)
}
ack()
}
@@ -430,7 +430,7 @@
return a.principal.Roots().DebugString(), nil
}
-func (a agentd) NotifyWhenChanged(call AgentNotifyWhenChangedServerCall) error {
+func (a agentd) NotifyWhenChanged(call agent.AgentNotifyWhenChangedServerCall) error {
ch := a.w.register(a.id)
defer a.w.unregister(a.id, ch)
for {
diff --git a/services/agent/server/sharing.go b/services/agent/internal/server/sharing.go
similarity index 100%
rename from services/agent/server/sharing.go
rename to services/agent/internal/server/sharing.go
diff --git a/services/agent/server/sharing_test.go b/services/agent/internal/server/sharing_test.go
similarity index 100%
rename from services/agent/server/sharing_test.go
rename to services/agent/internal/server/sharing_test.go
diff --git a/services/agent/internal/test_principal/main.go b/services/agent/internal/test_principal/main.go
index d60f430..06bbc52 100644
--- a/services/agent/internal/test_principal/main.go
+++ b/services/agent/internal/test_principal/main.go
@@ -16,7 +16,7 @@
"v.io/v23"
"v.io/v23/security"
"v.io/x/ref/envvar"
- "v.io/x/ref/services/agent"
+ "v.io/x/ref/services/agent/agentlib"
_ "v.io/x/ref/profiles"
)
@@ -56,8 +56,8 @@
if got := os.Getenv(envvar.Credentials); len(got) != 0 {
errorf("%v environment variable is unexpectedly set", envvar.Credentials)
}
- if got := os.Getenv(agent.FdVarName); len(got) == 0 {
- errorf("%v environment variable is not set", agent.FdVarName)
+ if got := os.Getenv(agentlib.FdVarName); len(got) == 0 {
+ errorf("%v environment variable is not set", agentlib.FdVarName)
}
// A pristine agent has a single blessing "agent_principal" (from agentd/main.go).
if blessings := p.BlessingsInfo(p.BlessingStore().Default()); len(blessings) != 1 {
diff --git a/services/agent/keymgr/client.go b/services/agent/keymgr/client.go
index d6c34a3..01098de 100644
--- a/services/agent/keymgr/client.go
+++ b/services/agent/keymgr/client.go
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Package keymgr provides a client for the Device Manager to manage keys in
-// the "Agent" process.
+// Package keymgr implements a client for deviced to manage keys in the agentd
+// process.
package keymgr
import (
@@ -14,8 +14,8 @@
"v.io/v23/context"
"v.io/v23/verror"
+ "v.io/x/ref/services/agent/internal/server"
"v.io/x/ref/services/agent/internal/unixfd"
- "v.io/x/ref/services/agent/server"
)
const pkgPath = "v.io/x/ref/services/agent/keymgr"
diff --git a/services/agent/keymgr/keymgr_test.go b/services/agent/keymgr/keymgr_test.go
index 1e2a521..15348b6 100644
--- a/services/agent/keymgr/keymgr_test.go
+++ b/services/agent/keymgr/keymgr_test.go
@@ -15,8 +15,8 @@
"v.io/v23"
"v.io/v23/context"
"v.io/v23/security"
- "v.io/x/ref/services/agent"
- "v.io/x/ref/services/agent/server"
+ "v.io/x/ref/services/agent/agentlib"
+ "v.io/x/ref/services/agent/internal/server"
"v.io/x/ref/test"
_ "v.io/x/ref/profiles"
@@ -72,7 +72,7 @@
return nil, err
}
- return agent.NewAgentPrincipal(ctx, fd, v23.GetClient(ctx))
+ return agentlib.NewAgentPrincipal(ctx, fd, v23.GetClient(ctx))
}
func TestSigning(t *testing.T) {
diff --git a/services/agent/server/wire.vdl b/services/agent/wire.vdl
similarity index 95%
rename from services/agent/server/wire.vdl
rename to services/agent/wire.vdl
index c025f6f..4c93acb 100644
--- a/services/agent/server/wire.vdl
+++ b/services/agent/wire.vdl
@@ -2,10 +2,10 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Package server provides a server which keeps a principal in memory
-// and allows clients to use that principal.
+// Package agent defines an interface to keep a private key in memory, and for
+// clients to have access to the private key.
//
-// PROTOCOL
+// Protocol
//
// The agent starts processes with the VEYRON_AGENT_FD set to one end of a
// unix domain socket. To connect to the agent, a client should create
@@ -30,9 +30,7 @@
// The protocol also has limited support for caching: A client can
// request notification when any other client modifies the principal so it
// can flush the cache. See NotifyWhenChanged for details.
-
-
-package server
+package agent
import (
"v.io/v23/security"
diff --git a/services/agent/server/wire.vdl.go b/services/agent/wire.vdl.go
similarity index 93%
rename from services/agent/server/wire.vdl.go
rename to services/agent/wire.vdl.go
index 16af73a..f01c204 100644
--- a/services/agent/server/wire.vdl.go
+++ b/services/agent/wire.vdl.go
@@ -5,7 +5,35 @@
// This file was auto-generated by the vanadium vdl tool.
// Source: wire.vdl
-package server
+// Package agent defines an interface to keep a private key in memory, and for
+// clients to have access to the private key.
+//
+// Protocol
+//
+// The agent starts processes with the VEYRON_AGENT_FD set to one end of a
+// unix domain socket. To connect to the agent, a client should create
+// a unix domain socket pair. Then send one end of the socket to the agent
+// with 1 byte of data. The agent will then serve the Agent service on
+// the received socket, using SecurityNone.
+//
+// The agent also supports an optional mode where it can manage multiple principals.
+// Typically this is only used by Device Manager. In this mode, VEYRON_AGENT_FD
+// will be 3, and there will be another socket at fd 4.
+// Creating a new principal is similar to connecting to to agent: create a socket
+// pair and send one end on fd 4 with 1 byte of data.
+// Set the data to 1 to request the principal only be stored in memory.
+// The agent will create a new principal and respond with a principal handle on fd 4.
+// To connect using a previously created principal, create a socket pair and send
+// one end with the principal handle as data on fd 4. The agent will not send a
+// response on fd 4.
+// In either, you can use the normal process to connect to an agent over the
+// other end of the pair. Typically you would pass the other end to a child
+// process and set VEYRON_AGENT_FD so it knows to connect.
+//
+// The protocol also has limited support for caching: A client can
+// request notification when any other client modifies the principal so it
+// can flush the cache. See NotifyWhenChanged for details.
+package agent
import (
// VDL system imports
@@ -393,7 +421,7 @@
// descAgent hides the desc to keep godoc clean.
var descAgent = rpc.InterfaceDesc{
Name: "Agent",
- PkgPath: "v.io/x/ref/services/agent/server",
+ PkgPath: "v.io/x/ref/services/agent",
Methods: []rpc.MethodDesc{
{
Name: "Bless",
diff --git a/services/device/internal/impl/app_service.go b/services/device/internal/impl/app_service.go
index 8e3926a..d5c9a5a 100644
--- a/services/device/internal/impl/app_service.go
+++ b/services/device/internal/impl/app_service.go
@@ -153,7 +153,7 @@
vexec "v.io/x/ref/lib/exec"
"v.io/x/ref/lib/mgmt"
vsecurity "v.io/x/ref/lib/security"
- "v.io/x/ref/services/agent"
+ "v.io/x/ref/services/agent/agentlib"
"v.io/x/ref/services/agent/keymgr"
"v.io/x/ref/services/device/internal/config"
"v.io/x/ref/services/internal/acls"
@@ -516,7 +516,7 @@
conn.Close()
return nil, nil, err
}
- p, err := agent.NewAgentPrincipal(agentctx, int(conn.Fd()), v23.GetClient(agentctx))
+ p, err := agentlib.NewAgentPrincipal(agentctx, int(conn.Fd()), v23.GetClient(agentctx))
if err != nil {
cancel()
conn.Close()
diff --git a/services/device/internal/impl/dispatcher.go b/services/device/internal/impl/dispatcher.go
index da5a9a2..88679c1 100644
--- a/services/device/internal/impl/dispatcher.go
+++ b/services/device/internal/impl/dispatcher.go
@@ -25,7 +25,7 @@
"v.io/v23/vdlroot/signature"
"v.io/v23/verror"
"v.io/x/lib/vlog"
- "v.io/x/ref/services/agent"
+ "v.io/x/ref/services/agent/agentlib"
"v.io/x/ref/services/agent/keymgr"
s_device "v.io/x/ref/services/device"
"v.io/x/ref/services/device/internal/config"
@@ -137,7 +137,7 @@
}
// If we're in 'security agent mode', set up the key manager agent.
- if len(os.Getenv(agent.FdVarName)) > 0 {
+ if len(os.Getenv(agentlib.FdVarName)) > 0 {
if keyMgrAgent, err := keymgr.NewAgent(); err != nil {
return nil, verror.New(errNewAgentFailed, ctx, err)
} else {
diff --git a/services/mounttable/mounttablelib/mounttable.go b/services/mounttable/mounttablelib/mounttable.go
index 8bd6e21..7fbcf7e 100644
--- a/services/mounttable/mounttablelib/mounttable.go
+++ b/services/mounttable/mounttablelib/mounttable.go
@@ -778,7 +778,7 @@
ch <- naming.GlobReplyEntry{naming.MountEntry{Name: "", Servers: servers}}
}
-func (ms *mountContext) SetPermissions(call rpc.ServerCall, tam access.Permissions, version string) error {
+func (ms *mountContext) SetPermissions(call rpc.ServerCall, perms access.Permissions, version string) error {
vlog.VI(2).Infof("SetPermissions %q", ms.name)
mt := ms.mt
@@ -793,7 +793,22 @@
}
n.parent.Unlock()
defer n.Unlock()
- n.acls, err = n.acls.Set(version, tam)
+
+ // If the caller is trying to add a Permission that they are no longer Admin in,
+ // retain the caller's blessings that were in Admin to prevent them from locking themselves out.
+ bnames, _ := security.RemoteBlessingNames(call.Context())
+ if acl, ok := perms[string(mounttable.Admin)]; !ok || !acl.Includes(bnames...) {
+ _, oldPerms := n.acls.Get()
+ oldAcl := oldPerms[string(mounttable.Admin)]
+ for _, bname := range bnames {
+ if oldAcl.Includes(bname) {
+ perms.Add(security.BlessingPattern(bname), string(mounttable.Admin))
+ }
+ }
+ }
+ perms.Normalize()
+
+ n.acls, err = n.acls.Set(version, perms)
if err == nil {
n.explicitAccessLists = true
}
diff --git a/services/mounttable/mounttablelib/mounttable_test.go b/services/mounttable/mounttablelib/mounttable_test.go
index b3a9594..fdb08c2 100644
--- a/services/mounttable/mounttablelib/mounttable_test.go
+++ b/services/mounttable/mounttablelib/mounttable_test.go
@@ -279,6 +279,26 @@
doSetPermissions(t, aliceCtx, mtAddr, "onlybob", acl, "", false)
doSetPermissions(t, bobCtx, mtAddr, "onlybob", acl, "", true)
+ // Test that setting Permissions to an acl that don't include the the setter's
+ // blessings in Admin, automatically add their Blessings to Admin to prevent
+ // locking everyone out.
+ acl, _ = doGetPermissions(t, bobCtx, mtAddr, "onlybob", true)
+ noRootAcl := acl.Copy()
+ noRootAcl.Clear("bob", "Admin")
+ doSetPermissions(t, bobCtx, mtAddr, "onlybob", noRootAcl, "", true)
+ // This should succeed, because "bob" should automatically be added to "Admin"
+ // even though he cleared himself from "Admin".
+ doSetPermissions(t, bobCtx, mtAddr, "onlybob", acl, "", true)
+ // Test that adding a non-standard acl is normalized when retrieved.
+ admin := acl["Admin"]
+ admin.In = []security.BlessingPattern{"bob", "bob"}
+ acl["Admin"] = admin
+ doSetPermissions(t, bobCtx, mtAddr, "onlybob", acl, "", true)
+ acl, _ = doGetPermissions(t, bobCtx, mtAddr, "onlybob", true)
+ if got, want := acl["Admin"].In, []security.BlessingPattern{"bob"}; !reflect.DeepEqual(got, want) {
+ boom(t, "got %v, want %v", got, want)
+ }
+
// Test generic unmount.
vlog.Info("Test generic unmount.")
doUnmount(t, rootCtx, mtAddr, "a/b", "", true)
diff --git a/test/modules/shell.go b/test/modules/shell.go
index 5e669e7..8ae6194 100644
--- a/test/modules/shell.go
+++ b/test/modules/shell.go
@@ -157,7 +157,7 @@
"v.io/v23/security"
"v.io/x/ref/envvar"
"v.io/x/ref/lib/exec"
- "v.io/x/ref/services/agent"
+ "v.io/x/ref/services/agent/agentlib"
"v.io/x/ref/services/agent/keymgr"
"v.io/x/ref/test/expect"
)
@@ -300,7 +300,7 @@
if err != nil {
return nil, err
}
- p, err := agent.NewAgentPrincipal(sh.ctx, fd, v23.GetClient(sh.ctx))
+ p, err := agentlib.NewAgentPrincipal(sh.ctx, fd, v23.GetClient(sh.ctx))
if err != nil {
syscall.Close(fd)
return nil, err
@@ -729,7 +729,7 @@
// want the child to directly use the directory specified
// by the shell's VeyronCredentials.
delete(m1, envvar.Credentials)
- delete(m1, agent.FdVarName)
+ delete(m1, agentlib.FdVarName)
m2 := mergeMaps(m1, evmap)
r := []string{}
diff --git a/test/v23tests/v23tests.go b/test/v23tests/v23tests.go
index 3192ba1..caf7fc9 100644
--- a/test/v23tests/v23tests.go
+++ b/test/v23tests/v23tests.go
@@ -25,7 +25,7 @@
"v.io/v23/security"
"v.io/x/ref/envvar"
- "v.io/x/ref/services/agent"
+ "v.io/x/ref/services/agent/agentlib"
"v.io/x/ref/test"
"v.io/x/ref/test/modules"
"v.io/x/ref/test/testutil"
@@ -340,7 +340,7 @@
}
// Set up agent for Child.
attr.Files = append(attr.Files, agentFile)
- attr.Env = append(attr.Env, fmt.Sprintf("%s=%d", agent.FdVarName, len(attr.Files)-1))
+ attr.Env = append(attr.Env, fmt.Sprintf("%s=%d", agentlib.FdVarName, len(attr.Files)-1))
// Set up environment for Child.
for _, v := range t.shell.Env() {