1package ndr
2
3import (
4	"encoding/binary"
5	"fmt"
6)
7
8/*
9Serialization Version 1
10https://msdn.microsoft.com/en-us/library/cc243563.aspx
11
12Common Header - https://msdn.microsoft.com/en-us/library/cc243890.aspx
138 bytes in total:
14- First byte - Version: Must equal 1
15- Second byte -  1st 4 bits: Endianess (0=Big; 1=Little); 2nd 4 bits: Character Encoding (0=ASCII; 1=EBCDIC)
16- 3rd - Floating point representation (This does not seem to be the case in examples for Microsoft test sources)
17- 4th - Common Header Length: Must equal 8
18- 5th - 8th - Filler: MUST be set to 0xcccccccc on marshaling, and SHOULD be ignored during unmarshaling.
19
20Private Header - https://msdn.microsoft.com/en-us/library/cc243919.aspx
218 bytes in total:
22- First 4 bytes - Indicates the length of a serialized top-level type in the octet stream. It MUST include the padding length and exclude the header itself.
23- Second 4 bytes - Filler: MUST be set to 0 (zero) during marshaling, and SHOULD be ignored during unmarshaling.
24*/
25
26const (
27	protocolVersion   uint8  = 1
28	commonHeaderBytes uint16 = 8
29	bigEndian                = 0
30	littleEndian             = 1
31	ascii             uint8  = 0
32	ebcdic            uint8  = 1
33	ieee              uint8  = 0
34	vax               uint8  = 1
35	cray              uint8  = 2
36	ibm               uint8  = 3
37)
38
39// CommonHeader implements the NDR common header: https://msdn.microsoft.com/en-us/library/cc243889.aspx
40type CommonHeader struct {
41	Version             uint8
42	Endianness          binary.ByteOrder
43	CharacterEncoding   uint8
44	FloatRepresentation uint8
45	HeaderLength        uint16
46	Filler              []byte
47}
48
49// PrivateHeader implements the NDR private header: https://msdn.microsoft.com/en-us/library/cc243919.aspx
50type PrivateHeader struct {
51	ObjectBufferLength uint32
52	Filler             []byte
53}
54
55func (dec *Decoder) readCommonHeader() error {
56	// Version
57	vb, err := dec.r.ReadByte()
58	if err != nil {
59		return Malformed{EText: "could not read first byte of common header for version"}
60	}
61	dec.ch.Version = uint8(vb)
62	if dec.ch.Version != protocolVersion {
63		return Malformed{EText: fmt.Sprintf("byte stream does not indicate a RPC Type serialization of version %v", protocolVersion)}
64	}
65	// Read Endianness & Character Encoding
66	eb, err := dec.r.ReadByte()
67	if err != nil {
68		return Malformed{EText: "could not read second byte of common header for endianness"}
69	}
70	endian := int(eb >> 4 & 0xF)
71	if endian != 0 && endian != 1 {
72		return Malformed{EText: "common header does not indicate a valid endianness"}
73	}
74	dec.ch.CharacterEncoding = uint8(vb & 0xF)
75	if dec.ch.CharacterEncoding != 0 && dec.ch.CharacterEncoding != 1 {
76		return Malformed{EText: "common header does not indicate a valid character encoding"}
77	}
78	switch endian {
79	case littleEndian:
80		dec.ch.Endianness = binary.LittleEndian
81	case bigEndian:
82		dec.ch.Endianness = binary.BigEndian
83	}
84	// Common header length
85	lb, err := dec.readBytes(2)
86	if err != nil {
87		return Malformed{EText: fmt.Sprintf("could not read common header length: %v", err)}
88	}
89	dec.ch.HeaderLength = dec.ch.Endianness.Uint16(lb)
90	if dec.ch.HeaderLength != commonHeaderBytes {
91		return Malformed{EText: "common header does not indicate a valid length"}
92	}
93	// Filler bytes
94	dec.ch.Filler, err = dec.readBytes(4)
95	if err != nil {
96		return Malformed{EText: fmt.Sprintf("could not read common header filler: %v", err)}
97	}
98	return nil
99}
100
101func (dec *Decoder) readPrivateHeader() error {
102	// The next 8 bytes after the common header comprise the RPC type marshalling private header for constructed types.
103	err := binary.Read(dec.r, dec.ch.Endianness, &dec.ph.ObjectBufferLength)
104	if err != nil {
105		return Malformed{EText: "could not read private header object buffer length"}
106	}
107	if dec.ph.ObjectBufferLength%8 != 0 {
108		return Malformed{EText: "object buffer length not a multiple of 8"}
109	}
110	// Filler bytes
111	dec.ph.Filler, err = dec.readBytes(4)
112	if err != nil {
113		return Malformed{EText: fmt.Sprintf("could not read private header filler: %v", err)}
114	}
115	return nil
116}
117