VOL-2496 Add "event listen" command to voltctl
Change-Id: I8f1fb34b55f56c8125142ac289e2f19fc170d804
diff --git a/vendor/gopkg.in/jcmturner/gokrb5.v7/credentials/ccache.go b/vendor/gopkg.in/jcmturner/gokrb5.v7/credentials/ccache.go
new file mode 100644
index 0000000..98ec29b
--- /dev/null
+++ b/vendor/gopkg.in/jcmturner/gokrb5.v7/credentials/ccache.go
@@ -0,0 +1,348 @@
+package credentials
+
+import (
+ "bytes"
+ "encoding/binary"
+ "errors"
+ "io/ioutil"
+ "strings"
+ "time"
+ "unsafe"
+
+ "github.com/jcmturner/gofork/encoding/asn1"
+ "gopkg.in/jcmturner/gokrb5.v7/types"
+)
+
+const (
+ headerFieldTagKDCOffset = 1
+)
+
+// The first byte of the file always has the value 5.
+// The value of the second byte contains the version number (1 through 4)
+// Versions 1 and 2 of the file format use native byte order for integer representations.
+// Versions 3 and 4 always use big-endian byte order
+// After the two-byte version indicator, the file has three parts:
+// 1) the header (in version 4 only)
+// 2) the default principal name
+// 3) a sequence of credentials
+
+// CCache is the file credentials cache as define here: https://web.mit.edu/kerberos/krb5-latest/doc/formats/ccache_file_format.html
+type CCache struct {
+ Version uint8
+ Header header
+ DefaultPrincipal principal
+ Credentials []*Credential
+ Path string
+}
+
+type header struct {
+ length uint16
+ fields []headerField
+}
+
+type headerField struct {
+ tag uint16
+ length uint16
+ value []byte
+}
+
+// Credential cache entry principal struct.
+type principal struct {
+ Realm string
+ PrincipalName types.PrincipalName
+}
+
+// Credential holds a Kerberos client's ccache credential information.
+type Credential struct {
+ Client principal
+ Server principal
+ Key types.EncryptionKey
+ AuthTime time.Time
+ StartTime time.Time
+ EndTime time.Time
+ RenewTill time.Time
+ IsSKey bool
+ TicketFlags asn1.BitString
+ Addresses []types.HostAddress
+ AuthData []types.AuthorizationDataEntry
+ Ticket []byte
+ SecondTicket []byte
+}
+
+// LoadCCache loads a credential cache file into a CCache type.
+func LoadCCache(cpath string) (*CCache, error) {
+ c := new(CCache)
+ b, err := ioutil.ReadFile(cpath)
+ if err != nil {
+ return c, err
+ }
+ err = c.Unmarshal(b)
+ return c, err
+}
+
+// Unmarshal a byte slice of credential cache data into CCache type.
+func (c *CCache) Unmarshal(b []byte) error {
+ p := 0
+ //The first byte of the file always has the value 5
+ if int8(b[p]) != 5 {
+ return errors.New("Invalid credential cache data. First byte does not equal 5")
+ }
+ p++
+ //Get credential cache version
+ //The second byte contains the version number (1 to 4)
+ c.Version = b[p]
+ if c.Version < 1 || c.Version > 4 {
+ return errors.New("Invalid credential cache data. Keytab version is not within 1 to 4")
+ }
+ p++
+ //Version 1 or 2 of the file format uses native byte order for integer representations. Versions 3 & 4 always uses big-endian byte order
+ var endian binary.ByteOrder
+ endian = binary.BigEndian
+ if (c.Version == 1 || c.Version == 2) && isNativeEndianLittle() {
+ endian = binary.LittleEndian
+ }
+ if c.Version == 4 {
+ err := parseHeader(b, &p, c, &endian)
+ if err != nil {
+ return err
+ }
+ }
+ c.DefaultPrincipal = parsePrincipal(b, &p, c, &endian)
+ for p < len(b) {
+ cred, err := parseCredential(b, &p, c, &endian)
+ if err != nil {
+ return err
+ }
+ c.Credentials = append(c.Credentials, cred)
+ }
+ return nil
+}
+
+func parseHeader(b []byte, p *int, c *CCache, e *binary.ByteOrder) error {
+ if c.Version != 4 {
+ return errors.New("Credentials cache version is not 4 so there is no header to parse.")
+ }
+ h := header{}
+ h.length = uint16(readInt16(b, p, e))
+ for *p <= int(h.length) {
+ f := headerField{}
+ f.tag = uint16(readInt16(b, p, e))
+ f.length = uint16(readInt16(b, p, e))
+ f.value = b[*p : *p+int(f.length)]
+ *p += int(f.length)
+ if !f.valid() {
+ return errors.New("Invalid credential cache header found")
+ }
+ h.fields = append(h.fields, f)
+ }
+ c.Header = h
+ return nil
+}
+
+// Parse the Keytab bytes of a principal into a Keytab entry's principal.
+func parsePrincipal(b []byte, p *int, c *CCache, e *binary.ByteOrder) (princ principal) {
+ if c.Version != 1 {
+ //Name Type is omitted in version 1
+ princ.PrincipalName.NameType = readInt32(b, p, e)
+ }
+ nc := int(readInt32(b, p, e))
+ if c.Version == 1 {
+ //In version 1 the number of components includes the realm. Minus 1 to make consistent with version 2
+ nc--
+ }
+ lenRealm := readInt32(b, p, e)
+ princ.Realm = string(readBytes(b, p, int(lenRealm), e))
+ for i := 0; i < nc; i++ {
+ l := readInt32(b, p, e)
+ princ.PrincipalName.NameString = append(princ.PrincipalName.NameString, string(readBytes(b, p, int(l), e)))
+ }
+ return princ
+}
+
+func parseCredential(b []byte, p *int, c *CCache, e *binary.ByteOrder) (cred *Credential, err error) {
+ cred = new(Credential)
+ cred.Client = parsePrincipal(b, p, c, e)
+ cred.Server = parsePrincipal(b, p, c, e)
+ key := types.EncryptionKey{}
+ key.KeyType = int32(readInt16(b, p, e))
+ if c.Version == 3 {
+ //repeated twice in version 3
+ key.KeyType = int32(readInt16(b, p, e))
+ }
+ key.KeyValue = readData(b, p, e)
+ cred.Key = key
+ cred.AuthTime = readTimestamp(b, p, e)
+ cred.StartTime = readTimestamp(b, p, e)
+ cred.EndTime = readTimestamp(b, p, e)
+ cred.RenewTill = readTimestamp(b, p, e)
+ if ik := readInt8(b, p, e); ik == 0 {
+ cred.IsSKey = false
+ } else {
+ cred.IsSKey = true
+ }
+ cred.TicketFlags = types.NewKrbFlags()
+ cred.TicketFlags.Bytes = readBytes(b, p, 4, e)
+ l := int(readInt32(b, p, e))
+ cred.Addresses = make([]types.HostAddress, l, l)
+ for i := range cred.Addresses {
+ cred.Addresses[i] = readAddress(b, p, e)
+ }
+ l = int(readInt32(b, p, e))
+ cred.AuthData = make([]types.AuthorizationDataEntry, l, l)
+ for i := range cred.AuthData {
+ cred.AuthData[i] = readAuthDataEntry(b, p, e)
+ }
+ cred.Ticket = readData(b, p, e)
+ cred.SecondTicket = readData(b, p, e)
+ return
+}
+
+// GetClientPrincipalName returns a PrincipalName type for the client the credentials cache is for.
+func (c *CCache) GetClientPrincipalName() types.PrincipalName {
+ return c.DefaultPrincipal.PrincipalName
+}
+
+// GetClientRealm returns the reals of the client the credentials cache is for.
+func (c *CCache) GetClientRealm() string {
+ return c.DefaultPrincipal.Realm
+}
+
+// GetClientCredentials returns a Credentials object representing the client of the credentials cache.
+func (c *CCache) GetClientCredentials() *Credentials {
+ return &Credentials{
+ username: c.DefaultPrincipal.PrincipalName.PrincipalNameString(),
+ realm: c.GetClientRealm(),
+ cname: c.DefaultPrincipal.PrincipalName,
+ }
+}
+
+// Contains tests if the cache contains a credential for the provided server PrincipalName
+func (c *CCache) Contains(p types.PrincipalName) bool {
+ for _, cred := range c.Credentials {
+ if cred.Server.PrincipalName.Equal(p) {
+ return true
+ }
+ }
+ return false
+}
+
+// GetEntry returns a specific credential for the PrincipalName provided.
+func (c *CCache) GetEntry(p types.PrincipalName) (*Credential, bool) {
+ cred := new(Credential)
+ var found bool
+ for i := range c.Credentials {
+ if c.Credentials[i].Server.PrincipalName.Equal(p) {
+ cred = c.Credentials[i]
+ found = true
+ break
+ }
+ }
+ if !found {
+ return cred, false
+ }
+ return cred, true
+}
+
+// GetEntries filters out configuration entries an returns a slice of credentials.
+func (c *CCache) GetEntries() []*Credential {
+ creds := make([]*Credential, 0)
+ for _, cred := range c.Credentials {
+ // Filter out configuration entries
+ if strings.HasPrefix(cred.Server.Realm, "X-CACHECONF") {
+ continue
+ }
+ creds = append(creds, cred)
+ }
+ return creds
+}
+
+func (h *headerField) valid() bool {
+ // At this time there is only one defined header field.
+ // Its tag value is 1, its length is always 8.
+ // Its contents are two 32-bit integers giving the seconds and microseconds
+ // of the time offset of the KDC relative to the client.
+ // Adding this offset to the current time on the client should give the current time on the KDC, if that offset has not changed since the initial authentication.
+
+ // Done as a switch in case other tag values are added in the future.
+ switch h.tag {
+ case headerFieldTagKDCOffset:
+ if h.length != 8 || len(h.value) != 8 {
+ return false
+ }
+ return true
+ }
+ return false
+}
+
+func readData(b []byte, p *int, e *binary.ByteOrder) []byte {
+ l := readInt32(b, p, e)
+ return readBytes(b, p, int(l), e)
+}
+
+func readAddress(b []byte, p *int, e *binary.ByteOrder) types.HostAddress {
+ a := types.HostAddress{}
+ a.AddrType = int32(readInt16(b, p, e))
+ a.Address = readData(b, p, e)
+ return a
+}
+
+func readAuthDataEntry(b []byte, p *int, e *binary.ByteOrder) types.AuthorizationDataEntry {
+ a := types.AuthorizationDataEntry{}
+ a.ADType = int32(readInt16(b, p, e))
+ a.ADData = readData(b, p, e)
+ return a
+}
+
+// Read bytes representing a timestamp.
+func readTimestamp(b []byte, p *int, e *binary.ByteOrder) time.Time {
+ return time.Unix(int64(readInt32(b, p, e)), 0)
+}
+
+// Read bytes representing an eight bit integer.
+func readInt8(b []byte, p *int, e *binary.ByteOrder) (i int8) {
+ buf := bytes.NewBuffer(b[*p : *p+1])
+ binary.Read(buf, *e, &i)
+ *p++
+ return
+}
+
+// Read bytes representing a sixteen bit integer.
+func readInt16(b []byte, p *int, e *binary.ByteOrder) (i int16) {
+ buf := bytes.NewBuffer(b[*p : *p+2])
+ binary.Read(buf, *e, &i)
+ *p += 2
+ return
+}
+
+// Read bytes representing a thirty two bit integer.
+func readInt32(b []byte, p *int, e *binary.ByteOrder) (i int32) {
+ buf := bytes.NewBuffer(b[*p : *p+4])
+ binary.Read(buf, *e, &i)
+ *p += 4
+ return
+}
+
+func readBytes(b []byte, p *int, s int, e *binary.ByteOrder) []byte {
+ buf := bytes.NewBuffer(b[*p : *p+s])
+ r := make([]byte, s)
+ binary.Read(buf, *e, &r)
+ *p += s
+ return r
+}
+
+func isNativeEndianLittle() bool {
+ var x = 0x012345678
+ var p = unsafe.Pointer(&x)
+ var bp = (*[4]byte)(p)
+
+ var endian bool
+ if 0x01 == bp[0] {
+ endian = false
+ } else if (0x78 & 0xff) == (bp[0] & 0xff) {
+ endian = true
+ } else {
+ // Default to big endian
+ endian = false
+ }
+ return endian
+}