blob: 157fcad4c6894b3275c718300c22e02c063bf33d [file] [log] [blame]
Takahiro Suzukid7bf8202020-12-17 20:21:59 +09001package kadmin
2
3import (
4 "bytes"
5 "encoding/binary"
6 "errors"
7 "fmt"
8 "math"
9
10 "gopkg.in/jcmturner/gokrb5.v7/messages"
11 "gopkg.in/jcmturner/gokrb5.v7/types"
12)
13
14const (
15 verisonHex = "ff80"
16)
17
18// Request message for changing password.
19type Request struct {
20 APREQ messages.APReq
21 KRBPriv messages.KRBPriv
22}
23
24// Reply message for a password change.
25type 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.
38func (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.
70func (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
94func 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.
104func (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}