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  }