forked from jsipprell/keyctl
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ref.go
160 lines (139 loc) · 3.53 KB
/
ref.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
package keyctl
import (
"bytes"
"errors"
"os"
"strconv"
)
var (
// Error returned if the Get() method is called on a Reference that doesn't
// represent a key or keychain.
ErrUnsupportedKeyType = errors.New("unsupported keyctl key type")
// Error returned if a reference is stale when Info() or Get() is called on
// it.
ErrInvalidReference = errors.New("invalid keyctl reference")
)
// Reference is a reference to an unloaded keyctl Key or Keychain. It can be
// dereferenced by calling the Get() method.
type Reference struct {
// Id is the kernel key or keychain identifier referenced.
Id int32
info *Info
parent keyId
}
// Information about a keyctl reference as returned by ref.Info()
type Info struct {
Type, Name string
Uid, Gid int
Perm KeyPerm
valid bool
}
func getInfo(id keyId) (i Info, err error) {
var desc []byte
if desc, err = describeKeyId(id); err != nil {
i.Name = err.Error()
return
}
fields := bytes.Split(desc, []byte{';'})
switch len(fields) {
case 5:
i.Name = string(fields[4])
fallthrough
case 4:
p, _ := strconv.ParseUint(string(fields[3]), 16, 32)
i.Perm = KeyPerm(p)
fallthrough
case 3:
i.Gid, _ = strconv.Atoi(string(fields[2]))
fallthrough
case 2:
i.Uid, _ = strconv.Atoi(string(fields[1]))
fallthrough
case 1:
if i.Type = string(fields[0]); i.Type == "user" {
i.Type = "key"
}
i.valid = true
default:
panic("invalid field count from kernel keyctl describe sysctl")
}
return
}
// Returns permissions in symbolic format.
func (i Info) Permissions() string {
if i.Uid == os.Geteuid() {
return encodePerms(uint8(i.Perm >> KeyPerm(16)))
} else {
fsgid, err := getfsgid()
if (err == nil && i.Gid == int(fsgid)) || i.Gid == os.Getegid() {
return encodePerms(uint8(i.Perm >> KeyPerm(8)))
}
}
return encodePerms(uint8(i.Perm))
}
// Return Information about a keyctl reference.
func (r *Reference) Info() (i Info, err error) {
if r.info == nil {
i, err = getInfo(keyId(r.Id))
r.info = &i
return
}
return *r.info, err
}
// Returns true if the Info fetched by ref.Info() is valid.
func (i Info) Valid() bool {
return i.valid
}
// Returns true if the keyctl reference is valid. Refererences can become
// invalid if they have expired since the reference was created.
func (r *Reference) Valid() bool {
if r.info == nil {
r.Info()
}
return r.info.valid
}
// Loads the referenced keyctl object, which must either be a key or a
// keyring otherwise ErrUnsupportedKeyType will be returned.
func (r *Reference) Get() (Id, error) {
if r.info == nil {
_, err := r.Info()
if err != nil {
return nil, err
}
}
if !r.info.valid {
return nil, ErrInvalidReference
}
switch r.info.Type {
case "key", "big_key":
return &Key{Name: r.info.Name, id: keyId(r.Id), ring: r.parent}, nil
case "keyring":
ring := &keyring{id: keyId(r.Id)}
if r.Id > 0 && r.info.Name != "" {
return &namedKeyring{
keyring: ring,
parent: r.parent,
name: r.info.Name,
}, nil
}
return ring, nil
default:
return nil, ErrUnsupportedKeyType
}
}
// List the contents of a keyring. Each contained object is represented by a
// Reference struct. Addl information is available by calling ref.Info(), and
// contained objects which are keys or subordinate keyrings can be fetched by
// calling ref.Get()
func ListKeyring(kr Keyring) ([]Reference, error) {
id := keyId(kr.Id())
keys, err := listKeys(id)
if err != nil {
return nil, err
}
refs := make([]Reference, len(keys))
for i, k := range keys {
refs[i].Id, refs[i].parent = int32(k), id
}
return refs, nil
}