blob: c642aea1ce0eafb61a58c60099d39de61f71e301 [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 Brown0a3e28a2015-08-12 14:59:14 -070011 "io"
Ryan Brown0a3e28a2015-08-12 14:59:14 -070012 "sync"
Matt Rosencrantz6357fcb2015-12-16 16:38:57 -080013 "time"
Ryan Brownfed691e2014-09-15 13:09:40 -070014
Jiri Simsa6ac95222015-02-23 16:11:49 -080015 "v.io/v23/security"
Ryan Brown7f950a82015-04-20 18:08:39 -070016 "v.io/v23/verror"
Cosmos Nicolaou1c33b7d2015-06-24 15:15:54 -070017 "v.io/x/ref/internal/logger"
Ryan Brown0a3e28a2015-08-12 14:59:14 -070018 "v.io/x/ref/services/agent"
Todd Wangb3511492015-04-07 23:32:34 -070019 "v.io/x/ref/services/agent/internal/cache"
Ryan Brown0a3e28a2015-08-12 14:59:14 -070020 "v.io/x/ref/services/agent/internal/ipc"
Ryan Brownfed691e2014-09-15 13:09:40 -070021)
22
Ryan Brown7f950a82015-04-20 18:08:39 -070023const pkgPath = "v.io/x/ref/services/agent/agentlib"
24
25// Errors
26var (
27 errInvalidProtocol = verror.Register(pkgPath+".errInvalidProtocol",
28 verror.NoRetry, "{1:}{2:} invalid agent protocol {3}")
29)
Ryan Brownfed691e2014-09-15 13:09:40 -070030
31type client struct {
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -070032 caller caller
Ryan Brownfed691e2014-09-15 13:09:40 -070033 key security.PublicKey
Matt Rosencrantz6357fcb2015-12-16 16:38:57 -080034 // TODO(mattr): At some point we should remove this backward
35 // compatibility mechanism, once all users are updated.
36 noCacheTimes bool
Ryan Brownfed691e2014-09-15 13:09:40 -070037}
38
Ryan Brown0a3e28a2015-08-12 14:59:14 -070039type caller interface {
40 call(name string, results []interface{}, args ...interface{}) error
41 io.Closer
42}
43
44type ipcCaller struct {
45 conn *ipc.IPCConn
46 flush func()
47 mu sync.Mutex
48}
49
50func (i *ipcCaller) call(name string, results []interface{}, args ...interface{}) error {
51 return i.conn.Call(name, args, results...)
52}
53
54func (i *ipcCaller) Close() error {
55 i.conn.Close()
56 return nil
57}
58
59func (i *ipcCaller) FlushAllCaches() error {
60 var flush func()
61 i.mu.Lock()
62 flush = i.flush
63 i.mu.Unlock()
64 if flush != nil {
65 flush()
66 }
67 return nil
68}
69
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -070070func results(inputs ...interface{}) []interface{} {
Todd Wange77f9952015-02-18 13:20:50 -080071 return inputs
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -070072}
73
Ryan Brown0a3e28a2015-08-12 14:59:14 -070074func newUncachedPrincipalX(path string) (*client, error) {
75 caller := new(ipcCaller)
76 i := ipc.NewIPC()
77 i.Serve(caller)
78 conn, err := i.Connect(path)
79 if err != nil {
80 return nil, err
81 }
82 caller.conn = conn
83 agent := &client{caller: caller}
84 if err := agent.fetchPublicKey(); err != nil {
85 return nil, err
86 }
Matt Rosencrantz6357fcb2015-12-16 16:38:57 -080087 var dis security.Discharge
88 var cacheTime time.Time
89 if err := caller.call("BlessingStoreDischarge2", results(&dis, &cacheTime), security.Caveat{}, security.DischargeImpetus{}); err != nil {
90 // If we can't fetch a discharge with two results, then we should fall back
91 // to the old one result version.
92 agent.noCacheTimes = true
93 }
Ryan Brown0a3e28a2015-08-12 14:59:14 -070094 return agent, nil
95}
96
97// NewAgentPrincipal returns a security.Pricipal using the PrivateKey held in a remote agent process.
98// 'path' is the path to the agent socket, typically obtained from
99// os.GetEnv(envvar.AgentAddress).
100func NewAgentPrincipalX(path string) (agent.Principal, error) {
101 p, err := newUncachedPrincipalX(path)
102 if err != nil {
103 return nil, err
104 }
105 cached, flush, err := cache.NewCachedPrincipalX(p)
106 if err != nil {
107 return nil, err
108 }
109 caller := p.caller.(*ipcCaller)
110 caller.mu.Lock()
111 caller.flush = flush
112 caller.mu.Unlock()
113 return cached, nil
114}
115
Ryan Brown0a3e28a2015-08-12 14:59:14 -0700116func (c *client) Close() error {
117 return c.caller.Close()
118}
119
Ryan Brownfed691e2014-09-15 13:09:40 -0700120func (c *client) fetchPublicKey() (err error) {
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -0700121 var b []byte
122 if err = c.caller.call("PublicKey", results(&b)); err != nil {
Ryan Brownfed691e2014-09-15 13:09:40 -0700123 return
124 }
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -0700125 c.key, err = security.UnmarshalPublicKey(b)
Ryan Brownfed691e2014-09-15 13:09:40 -0700126 return
127}
128
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -0700129func (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 -0800130 var blessings security.Blessings
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -0700131 marshalledKey, err := key.MarshalBinary()
132 if err != nil {
Asim Shankar2bf7b1e2015-02-27 00:45:12 -0800133 return security.Blessings{}, err
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -0700134 }
Asim Shankarb07ec692015-02-27 23:40:44 -0800135 err = c.caller.call("Bless", results(&blessings), marshalledKey, with, extension, caveat, additionalCaveats)
136 return blessings, err
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -0700137}
138
139func (c *client) BlessSelf(name string, caveats ...security.Caveat) (security.Blessings, error) {
Asim Shankarb07ec692015-02-27 23:40:44 -0800140 var blessings security.Blessings
141 err := c.caller.call("BlessSelf", results(&blessings), name, caveats)
142 return blessings, err
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -0700143}
144
145func (c *client) Sign(message []byte) (sig security.Signature, err error) {
146 err = c.caller.call("Sign", results(&sig), message)
147 return
148}
149
Asim Shankar19da8182015-02-06 01:41:16 -0800150func (c *client) MintDischarge(forCaveat, caveatOnDischarge security.Caveat, additionalCaveatsOnDischarge ...security.Caveat) (security.Discharge, error) {
Asim Shankar08642822015-03-02 21:21:09 -0800151 var discharge security.Discharge
Asim Shankar19da8182015-02-06 01:41:16 -0800152 if err := c.caller.call("MintDischarge", results(&discharge), forCaveat, caveatOnDischarge, additionalCaveatsOnDischarge); err != nil {
Asim Shankar3ad0b8a2015-02-25 00:37:21 -0800153 return security.Discharge{}, err
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -0700154 }
Asim Shankar08642822015-03-02 21:21:09 -0800155 return discharge, nil
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -0700156}
157
Ryan Brownfed691e2014-09-15 13:09:40 -0700158func (c *client) PublicKey() security.PublicKey {
159 return c.key
160}
161
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -0700162func (c *client) BlessingStore() security.BlessingStore {
Matt Rosencrantz6357fcb2015-12-16 16:38:57 -0800163 return &blessingStore{caller: c.caller, key: c.key, noCacheTimes: c.noCacheTimes}
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -0700164}
165
166func (c *client) Roots() security.BlessingRoots {
167 return &blessingRoots{c.caller}
168}
169
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -0700170type blessingStore struct {
Matt Rosencrantz6357fcb2015-12-16 16:38:57 -0800171 caller caller
172 key security.PublicKey
173 noCacheTimes bool
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -0700174}
175
176func (b *blessingStore) Set(blessings security.Blessings, forPeers security.BlessingPattern) (security.Blessings, error) {
Asim Shankarb07ec692015-02-27 23:40:44 -0800177 var previous security.Blessings
178 err := b.caller.call("BlessingStoreSet", results(&previous), blessings, forPeers)
179 return previous, err
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -0700180}
181
182func (b *blessingStore) ForPeer(peerBlessings ...string) security.Blessings {
Asim Shankarb07ec692015-02-27 23:40:44 -0800183 var blessings security.Blessings
184 if err := b.caller.call("BlessingStoreForPeer", results(&blessings), peerBlessings); err != nil {
Cosmos Nicolaou1c33b7d2015-06-24 15:15:54 -0700185 logger.Global().Infof("error calling BlessingStorePeerBlessings: %v", err)
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -0700186 }
187 return blessings
188}
189
190func (b *blessingStore) SetDefault(blessings security.Blessings) error {
Asim Shankarb07ec692015-02-27 23:40:44 -0800191 return b.caller.call("BlessingStoreSetDefault", results(), blessings)
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -0700192}
193
194func (b *blessingStore) Default() security.Blessings {
Asim Shankarb07ec692015-02-27 23:40:44 -0800195 var blessings security.Blessings
196 err := b.caller.call("BlessingStoreDefault", results(&blessings))
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -0700197 if err != nil {
Cosmos Nicolaou1c33b7d2015-06-24 15:15:54 -0700198 logger.Global().Infof("error calling BlessingStoreDefault: %v", err)
Asim Shankar2bf7b1e2015-02-27 00:45:12 -0800199 return security.Blessings{}
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -0700200 }
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -0700201 return blessings
202}
203
204func (b *blessingStore) PublicKey() security.PublicKey {
205 return b.key
206}
207
gauthamtf8263932014-12-16 10:59:09 -0800208func (b *blessingStore) PeerBlessings() map[security.BlessingPattern]security.Blessings {
Asim Shankarb07ec692015-02-27 23:40:44 -0800209 var bmap map[security.BlessingPattern]security.Blessings
210 err := b.caller.call("BlessingStorePeerBlessings", results(&bmap))
gauthamtf8263932014-12-16 10:59:09 -0800211 if err != nil {
Cosmos Nicolaou1c33b7d2015-06-24 15:15:54 -0700212 logger.Global().Infof("error calling BlessingStorePeerBlessings: %v", err)
gauthamtf8263932014-12-16 10:59:09 -0800213 return nil
214 }
Asim Shankarb07ec692015-02-27 23:40:44 -0800215 return bmap
gauthamtf8263932014-12-16 10:59:09 -0800216}
217
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -0700218func (b *blessingStore) DebugString() (s string) {
219 err := b.caller.call("BlessingStoreDebugString", results(&s))
220 if err != nil {
221 s = fmt.Sprintf("error calling BlessingStoreDebugString: %v", err)
Cosmos Nicolaou1c33b7d2015-06-24 15:15:54 -0700222 logger.Global().Infof(s)
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -0700223 }
224 return
225}
226
Suharsh Sivakumard7d4e222015-06-22 11:10:44 -0700227func (b *blessingStore) CacheDischarge(d security.Discharge, c security.Caveat, i security.DischargeImpetus) {
228 err := b.caller.call("BlessingStoreCacheDischarge", results(), d, c, i)
229 if err != nil {
Cosmos Nicolaou1c33b7d2015-06-24 15:15:54 -0700230 logger.Global().Infof("error calling BlessingStoreCacheDischarge: %v", err)
Suharsh Sivakumard7d4e222015-06-22 11:10:44 -0700231 }
232}
233
234func (b *blessingStore) ClearDischarges(discharges ...security.Discharge) {
235 err := b.caller.call("BlessingStoreClearDischarges", results(), discharges)
236 if err != nil {
Cosmos Nicolaou1c33b7d2015-06-24 15:15:54 -0700237 logger.Global().Infof("error calling BlessingStoreClearDischarges: %v", err)
Suharsh Sivakumard7d4e222015-06-22 11:10:44 -0700238 }
239}
240
Matt Rosencrantz6357fcb2015-12-16 16:38:57 -0800241func (b *blessingStore) Discharge(caveat security.Caveat, impetus security.DischargeImpetus) (out security.Discharge, cacheTime time.Time) {
242 res := []interface{}{&out}
243 method := "BlessingStoreDischarge"
244 if !b.noCacheTimes {
245 res = append(res, &cacheTime)
246 method = "BlessingStoreDischarge2"
247 }
248 err := b.caller.call(method, res, caveat, impetus)
Suharsh Sivakumard7d4e222015-06-22 11:10:44 -0700249 if err != nil {
Cosmos Nicolaou1c33b7d2015-06-24 15:15:54 -0700250 logger.Global().Infof("error calling BlessingStoreDischarge: %v", err)
Suharsh Sivakumard7d4e222015-06-22 11:10:44 -0700251 }
252 return
253}
254
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -0700255type blessingRoots struct {
256 caller caller
257}
258
Asim Shankar6eba9862015-09-03 01:07:14 -0400259func (b *blessingRoots) Add(root []byte, pattern security.BlessingPattern) error {
260 return b.caller.call("BlessingRootsAdd", results(), root, pattern)
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -0700261}
262
Asim Shankar6eba9862015-09-03 01:07:14 -0400263func (b *blessingRoots) Recognized(root []byte, blessing string) error {
264 return b.caller.call("BlessingRootsRecognized", results(), root, blessing)
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -0700265}
266
Ankur9e5b7722015-04-28 15:00:25 -0700267func (b *blessingRoots) Dump() map[security.BlessingPattern][]security.PublicKey {
268 var marshaledRoots map[security.BlessingPattern][][]byte
269 if err := b.caller.call("BlessingRootsDump", results(&marshaledRoots)); err != nil {
Cosmos Nicolaou1c33b7d2015-06-24 15:15:54 -0700270 logger.Global().Infof("error calling BlessingRootsDump: %v", err)
Ankur9e5b7722015-04-28 15:00:25 -0700271 return nil
272 }
273 ret := make(map[security.BlessingPattern][]security.PublicKey)
274 for p, marshaledKeys := range marshaledRoots {
275 for _, marshaledKey := range marshaledKeys {
276 key, err := security.UnmarshalPublicKey(marshaledKey)
277 if err != nil {
Cosmos Nicolaou1c33b7d2015-06-24 15:15:54 -0700278 logger.Global().Infof("security.UnmarshalPublicKey(%v) returned error: %v", marshaledKey, err)
Ankur9e5b7722015-04-28 15:00:25 -0700279 continue
280 }
281 ret[p] = append(ret[p], key)
282 }
283 }
284 return ret
285}
286
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -0700287func (b *blessingRoots) DebugString() (s string) {
288 err := b.caller.call("BlessingRootsDebugString", results(&s))
289 if err != nil {
290 s = fmt.Sprintf("error calling BlessingRootsDebugString: %v", err)
Cosmos Nicolaou1c33b7d2015-06-24 15:15:54 -0700291 logger.Global().Infof(s)
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -0700292 }
Ryan Brownfed691e2014-09-15 13:09:40 -0700293 return
294}