blob: 7a93f3166ffb300e9c16141e67fef90262154284 [file] [log] [blame]
Ryan Brown81789442014-10-30 13:23:53 -07001// Package keymgr provides a client for the Node Manager to manage keys in
2// the "Agent" process.
3package keymgr
4
5import (
6 "net"
7 "os"
8 "strconv"
9 "sync"
10
11 "veyron.io/veyron/veyron/lib/unixfd"
12 "veyron.io/veyron/veyron/security/agent/server"
13 "veyron.io/veyron/veyron2/context"
14 "veyron.io/veyron/veyron2/verror"
15)
16
17const defaultManagerSocket = 4
18
19type Agent struct {
20 conn *net.UnixConn // Guarded by mu
21 mu sync.Mutex
22}
23
24// NewAgent returns a client connected to the agent on the default file descriptors.
25func NewAgent() (*Agent, error) {
26 return newAgent(defaultManagerSocket)
27}
28
29func newAgent(fd int) (a *Agent, err error) {
30 file := os.NewFile(uintptr(fd), "fd")
31 defer file.Close()
32 conn, err := net.FileConn(file)
33 if err != nil {
34 return nil, err
35 }
36
37 return &Agent{conn: conn.(*net.UnixConn)}, nil
38}
39
Bogdan Caprita7f491672014-11-13 14:51:08 -080040// TODO(caprita): Get rid of context.T arg. Doesn't seem to be used.
41
Ryan Brown81789442014-10-30 13:23:53 -070042// NewPrincipal creates a new principal and returns the handle and a socket serving
43// the principal.
44// Typically the socket will be passed to a child process using cmd.ExtraFiles.
Bogdan Caprita7f491672014-11-13 14:51:08 -080045func (a *Agent) NewPrincipal(_ context.T, inMemory bool) (handle []byte, conn *os.File, err error) {
Ryan Brown81789442014-10-30 13:23:53 -070046 req := make([]byte, 1)
Bogdan Caprita7f491672014-11-13 14:51:08 -080047 if inMemory {
Ryan Brown81789442014-10-30 13:23:53 -070048 req[0] = 1
49 }
50 a.mu.Lock()
51 defer a.mu.Unlock()
52 conn, err = a.connect(req)
53 if err != nil {
54 return nil, nil, err
55 }
56 buf := make([]byte, server.PrincipalHandleByteSize)
57 n, err := a.conn.Read(buf)
58 if err != nil {
59 conn.Close()
60 return nil, nil, err
61 }
62 if n != server.PrincipalHandleByteSize {
63 conn.Close()
64 return nil, nil, verror.BadProtocolf("invalid response from agent. (expected %d bytes, got %d)", server.PrincipalHandleByteSize, n)
65 }
66 return buf, conn, nil
67}
68
69func (a *Agent) connect(req []byte) (*os.File, error) {
70 // We're passing this to a child, so no CLOEXEC.
71 addr, err := unixfd.SendConnection(a.conn, req, false)
72 if err != nil {
73 return nil, err
74 }
75 fd, err := strconv.ParseInt(addr.String(), 10, 32)
76 if err != nil {
77 return nil, err
78 }
79 return os.NewFile(uintptr(fd), "client"), nil
80}
81
82// NewConnection creates a connection to an agent which exports a principal
83// previously created with NewPrincipal.
84// Typically this will be passed to a child process using cmd.ExtraFiles.
85func (a *Agent) NewConnection(handle []byte) (*os.File, error) {
86 if len(handle) != server.PrincipalHandleByteSize {
87 return nil, verror.BadArgf("Invalid key handle")
88 }
89 a.mu.Lock()
90 defer a.mu.Unlock()
91 return a.connect(handle)
92}