aboutsummaryrefslogtreecommitdiff
path: root/ldapserver/packet.go
diff options
context:
space:
mode:
authorAlex Auvolat <alex@adnab.me>2020-01-19 13:00:53 +0100
committerAlex Auvolat <alex@adnab.me>2020-01-19 13:00:53 +0100
commit67fa504e20095d9acd5537b46f604ce8baa4e44a (patch)
treedcbe95bfdcd71a2d0307ea7214017c3632f44f8f /ldapserver/packet.go
parentbade33cf1529893a92a283f6dc86e73f8766049e (diff)
downloadbottin-67fa504e20095d9acd5537b46f604ce8baa4e44a.tar.gz
bottin-67fa504e20095d9acd5537b46f604ce8baa4e44a.zip
Add ldapserver source in here & add support for client state
Diffstat (limited to 'ldapserver/packet.go')
-rw-r--r--ldapserver/packet.go148
1 files changed, 148 insertions, 0 deletions
diff --git a/ldapserver/packet.go b/ldapserver/packet.go
new file mode 100644
index 0000000..24d01ed
--- /dev/null
+++ b/ldapserver/packet.go
@@ -0,0 +1,148 @@
+package ldapserver
+
+import (
+ "bufio"
+ "errors"
+ "fmt"
+
+ ldap "github.com/vjeantet/goldap/message"
+)
+
+type messagePacket struct {
+ bytes []byte
+}
+
+func readMessagePacket(br *bufio.Reader) (*messagePacket, error) {
+ var err error
+ var bytes *[]byte
+ bytes, err = readLdapMessageBytes(br)
+
+ if err == nil {
+ messagePacket := &messagePacket{bytes: *bytes}
+ return messagePacket, err
+ }
+ return &messagePacket{}, err
+
+}
+
+func (msg *messagePacket) readMessage() (m ldap.LDAPMessage, err error) {
+ defer func() {
+ if r := recover(); r != nil {
+ err = fmt.Errorf("invalid packet received hex=%x, %#v", msg.bytes, r)
+ }
+ }()
+
+ return decodeMessage(msg.bytes)
+}
+
+func decodeMessage(bytes []byte) (ret ldap.LDAPMessage, err error) {
+ defer func() {
+ if e := recover(); e != nil {
+ err = errors.New(fmt.Sprintf("%s", e))
+ }
+ }()
+ zero := 0
+ ret, err = ldap.ReadLDAPMessage(ldap.NewBytes(zero, bytes))
+ return
+}
+
+// BELLOW SHOULD BE IN ROOX PACKAGE
+
+func readLdapMessageBytes(br *bufio.Reader) (ret *[]byte, err error) {
+ var bytes []byte
+ var tagAndLength ldap.TagAndLength
+ tagAndLength, err = readTagAndLength(br, &bytes)
+ if err != nil {
+ return
+ }
+ readBytes(br, &bytes, tagAndLength.Length)
+ return &bytes, err
+}
+
+// readTagAndLength parses an ASN.1 tag and length pair from a live connection
+// into a byte slice. It returns the parsed data and the new offset. SET and
+// SET OF (tag 17) are mapped to SEQUENCE and SEQUENCE OF (tag 16) since we
+// don't distinguish between ordered and unordered objects in this code.
+func readTagAndLength(conn *bufio.Reader, bytes *[]byte) (ret ldap.TagAndLength, err error) {
+ // offset = initOffset
+ //b := bytes[offset]
+ //offset++
+ var b byte
+ b, err = readBytes(conn, bytes, 1)
+ if err != nil {
+ return
+ }
+ ret.Class = int(b >> 6)
+ ret.IsCompound = b&0x20 == 0x20
+ ret.Tag = int(b & 0x1f)
+
+ // // If the bottom five bits are set, then the tag number is actually base 128
+ // // encoded afterwards
+ // if ret.tag == 0x1f {
+ // ret.tag, err = parseBase128Int(conn, bytes)
+ // if err != nil {
+ // return
+ // }
+ // }
+ // We are expecting the LDAP sequence tag 0x30 as first byte
+ if b != 0x30 {
+ panic(fmt.Sprintf("Expecting 0x30 as first byte, but got %#x instead", b))
+ }
+
+ b, err = readBytes(conn, bytes, 1)
+ if err != nil {
+ return
+ }
+ if b&0x80 == 0 {
+ // The length is encoded in the bottom 7 bits.
+ ret.Length = int(b & 0x7f)
+ } else {
+ // Bottom 7 bits give the number of length bytes to follow.
+ numBytes := int(b & 0x7f)
+ if numBytes == 0 {
+ err = ldap.SyntaxError{"indefinite length found (not DER)"}
+ return
+ }
+ ret.Length = 0
+ for i := 0; i < numBytes; i++ {
+
+ b, err = readBytes(conn, bytes, 1)
+ if err != nil {
+ return
+ }
+ if ret.Length >= 1<<23 {
+ // We can't shift ret.length up without
+ // overflowing.
+ err = ldap.StructuralError{"length too large"}
+ return
+ }
+ ret.Length <<= 8
+ ret.Length |= int(b)
+ // Compat some lib which use go-ldap or someone else,
+ // they encode int may have leading zeros when it's greater then 127
+ // if ret.Length == 0 {
+ // // DER requires that lengths be minimal.
+ // err = ldap.StructuralError{"superfluous leading zeros in length"}
+ // return
+ // }
+ }
+ }
+
+ return
+}
+
+// Read "length" bytes from the connection
+// Append the read bytes to "bytes"
+// Return the last read byte
+func readBytes(conn *bufio.Reader, bytes *[]byte, length int) (b byte, err error) {
+ newbytes := make([]byte, length)
+ n, err := conn.Read(newbytes)
+ if n != length {
+ fmt.Errorf("%d bytes read instead of %d", n, length)
+ } else if err != nil {
+ return
+ }
+ *bytes = append(*bytes, newbytes...)
+ b = (*bytes)[len(*bytes)-1]
+ return
+}