blob: bcda6306cdceab57dfec401166a405e489152d27 [file] [log] [blame]
Jiri Simsad7616c92015-03-24 23:44:30 -07001// Copyright 2015 The Vanadium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
Todd Wang88509682015-04-10 10:28:24 -07005// Package agentlib implements a client for communicating with an agentd process
6// holding the private key for an identity.
7package agentlib
Ryan Brownfed691e2014-09-15 13:09:40 -07008
9import (
10 "fmt"
Ryan Brown50b473a2014-09-23 14:23:00 -070011 "net"
12 "os"
Ryan Brown7f950a82015-04-20 18:08:39 -070013 "strconv"
14 "syscall"
Ryan Brownfed691e2014-09-15 13:09:40 -070015
Jiri Simsa6ac95222015-02-23 16:11:49 -080016 "v.io/v23/context"
Jiri Simsa6ac95222015-02-23 16:11:49 -080017 "v.io/v23/naming"
18 "v.io/v23/options"
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070019 "v.io/v23/rpc"
Jiri Simsa6ac95222015-02-23 16:11:49 -080020 "v.io/v23/security"
Ryan Brown7f950a82015-04-20 18:08:39 -070021 "v.io/v23/verror"
Jiri Simsa6ac95222015-02-23 16:11:49 -080022 "v.io/v23/vtrace"
Jiri Simsa337af232015-02-27 14:36:46 -080023 "v.io/x/lib/vlog"
Todd Wangb3511492015-04-07 23:32:34 -070024 "v.io/x/ref/services/agent/internal/cache"
Todd Wangfb939032015-04-08 16:42:44 -070025 "v.io/x/ref/services/agent/internal/unixfd"
Ryan Brownfed691e2014-09-15 13:09:40 -070026)
27
Ryan Brown7f950a82015-04-20 18:08:39 -070028const pkgPath = "v.io/x/ref/services/agent/agentlib"
29
30// Errors
31var (
32 errInvalidProtocol = verror.Register(pkgPath+".errInvalidProtocol",
33 verror.NoRetry, "{1:}{2:} invalid agent protocol {3}")
34)
Ryan Brownfed691e2014-09-15 13:09:40 -070035
36type client struct {
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -070037 caller caller
Ryan Brownfed691e2014-09-15 13:09:40 -070038 key security.PublicKey
39}
40
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -070041type caller struct {
Matt Rosencrantz6edab562015-01-12 11:07:55 -080042 ctx *context.T
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070043 client rpc.Client
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -070044 name string
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -070045}
46
Todd Wange77f9952015-02-18 13:20:50 -080047func (c *caller) call(name string, results []interface{}, args ...interface{}) error {
48 call, err := c.startCall(name, args...)
49 if err != nil {
50 return err
Ryan Brownfed691e2014-09-15 13:09:40 -070051 }
Todd Wange77f9952015-02-18 13:20:50 -080052 if err := call.Finish(results...); err != nil {
53 return err
54 }
55 return nil
Ryan Brownfed691e2014-09-15 13:09:40 -070056}
57
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070058func (c *caller) startCall(name string, args ...interface{}) (rpc.ClientCall, error) {
Todd Wangad492042015-04-17 15:58:40 -070059 ctx, _ := vtrace.WithNewTrace(c.ctx)
Suharsh Sivakumar2c5d8102015-03-23 08:49:12 -070060 // SecurityNone is safe here since we're using anonymous unix sockets.
61 return c.client.StartCall(ctx, c.name, name, args, options.SecurityNone, options.NoResolve{})
Ryan Brown81bcb3a2015-02-11 10:58:01 -080062}
63
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -070064func results(inputs ...interface{}) []interface{} {
Todd Wange77f9952015-02-18 13:20:50 -080065 return inputs
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -070066}
67
68// NewAgentPrincipal returns a security.Pricipal using the PrivateKey held in a remote agent process.
Ryan Brown7f950a82015-04-20 18:08:39 -070069// 'endpoint' is the endpoint for connecting to the agent, typically obtained from
70// os.GetEnv(envvar.AgentEndpoint).
Bogdan Caprita6613fc42015-01-28 11:54:23 -080071// 'ctx' should not have a deadline, and should never be cancelled while the
72// principal is in use.
Ryan Brown7f950a82015-04-20 18:08:39 -070073func NewAgentPrincipal(ctx *context.T, endpoint naming.Endpoint, insecureClient rpc.Client) (security.Principal, error) {
74 p, err := newUncachedPrincipal(ctx, endpoint, insecureClient)
Ryan Brown81bcb3a2015-02-11 10:58:01 -080075 if err != nil {
76 return p, err
77 }
78 call, callErr := p.caller.startCall("NotifyWhenChanged")
79 if callErr != nil {
80 return nil, callErr
81 }
82 return cache.NewCachedPrincipal(p.caller.ctx, p, call)
83}
Ryan Brown7f950a82015-04-20 18:08:39 -070084func newUncachedPrincipal(ctx *context.T, ep naming.Endpoint, insecureClient rpc.Client) (*client, error) {
85 // This isn't a real vanadium endpoint. It contains the vanadium version
86 // info, but the address is serving the agent protocol.
87 if ep.Addr().Network() != "" {
88 return nil, verror.New(errInvalidProtocol, ctx, ep.Addr().Network())
89 }
90 fd, err := strconv.Atoi(ep.Addr().String())
91 if err != nil {
92 return nil, err
93 }
94 syscall.ForkLock.Lock()
95 fd, err = syscall.Dup(fd)
96 if err == nil {
97 syscall.CloseOnExec(fd)
98 }
99 syscall.ForkLock.Unlock()
100 if err != nil {
101 return nil, err
102 }
Ryan Brown81789442014-10-30 13:23:53 -0700103 f := os.NewFile(uintptr(fd), "agent_client")
104 defer f.Close()
105 conn, err := net.FileConn(f)
Ryan Brown50b473a2014-09-23 14:23:00 -0700106 if err != nil {
107 return nil, err
108 }
109 // This is just an arbitrary 1 byte string. The value is ignored.
110 data := make([]byte, 1)
Bogdan Capritabb37c542015-01-22 10:21:57 -0800111 addr, err := unixfd.SendConnection(conn.(*net.UnixConn), data)
Ryan Brown50b473a2014-09-23 14:23:00 -0700112 if err != nil {
113 return nil, err
114 }
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -0700115 caller := caller{
Matt Rosencrantz99cc06e2015-01-16 10:25:11 -0800116 client: insecureClient,
Ryan Brown7f950a82015-04-20 18:08:39 -0700117 name: naming.JoinAddressName(agentEndpoint("unixfd", addr.String()), ""),
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -0700118 ctx: ctx,
119 }
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -0700120 agent := &client{caller: caller}
Ryan Brownfed691e2014-09-15 13:09:40 -0700121 if err := agent.fetchPublicKey(); err != nil {
122 return nil, err
123 }
124 return agent, nil
125}
126
127func (c *client) fetchPublicKey() (err error) {
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -0700128 var b []byte
129 if err = c.caller.call("PublicKey", results(&b)); err != nil {
Ryan Brownfed691e2014-09-15 13:09:40 -0700130 return
131 }
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -0700132 c.key, err = security.UnmarshalPublicKey(b)
Ryan Brownfed691e2014-09-15 13:09:40 -0700133 return
134}
135
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -0700136func (c *client) Bless(key security.PublicKey, with security.Blessings, extension string, caveat security.Caveat, additionalCaveats ...security.Caveat) (security.Blessings, error) {
Asim Shankarb07ec692015-02-27 23:40:44 -0800137 var blessings security.Blessings
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -0700138 marshalledKey, err := key.MarshalBinary()
139 if err != nil {
Asim Shankar2bf7b1e2015-02-27 00:45:12 -0800140 return security.Blessings{}, err
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -0700141 }
Asim Shankarb07ec692015-02-27 23:40:44 -0800142 err = c.caller.call("Bless", results(&blessings), marshalledKey, with, extension, caveat, additionalCaveats)
143 return blessings, err
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -0700144}
145
146func (c *client) BlessSelf(name string, caveats ...security.Caveat) (security.Blessings, error) {
Asim Shankarb07ec692015-02-27 23:40:44 -0800147 var blessings security.Blessings
148 err := c.caller.call("BlessSelf", results(&blessings), name, caveats)
149 return blessings, err
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -0700150}
151
152func (c *client) Sign(message []byte) (sig security.Signature, err error) {
153 err = c.caller.call("Sign", results(&sig), message)
154 return
155}
156
Asim Shankar19da8182015-02-06 01:41:16 -0800157func (c *client) MintDischarge(forCaveat, caveatOnDischarge security.Caveat, additionalCaveatsOnDischarge ...security.Caveat) (security.Discharge, error) {
Asim Shankar08642822015-03-02 21:21:09 -0800158 var discharge security.Discharge
Asim Shankar19da8182015-02-06 01:41:16 -0800159 if err := c.caller.call("MintDischarge", results(&discharge), forCaveat, caveatOnDischarge, additionalCaveatsOnDischarge); err != nil {
Asim Shankar3ad0b8a2015-02-25 00:37:21 -0800160 return security.Discharge{}, err
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -0700161 }
Asim Shankar08642822015-03-02 21:21:09 -0800162 return discharge, nil
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -0700163}
164
Ryan Brownfed691e2014-09-15 13:09:40 -0700165func (c *client) PublicKey() security.PublicKey {
166 return c.key
167}
168
gauthamtf8263932014-12-16 10:59:09 -0800169func (c *client) BlessingsByName(pattern security.BlessingPattern) []security.Blessings {
Asim Shankarb07ec692015-02-27 23:40:44 -0800170 var blessings []security.Blessings
171 if err := c.caller.call("BlessingsByName", results(&blessings), pattern); err != nil {
gauthamtf8263932014-12-16 10:59:09 -0800172 vlog.Errorf("error calling BlessingsByName: %v", err)
173 return nil
174 }
gauthamtf8263932014-12-16 10:59:09 -0800175 return blessings
176}
177
gauthamt8dc9a182015-01-08 18:03:18 -0800178func (c *client) BlessingsInfo(blessings security.Blessings) map[string][]security.Caveat {
179 var bInfo map[string][]security.Caveat
Asim Shankarb07ec692015-02-27 23:40:44 -0800180 err := c.caller.call("BlessingsInfo", results(&bInfo), blessings)
gauthamtf8263932014-12-16 10:59:09 -0800181 if err != nil {
182 vlog.Errorf("error calling BlessingsInfo: %v", err)
183 return nil
184 }
gauthamt8dc9a182015-01-08 18:03:18 -0800185 return bInfo
gauthamtf8263932014-12-16 10:59:09 -0800186}
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -0700187func (c *client) BlessingStore() security.BlessingStore {
188 return &blessingStore{c.caller, c.key}
189}
190
191func (c *client) Roots() security.BlessingRoots {
192 return &blessingRoots{c.caller}
193}
194
195func (c *client) AddToRoots(blessings security.Blessings) error {
Asim Shankarb07ec692015-02-27 23:40:44 -0800196 return c.caller.call("AddToRoots", results(), blessings)
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -0700197}
198
199type blessingStore struct {
200 caller caller
201 key security.PublicKey
202}
203
204func (b *blessingStore) Set(blessings security.Blessings, forPeers security.BlessingPattern) (security.Blessings, error) {
Asim Shankarb07ec692015-02-27 23:40:44 -0800205 var previous security.Blessings
206 err := b.caller.call("BlessingStoreSet", results(&previous), blessings, forPeers)
207 return previous, err
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -0700208}
209
210func (b *blessingStore) ForPeer(peerBlessings ...string) security.Blessings {
Asim Shankarb07ec692015-02-27 23:40:44 -0800211 var blessings security.Blessings
212 if err := b.caller.call("BlessingStoreForPeer", results(&blessings), peerBlessings); err != nil {
213 vlog.Errorf("error calling BlessingStorePeerBlessings: %v", err)
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -0700214 }
215 return blessings
216}
217
218func (b *blessingStore) SetDefault(blessings security.Blessings) error {
Asim Shankarb07ec692015-02-27 23:40:44 -0800219 return b.caller.call("BlessingStoreSetDefault", results(), blessings)
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -0700220}
221
222func (b *blessingStore) Default() security.Blessings {
Asim Shankarb07ec692015-02-27 23:40:44 -0800223 var blessings security.Blessings
224 err := b.caller.call("BlessingStoreDefault", results(&blessings))
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -0700225 if err != nil {
226 vlog.Errorf("error calling BlessingStoreDefault: %v", err)
Asim Shankar2bf7b1e2015-02-27 00:45:12 -0800227 return security.Blessings{}
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -0700228 }
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -0700229 return blessings
230}
231
232func (b *blessingStore) PublicKey() security.PublicKey {
233 return b.key
234}
235
gauthamtf8263932014-12-16 10:59:09 -0800236func (b *blessingStore) PeerBlessings() map[security.BlessingPattern]security.Blessings {
Asim Shankarb07ec692015-02-27 23:40:44 -0800237 var bmap map[security.BlessingPattern]security.Blessings
238 err := b.caller.call("BlessingStorePeerBlessings", results(&bmap))
gauthamtf8263932014-12-16 10:59:09 -0800239 if err != nil {
240 vlog.Errorf("error calling BlessingStorePeerBlessings: %v", err)
241 return nil
242 }
Asim Shankarb07ec692015-02-27 23:40:44 -0800243 return bmap
gauthamtf8263932014-12-16 10:59:09 -0800244}
245
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -0700246func (b *blessingStore) DebugString() (s string) {
247 err := b.caller.call("BlessingStoreDebugString", results(&s))
248 if err != nil {
249 s = fmt.Sprintf("error calling BlessingStoreDebugString: %v", err)
250 vlog.Errorf(s)
251 }
252 return
253}
254
255type blessingRoots struct {
256 caller caller
257}
258
259func (b *blessingRoots) Add(root security.PublicKey, pattern security.BlessingPattern) error {
260 marshalledKey, err := root.MarshalBinary()
261 if err != nil {
262 return err
263 }
264 return b.caller.call("BlessingRootsAdd", results(), marshalledKey, pattern)
265}
266
267func (b *blessingRoots) Recognized(root security.PublicKey, blessing string) error {
268 marshalledKey, err := root.MarshalBinary()
269 if err != nil {
270 return err
271 }
Asim Shankarb378e662015-01-16 10:50:48 -0800272 return b.caller.call("BlessingRootsRecognized", results(), marshalledKey, blessing)
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -0700273}
274
275func (b *blessingRoots) DebugString() (s string) {
276 err := b.caller.call("BlessingRootsDebugString", results(&s))
277 if err != nil {
278 s = fmt.Sprintf("error calling BlessingRootsDebugString: %v", err)
279 vlog.Errorf(s)
280 }
Ryan Brownfed691e2014-09-15 13:09:40 -0700281 return
282}
Ryan Brown7f950a82015-04-20 18:08:39 -0700283
284func agentEndpoint(proto, addr string) string {
285 // TODO: use naming.FormatEndpoint when it supports version 5.
286 return fmt.Sprintf("@5@%s@%s@@s@@@", proto, addr)
287}
288
289func AgentEndpoint(fd int) string {
290 // We use an empty protocol here because this isn't really speaking
291 // veyron rpc.
292 return agentEndpoint("", fmt.Sprintf("%d", fd))
293}