github.com/jcmturner/gokrb5/v8@v8.4.4/kadmin/message.go (about) 1 package kadmin 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "errors" 7 "fmt" 8 "math" 9 10 "github.com/jcmturner/gokrb5/v8/messages" 11 "github.com/jcmturner/gokrb5/v8/types" 12 ) 13 14 const ( 15 verisonHex = "ff80" 16 ) 17 18 // Request message for changing password. 19 type Request struct { 20 APREQ messages.APReq 21 KRBPriv messages.KRBPriv 22 } 23 24 // Reply message for a password change. 25 type Reply struct { 26 MessageLength int 27 Version int 28 APREPLength int 29 APREP messages.APRep 30 KRBPriv messages.KRBPriv 31 KRBError messages.KRBError 32 IsKRBError bool 33 ResultCode uint16 34 Result string 35 } 36 37 // Marshal a Request into a byte slice. 38 func (m *Request) Marshal() (b []byte, err error) { 39 b = []byte{255, 128} // protocol version number: contains the hex constant 0xff80 (big-endian integer). 40 ab, e := m.APREQ.Marshal() 41 if e != nil { 42 err = fmt.Errorf("error marshaling AP_REQ: %v", e) 43 return 44 } 45 if len(ab) > math.MaxUint16 { 46 err = errors.New("length of AP_REQ greater then max Uint16 size") 47 return 48 } 49 al := make([]byte, 2) 50 binary.BigEndian.PutUint16(al, uint16(len(ab))) 51 b = append(b, al...) 52 b = append(b, ab...) 53 pb, e := m.KRBPriv.Marshal() 54 if e != nil { 55 err = fmt.Errorf("error marshaling KRB_Priv: %v", e) 56 return 57 } 58 b = append(b, pb...) 59 if len(b)+2 > math.MaxUint16 { 60 err = errors.New("length of message greater then max Uint16 size") 61 return 62 } 63 ml := make([]byte, 2) 64 binary.BigEndian.PutUint16(ml, uint16(len(b)+2)) 65 b = append(ml, b...) 66 return 67 } 68 69 // Unmarshal a byte slice into a Reply. 70 func (m *Reply) Unmarshal(b []byte) error { 71 m.MessageLength = int(binary.BigEndian.Uint16(b[0:2])) 72 m.Version = int(binary.BigEndian.Uint16(b[2:4])) 73 if m.Version != 1 { 74 return fmt.Errorf("kadmin reply has incorrect protocol version number: %d", m.Version) 75 } 76 m.APREPLength = int(binary.BigEndian.Uint16(b[4:6])) 77 if m.APREPLength != 0 { 78 err := m.APREP.Unmarshal(b[6 : 6+m.APREPLength]) 79 if err != nil { 80 return err 81 } 82 err = m.KRBPriv.Unmarshal(b[6+m.APREPLength : m.MessageLength]) 83 if err != nil { 84 return err 85 } 86 } else { 87 m.IsKRBError = true 88 m.KRBError.Unmarshal(b[6:m.MessageLength]) 89 m.ResultCode, m.Result = parseResponse(m.KRBError.EData) 90 } 91 return nil 92 } 93 94 func parseResponse(b []byte) (c uint16, s string) { 95 c = binary.BigEndian.Uint16(b[0:2]) 96 buf := bytes.NewBuffer(b[2:]) 97 m := make([]byte, len(b)-2) 98 binary.Read(buf, binary.BigEndian, &m) 99 s = string(m) 100 return 101 } 102 103 // Decrypt the encrypted part of the KRBError within the change password Reply. 104 func (m *Reply) Decrypt(key types.EncryptionKey) error { 105 if m.IsKRBError { 106 return m.KRBError 107 } 108 err := m.KRBPriv.DecryptEncPart(key) 109 if err != nil { 110 return err 111 } 112 m.ResultCode, m.Result = parseResponse(m.KRBPriv.DecryptedEncPart.UserData) 113 return nil 114 }