Merge "ref: fixing go vet violations"
diff --git a/envvar.go b/envvar.go
index 31ca4bb..bb7af0a 100644
--- a/envvar.go
+++ b/envvar.go
@@ -24,12 +24,20 @@
// See v.io/x/ref/lib/security.CreatePersistentPrincipal.
EnvCredentials = "V23_CREDENTIALS"
+ // EnvAgentPath is the name of the environment variable pointing to an
+ // agentd process containing all the credentials a principal (the blessing
+ // store, the blessing roots, possibly the private key etc.).
+ //
+ // Typically only one of EnvCredentials or EnvAgentPaths will be set in a
+ // process. If both are set, then EnvCredentials takes preference.
+ EnvAgentPath = "V23_AGENT_PATH"
+
// EnvAgentEndpoint is the name of the environment variable pointing to an
// agentd process containing all the credentials a principal (the blessing
// store, the blessing roots, possibly the private key etc.).
//
- // Typically only one of EnvCredentials or EnvAgentEndpoint will be set in a
- // process. If both are set, then EnvCredentials takes preference.
+ // EnvAgentEndpoint is deprecated. New agentd processes should use EnvAgentPath.
+ // If both are set, EnvAgentPath takes preference.
EnvAgentEndpoint = "V23_AGENT_ENDPOINT"
// EnvNamespacePrefix is the prefix of all environment variables that define a
diff --git a/lib/mgmt/model.go b/lib/mgmt/model.go
index 1aa425f..95a667f 100644
--- a/lib/mgmt/model.go
+++ b/lib/mgmt/model.go
@@ -13,6 +13,7 @@
ProtocolConfigKey = "MGMT_CHILD_PROCESS_PROTOCOL"
ParentBlessingConfigKey = "MGMT_PARENT_BLESSING_PEER_PATTERN"
SecurityAgentEndpointConfigKey = "MGMT_SECURITY_AGENT_EP"
+ SecurityAgentPathConfigKey = "MGMT_SECURITY_AGENT_PATH"
AppOriginConfigKey = "MGMT_APP_ORIGIN"
PublisherBlessingPrefixesKey = "MGMT_PUBLISHER_BLESSING_PREFIXES"
InstanceNameKey = "MGMT_INSTANCE_NAME"
diff --git a/runtime/internal/rt/security.go b/runtime/internal/rt/security.go
index 5e439b1..1b8d6cf 100644
--- a/runtime/internal/rt/security.go
+++ b/runtime/internal/rt/security.go
@@ -20,6 +20,7 @@
"v.io/x/ref/lib/mgmt"
vsecurity "v.io/x/ref/lib/security"
inaming "v.io/x/ref/runtime/internal/naming"
+ "v.io/x/ref/services/agent"
"v.io/x/ref/services/agent/agentlib"
)
@@ -48,6 +49,11 @@
return principal, nil, func() {}, nil
}
// Use credentials stored in the agent.
+ if principal, err := ipcAgent(); err != nil {
+ return nil, nil, nil, err
+ } else if principal != nil {
+ return principal, nil, func() { principal.Close() }, nil
+ }
if ep, _, err := agentEP(); err != nil {
return nil, nil, nil, err
} else if ep != nil {
@@ -98,6 +104,24 @@
return ifd, nil
}
+func ipcAgent() (agent.Principal, error) {
+ handle, err := exec.GetChildHandle()
+ if err != nil && verror.ErrorID(err) != exec.ErrNoVersion.ID {
+ return nil, err
+ }
+ var path string
+ if handle != nil {
+ // We were started by a parent (presumably, device manager).
+ path, _ = handle.Config.Get(mgmt.SecurityAgentPathConfigKey)
+ } else {
+ path = os.Getenv(ref.EnvAgentPath)
+ }
+ if path == "" {
+ return nil, nil
+ }
+ return agentlib.NewAgentPrincipalX(path)
+}
+
// agentEP returns an Endpoint to be used to communicate with
// the security agent if the current process has been configured to use the
// agent.
diff --git a/services/agent/agentlib/client.go b/services/agent/agentlib/client.go
index 3f6f82c..1d72439 100644
--- a/services/agent/agentlib/client.go
+++ b/services/agent/agentlib/client.go
@@ -8,9 +8,11 @@
import (
"fmt"
+ "io"
"net"
"os"
"strconv"
+ "sync"
"syscall"
"v.io/v23/context"
@@ -21,7 +23,9 @@
"v.io/v23/verror"
"v.io/v23/vtrace"
"v.io/x/ref/internal/logger"
+ "v.io/x/ref/services/agent"
"v.io/x/ref/services/agent/internal/cache"
+ "v.io/x/ref/services/agent/internal/ipc"
"v.io/x/ref/services/agent/internal/unixfd"
)
@@ -38,13 +42,50 @@
key security.PublicKey
}
-type caller struct {
+type caller interface {
+ call(name string, results []interface{}, args ...interface{}) error
+ io.Closer
+}
+
+type ipcCaller struct {
+ conn *ipc.IPCConn
+ flush func()
+ mu sync.Mutex
+}
+
+func (i *ipcCaller) call(name string, results []interface{}, args ...interface{}) error {
+ return i.conn.Call(name, args, results...)
+}
+
+func (i *ipcCaller) Close() error {
+ i.conn.Close()
+ return nil
+}
+
+func (i *ipcCaller) FlushAllCaches() error {
+ var flush func()
+ i.mu.Lock()
+ flush = i.flush
+ i.mu.Unlock()
+ if flush != nil {
+ flush()
+ }
+ return nil
+}
+
+type vrpcCaller struct {
ctx *context.T
client rpc.Client
name string
+ cancel func()
}
-func (c *caller) call(name string, results []interface{}, args ...interface{}) error {
+func (c *vrpcCaller) Close() error {
+ c.cancel()
+ return nil
+}
+
+func (c *vrpcCaller) call(name string, results []interface{}, args ...interface{}) error {
call, err := c.startCall(name, args...)
if err != nil {
return err
@@ -55,7 +96,7 @@
return nil
}
-func (c *caller) startCall(name string, args ...interface{}) (rpc.ClientCall, error) {
+func (c *vrpcCaller) startCall(name string, args ...interface{}) (rpc.ClientCall, error) {
ctx, _ := vtrace.WithNewTrace(c.ctx)
// SecurityNone is safe here since we're using anonymous unix sockets.
return c.client.StartCall(ctx, c.name, name, args, options.SecurityNone, options.NoResolve{})
@@ -65,6 +106,41 @@
return inputs
}
+func newUncachedPrincipalX(path string) (*client, error) {
+ caller := new(ipcCaller)
+ i := ipc.NewIPC()
+ i.Serve(caller)
+ conn, err := i.Connect(path)
+ if err != nil {
+ return nil, err
+ }
+ caller.conn = conn
+ agent := &client{caller: caller}
+ if err := agent.fetchPublicKey(); err != nil {
+ return nil, err
+ }
+ return agent, nil
+}
+
+// NewAgentPrincipal returns a security.Pricipal using the PrivateKey held in a remote agent process.
+// 'path' is the path to the agent socket, typically obtained from
+// os.GetEnv(envvar.AgentAddress).
+func NewAgentPrincipalX(path string) (agent.Principal, error) {
+ p, err := newUncachedPrincipalX(path)
+ if err != nil {
+ return nil, err
+ }
+ cached, flush, err := cache.NewCachedPrincipalX(p)
+ if err != nil {
+ return nil, err
+ }
+ caller := p.caller.(*ipcCaller)
+ caller.mu.Lock()
+ caller.flush = flush
+ caller.mu.Unlock()
+ return cached, nil
+}
+
// NewAgentPrincipal returns a security.Pricipal using the PrivateKey held in a remote agent process.
// 'endpoint' is the endpoint for connecting to the agent, typically obtained from
// os.GetEnv(envvar.AgentEndpoint).
@@ -75,11 +151,12 @@
if err != nil {
return p, err
}
- call, callErr := p.caller.startCall("NotifyWhenChanged")
+ caller := p.caller.(*vrpcCaller)
+ call, callErr := caller.startCall("NotifyWhenChanged")
if callErr != nil {
return nil, callErr
}
- return cache.NewCachedPrincipal(p.caller.ctx, p, call)
+ return cache.NewCachedPrincipal(caller.ctx, p, call)
}
func newUncachedPrincipal(ctx *context.T, ep naming.Endpoint, insecureClient rpc.Client) (*client, error) {
// This isn't a real vanadium endpoint. It contains the vanadium version
@@ -112,10 +189,12 @@
if err != nil {
return nil, err
}
- caller := caller{
+ ctx, cancel := context.WithCancel(ctx)
+ caller := &vrpcCaller{
client: insecureClient,
name: naming.JoinAddressName(agentEndpoint("unixfd", addr.String()), ""),
ctx: ctx,
+ cancel: cancel,
}
agent := &client{caller: caller}
if err := agent.fetchPublicKey(); err != nil {
@@ -124,6 +203,10 @@
return agent, nil
}
+func (c *client) Close() error {
+ return c.caller.Close()
+}
+
func (c *client) fetchPublicKey() (err error) {
var b []byte
if err = c.caller.call("PublicKey", results(&b)); err != nil {
diff --git a/services/agent/agentlib/peer_test.go b/services/agent/agentlib/peer_test.go
index 99a86a1..3d5ceeb 100644
--- a/services/agent/agentlib/peer_test.go
+++ b/services/agent/agentlib/peer_test.go
@@ -14,3 +14,7 @@
func NewUncachedPrincipal(ctx *context.T, endpoint naming.Endpoint, insecureClient rpc.Client) (security.Principal, error) {
return newUncachedPrincipal(ctx, endpoint, insecureClient)
}
+
+func NewUncachedPrincipalX(path string) (security.Principal, error) {
+ return newUncachedPrincipalX(path)
+}
diff --git a/services/agent/internal/cache/cache.go b/services/agent/internal/cache/cache.go
index 29a518c..f4500a8 100644
--- a/services/agent/internal/cache/cache.go
+++ b/services/agent/internal/cache/cache.go
@@ -12,6 +12,8 @@
"v.io/v23/rpc"
"v.io/v23/security"
"v.io/v23/verror"
+ "v.io/x/ref/internal/logger"
+ "v.io/x/ref/services/agent"
"v.io/x/ref/services/agent/internal/lru"
)
@@ -30,7 +32,6 @@
type cachedRoots struct {
mu *sync.RWMutex
impl security.BlessingRoots
- ctx *context.T
cache map[string][]security.BlessingPattern // GUARDED_BY(mu)
// TODO(ataly): Get rid of the following fields once all agents have been
@@ -39,8 +40,8 @@
negative *lru.Cache // key + blessing -> error
}
-func newCachedRoots(ctx *context.T, impl security.BlessingRoots, mu *sync.RWMutex) (*cachedRoots, error) {
- roots := &cachedRoots{mu: mu, impl: impl, ctx: ctx}
+func newCachedRoots(impl security.BlessingRoots, mu *sync.RWMutex) (*cachedRoots, error) {
+ roots := &cachedRoots{mu: mu, impl: impl}
roots.flush()
if err := roots.fetchAndCacheRoots(); err != nil {
return nil, err
@@ -126,7 +127,7 @@
if !cacheExists {
r.mu.Lock()
if err := r.fetchAndCacheRoots(); err != nil {
- r.ctx.Errorf("failed to cache roots: %v", err)
+ logger.Global().Errorf("failed to cache roots: %v", err)
r.mu.Unlock()
return nil
}
@@ -177,7 +178,7 @@
for keyStr, patterns := range r.cache {
key, err := security.UnmarshalPublicKey([]byte(keyStr))
if err != nil {
- r.ctx.Errorf("security.UnmarshalPublicKey(%v) returned error: %v", []byte(keyStr), err)
+ logger.Global().Errorf("security.UnmarshalPublicKey(%v) returned error: %v", []byte(keyStr), err)
return nil
}
for _, p := range patterns {
@@ -219,7 +220,6 @@
mu *sync.RWMutex
key security.PublicKey
def security.Blessings
- ctx *context.T
hasDef bool
peers map[security.BlessingPattern]security.Blessings
impl security.BlessingStore
@@ -266,7 +266,7 @@
if union, err := security.UnionOfBlessings(ret, b); err == nil {
ret = union
} else {
- s.ctx.Errorf("UnionOfBlessings(%v, %v) failed: %v, dropping the latter from BlessingStore.ForPeers(%v)", ret, b, err, peerBlessings)
+ logger.Global().Errorf("UnionOfBlessings(%v, %v) failed: %v, dropping the latter from BlessingStore.ForPeers(%v)", ret, b, err, peerBlessings)
}
}
}
@@ -341,7 +341,7 @@
// wraps over another implementation and adds caching.
type cachedPrincipal struct {
cache security.Principal
- /* impl */ security.Principal
+ /* impl */ agent.Principal
}
func (p *cachedPrincipal) BlessingsByName(pattern security.BlessingPattern) []security.Blessings {
@@ -364,6 +364,10 @@
return p.cache.AddToRoots(blessings)
}
+func (p *cachedPrincipal) Close() error {
+ return p.Principal.Close()
+}
+
type dummySigner struct {
key security.PublicKey
}
@@ -377,9 +381,32 @@
return s.key
}
-func NewCachedPrincipal(ctx *context.T, impl security.Principal, call rpc.ClientCall) (p security.Principal, err error) {
+func NewCachedPrincipal(ctx *context.T, impl agent.Principal, call rpc.ClientCall) (p agent.Principal, err error) {
+ p, flush, err := NewCachedPrincipalX(impl)
+
+ if err == nil {
+ go func() {
+ var x bool
+ for {
+ if recvErr := call.Recv(&x); recvErr != nil {
+ if ctx.Err() != context.Canceled {
+ logger.Global().Errorf("Error from agent: %v", recvErr)
+ }
+ flush()
+ call.Finish()
+ return
+ }
+ flush()
+ }
+ }()
+ }
+
+ return
+}
+
+func NewCachedPrincipalX(impl agent.Principal) (p agent.Principal, flush func(), err error) {
var mu sync.RWMutex
- cachedRoots, err := newCachedRoots(ctx, impl.Roots(), &mu)
+ cachedRoots, err := newCachedRoots(impl.Roots(), &mu)
if err != nil {
return
}
@@ -387,34 +414,19 @@
mu: &mu,
key: impl.PublicKey(),
impl: impl.BlessingStore(),
- ctx: ctx,
}
- flush := func() {
+ flush = func() {
defer mu.Unlock()
mu.Lock()
cachedRoots.flush()
cachedStore.flush()
}
- p, err = security.CreatePrincipal(dummySigner{impl.PublicKey()}, cachedStore, cachedRoots)
+ sp, err := security.CreatePrincipal(dummySigner{impl.PublicKey()}, cachedStore, cachedRoots)
if err != nil {
return
}
- go func() {
- var x bool
- for {
- if recvErr := call.Recv(&x); recvErr != nil {
- if ctx.Err() != context.Canceled {
- ctx.Errorf("Error from agent: %v", recvErr)
- }
- flush()
- call.Finish()
- return
- }
- flush()
- }
- }()
- p = &cachedPrincipal{p, impl}
+ p = &cachedPrincipal{sp, impl}
return
}
diff --git a/services/agent/internal/cache/cache_test.go b/services/agent/internal/cache/cache_test.go
index b6b53d3..e0c2193 100644
--- a/services/agent/internal/cache/cache_test.go
+++ b/services/agent/internal/cache/cache_test.go
@@ -22,7 +22,7 @@
ctx = context.WithLogger(ctx, logger.Global())
p := testutil.NewPrincipal()
impl := p.Roots()
- roots, err := newCachedRoots(ctx, impl, &mu)
+ roots, err := newCachedRoots(impl, &mu)
if err != nil {
panic(err)
}
diff --git a/services/agent/keymgr/client.go b/services/agent/keymgr/client.go
index 01098de..ae837dd 100644
--- a/services/agent/keymgr/client.go
+++ b/services/agent/keymgr/client.go
@@ -14,6 +14,8 @@
"v.io/v23/context"
"v.io/v23/verror"
+ "v.io/x/ref/services/agent"
+ "v.io/x/ref/services/agent/internal/ipc"
"v.io/x/ref/services/agent/internal/server"
"v.io/x/ref/services/agent/internal/unixfd"
)
@@ -30,6 +32,10 @@
const defaultManagerSocket = 4
+type KeyManager struct {
+ conn *ipc.IPCConn
+}
+
type Agent struct {
conn *net.UnixConn // Guarded by mu
mu sync.Mutex
@@ -40,6 +46,17 @@
return newAgent(defaultManagerSocket)
}
+// NewKeyManager returns a client connected to the specified KeyManager.
+func NewKeyManager(path string) (agent.KeyManager, error) {
+ i := ipc.NewIPC()
+ conn, err := i.Connect(path)
+ var m *KeyManager
+ if err == nil {
+ m = &KeyManager{conn}
+ }
+ return m, err
+}
+
func NewLocalAgent(ctx *context.T, path string, passphrase []byte) (*Agent, error) {
file, err := server.RunKeyManager(ctx, path, passphrase)
if err != nil {
@@ -79,19 +96,27 @@
if err != nil {
return nil, nil, err
}
- buf := make([]byte, server.PrincipalHandleByteSize)
+ buf := make([]byte, agent.PrincipalHandleByteSize)
n, err := a.conn.Read(buf)
if err != nil {
conn.Close()
return nil, nil, err
}
- if n != server.PrincipalHandleByteSize {
+ if n != agent.PrincipalHandleByteSize {
conn.Close()
- return nil, nil, verror.New(errInvalidResponse, ctx, server.PrincipalHandleByteSize, n)
+ return nil, nil, verror.New(errInvalidResponse, ctx, agent.PrincipalHandleByteSize, n)
}
return buf, conn, nil
}
+// NewPrincipal creates a new principal and returns a handle.
+// The handle may be passed to ServePrincipal to start an agent serving the principal.
+func (m *KeyManager) NewPrincipal(inMemory bool) (handle [agent.PrincipalHandleByteSize]byte, err error) {
+ args := []interface{}{inMemory}
+ err = m.conn.Call("NewPrincipal", args, &handle)
+ return
+}
+
func (a *Agent) connect(req []byte) (*os.File, error) {
addr, err := unixfd.SendConnection(a.conn, req)
if err != nil {
@@ -108,10 +133,37 @@
// previously created with NewPrincipal.
// Typically this will be passed to a child process using cmd.ExtraFiles.
func (a *Agent) NewConnection(handle []byte) (*os.File, error) {
- if len(handle) != server.PrincipalHandleByteSize {
+ if len(handle) != agent.PrincipalHandleByteSize {
return nil, verror.New(errInvalidKeyHandle, nil)
}
a.mu.Lock()
defer a.mu.Unlock()
return a.connect(handle)
}
+
+// ServePrincipal creates a socket at socketPath and serves a principal
+// previously created with NewPrincipal.
+func (m *KeyManager) ServePrincipal(handle [agent.PrincipalHandleByteSize]byte, socketPath string) error {
+ args := []interface{}{handle, socketPath}
+ return m.conn.Call("ServePrincipal", args)
+}
+
+// StopServing shuts down a server previously started with ServePrincipal.
+// The principal is not deleted and the server can be restarted by calling
+// ServePrincipal again.
+func (m *KeyManager) StopServing(handle [agent.PrincipalHandleByteSize]byte) error {
+ args := []interface{}{handle}
+ return m.conn.Call("StopServing", args)
+}
+
+// DeletePrincipal shuts down a server started by ServePrincipal and additionally
+// deletes the principal.
+func (m *KeyManager) DeletePrincipal(handle [agent.PrincipalHandleByteSize]byte) error {
+ args := []interface{}{handle}
+ return m.conn.Call("DeletePrincipal", args)
+}
+
+func (m *KeyManager) Close() error {
+ m.conn.Close()
+ return nil
+}
diff --git a/services/agent/model.go b/services/agent/model.go
new file mode 100644
index 0000000..38d6ece
--- /dev/null
+++ b/services/agent/model.go
@@ -0,0 +1,27 @@
+// 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 agent
+
+import (
+ "crypto/sha512"
+ "io"
+
+ "v.io/v23/security"
+)
+
+type Principal interface {
+ security.Principal
+ io.Closer
+}
+
+const PrincipalHandleByteSize = sha512.Size
+
+type KeyManager interface {
+ NewPrincipal(inMemory bool) (handle [PrincipalHandleByteSize]byte, err error)
+ ServePrincipal(handle [PrincipalHandleByteSize]byte, socketPath string) error
+ StopServing(handle [PrincipalHandleByteSize]byte) error
+ DeletePrincipal(handle [PrincipalHandleByteSize]byte) error
+ io.Closer
+}
diff --git a/services/device/deviced/internal/impl/proxy_invoker.go b/services/device/deviced/internal/impl/proxy_invoker.go
index c395de6..d15dec1 100644
--- a/services/device/deviced/internal/impl/proxy_invoker.go
+++ b/services/device/deviced/internal/impl/proxy_invoker.go
@@ -214,7 +214,7 @@
}
func (p *proxyInvoker) Globber() *rpc.GlobState {
- return &rpc.GlobState{AllGlobberX: p}
+ return &rpc.GlobState{AllGlobber: p}
}
type call struct {
diff --git a/services/mounttable/mounttablelib/mounttable_test.go b/services/mounttable/mounttablelib/mounttable_test.go
index 879943b..002af2b 100644
--- a/services/mounttable/mounttablelib/mounttable_test.go
+++ b/services/mounttable/mounttablelib/mounttable_test.go
@@ -484,7 +484,7 @@
root, _, _ := mt.Lookup(ctx, "")
g, _ := glob.Parse("...")
fCall := &fakeServerCall{}
- root.(rpc.Globber).Globber().AllGlobberX.Glob__(ctx, fCall, g)
+ root.(rpc.Globber).Globber().AllGlobber.Glob__(ctx, fCall, g)
return fCall.sendCount, nil
}
diff --git a/services/wspr/internal/principal/principal_test.go b/services/wspr/internal/principal/principal_test.go
index 330a179..64cb612 100644
--- a/services/wspr/internal/principal/principal_test.go
+++ b/services/wspr/internal/principal/principal_test.go
@@ -178,7 +178,13 @@
if err != nil {
t.Fatalf("NewPrincipalManager failed: %v", err)
}
+
googleAccount := "fred/jim@gmail.com"
+ googleBlessings := accountBlessing(root, googleAccount)
+
+ if err := m.AddAccount(googleAccount, googleBlessings); err != nil {
+ t.Errorf("AddAccount(%v, %v) failed: %v", googleAccount, googleBlessings, err)
+ }
// Test with unknown origin.
unknownOrigin := "http://unknown.com"
diff --git a/services/wspr/internal/rpc/server/invoker.go b/services/wspr/internal/rpc/server/invoker.go
index 9e6e40c..ae5c48a 100644
--- a/services/wspr/internal/rpc/server/invoker.go
+++ b/services/wspr/internal/rpc/server/invoker.go
@@ -84,7 +84,7 @@
if i.globFunc == nil {
return nil
}
- return &rpc.GlobState{AllGlobberX: i}
+ return &rpc.GlobState{AllGlobber: i}
}
func (i *invoker) Glob__(ctx *context.T, call rpc.GlobServerCall, g *glob.Glob) error {