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 {